source: vendor/emx/current/src/emxomf/emxaout.c

Last change on this file was 18, checked in by bird, 23 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 33.1 KB
Line 
1/* emxaout.c -- Convert OS/2-style OMF object files to GNU-style a.out
2 object files
3 Copyright (c) 1994-1998 Eberhard Mattes
4
5This file is part of emxaout.
6
7emxaout is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12emxaout is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with emxaout; see the file COPYING. If not, write to
19the Free Software Foundation, 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, USA. */
21
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <stdarg.h>
26#include <string.h>
27#include <getopt.h>
28#include <sys/param.h>
29#include <sys/emxload.h>
30#include <ar.h>
31
32#define GROW_DEF_STATIC(NAME,TYPE) \
33 static struct grow NAME##_grow; \
34 static TYPE *NAME
35#define GROW_SETUP(NAME,INCR) \
36 (NAME = NULL, grow_init (&NAME##_grow, &NAME, sizeof (*(NAME)), INCR))
37#define GROW_FREE(NAME) \
38 grow_free (&NAME##_grow)
39#define GROW_COUNT(NAME) \
40 NAME##_grow.count
41#define GROW_ADD(NAME) \
42 (grow_by (&NAME##_grow, 1), NAME##_grow.count++)
43
44/* The version number of this program. This is printed with the usage
45 message. */
46
47#define VERSION "0.9d"
48
49/* Insert private header files. */
50
51#include "defs.h" /* Common definitions */
52#include "grow.h" /* Growing objects */
53
54#define SEG_OTHER 0
55#define SEG_CODE 1
56#define SEG_DATA 2
57#define SEG_BSS 3
58#define SEG_SET 4
59#define SEG_DEBUG 5
60
61struct segment
62{
63 int name;
64 dword size;
65 byte *data;
66 int type;
67};
68
69struct group
70{
71 int name;
72};
73
74struct pubdef
75{
76 char *name;
77 dword offset;
78 int group;
79 int seg;
80 int frame;
81};
82
83struct extdef
84{
85 char *name;
86 int sym;
87 dword size; /* Non-zero for COMDEF */
88};
89
90struct symbol
91{
92 char *name;
93 struct nlist n;
94};
95
96struct thread
97{
98 int method;
99 int index;
100};
101
102
103/* Prototypes for public functions. */
104
105void error (const char *fmt, ...) NORETURN2 ATTR_PRINTF (1, 2);
106void error2 (const char *fmt, ...) NORETURN2 ATTR_PRINTF (1, 2);
107void *xmalloc (size_t n);
108void *xrealloc (void *ptr, size_t n);
109char *xstrdup (const char *s);
110
111
112/* The name of the current input file. */
113static const char *inp_fname;
114
115/* The name of the current output file. */
116static const char *out_fname = NULL;
117
118/* The current input file. */
119static FILE *inp_file;
120
121/* The current output file. */
122static FILE *out_file = NULL;
123
124/* Assume that the .obj file contains leading underscores -- don't add
125 extra underscores. */
126static int underscores = FALSE;
127
128static int rec_type;
129static int rec_len;
130static int rec_idx;
131static byte rec_buf[MAX_REC_SIZE+8];
132
133static int group_flat;
134
135static int seg_code;
136static int seg_data;
137static int seg_bss;
138
139static int cur_seg;
140static dword cur_off;
141
142static struct thread frame_threads[4];
143static struct thread target_threads[4];
144
145GROW_DEF_STATIC (lnames, char *);
146GROW_DEF_STATIC (groups, struct group);
147GROW_DEF_STATIC (segments, struct segment);
148GROW_DEF_STATIC (pubdefs, struct pubdef);
149GROW_DEF_STATIC (extdefs, struct extdef);
150GROW_DEF_STATIC (symbols, struct symbol);
151GROW_DEF_STATIC (trelocs, struct reloc);
152GROW_DEF_STATIC (drelocs, struct reloc);
153
154
155/* If there is an output file, close and delete it. */
156
157static void cleanup (void)
158{
159 if (out_file != NULL)
160 {
161 fclose (out_file);
162 remove (out_fname);
163 }
164}
165
166
167/* Display an error message on stderr, delete the output file and
168 quit. This function is invoked like printf(): FMT is a
169 printf-style format string, all other arguments are formatted
170 according to FMT. The message should not end with a newline. The
171 exit code is 2. */
172
173void error (const char *fmt, ...)
174{
175 va_list arg_ptr;
176
177 va_start (arg_ptr, fmt);
178 fprintf (stderr, "emxaout: ");
179 vfprintf (stderr, fmt, arg_ptr);
180 fputc ('\n', stderr);
181 cleanup ();
182 exit (2);
183}
184
185
186/* Display an error message for the current input file on stderr,
187 delete the output file and quit. This function is invoked like
188 printf(): FMT is a printf-style format string, all other arguments
189 are formatted according to FMT. The message should not end with a
190 newline. The exit code is 2. */
191
192void error2 (const char *fmt, ...)
193{
194 va_list arg_ptr;
195
196 va_start (arg_ptr, fmt);
197 fprintf (stderr, "%s[%ld+%d]: ", inp_fname,
198 ftell (inp_file) - (sizeof (struct omf_rec) + rec_len + 1),
199 rec_idx);
200 vfprintf (stderr, fmt, arg_ptr);
201 fputc ('\n', stderr);
202 cleanup ();
203 exit (2);
204}
205
206
207/* Allocate N bytes of memory. Quit on failure. This function is
208 used like malloc(), but we don't have to check the return value. */
209
210void *xmalloc (size_t n)
211{
212 void *p;
213
214 p = malloc (n);
215 if (p == NULL && n != 0)
216 error ("Out of memory");
217 return p;
218}
219
220
221/* Change the allocation of PTR to N bytes. Quit on failure. This
222 function is used like realloc(), but we don't have to check the
223 return value. */
224
225void *xrealloc (void *ptr, size_t n)
226{
227 void *p;
228
229 p = realloc (ptr, n);
230 if (p == NULL)
231 error ("Out of memory");
232 return p;
233}
234
235
236/* Create a duplicate of the string S on the heap. Quit on failure.
237 This function is used like strdup(), but we don't have to check the
238 return value. */
239
240char *xstrdup (const char *s)
241{
242 char *p;
243
244 p = xmalloc (strlen (s) + 1);
245 strcpy (p, s);
246 return p;
247}
248
249
250/* Display a warning message on stderr (and do not quit). This
251 function is invoked like printf(): FMT is a printf-style format
252 string, all other arguments are formatted according to FMT. */
253
254void warning (const char *fmt, ...)
255{
256 va_list arg_ptr;
257
258 va_start (arg_ptr, fmt);
259 fprintf (stderr, "emxaout warning: ");
260 vfprintf (stderr, fmt, arg_ptr);
261 fputc ('\n', stderr);
262}
263
264
265/* Display some hints on using this program, then quit. */
266
267static void usage (void)
268{
269 puts ("emxaout " VERSION " -- Copyright (c) 1994-1996 by Eberhard Mattes\n");
270 puts ("Usage:");
271 puts (" emxaout [-u] [-o <output_file>] <input_file>");
272 puts ("\nOptions:");
273 puts (" -u Don't add leading underscores");
274 puts (" -o <output_file> Write output to <output_file>");
275 exit (1);
276}
277
278
279/* Create the output file. */
280
281static void open_output (void)
282{
283 out_file = fopen (out_fname, "wb");
284 if (out_file == NULL)
285 error ("Cannot create output file `%s'", out_fname);
286}
287
288
289/* Close the output file. Display an error message and quit on
290 failure. */
291
292static void close_output (void)
293{
294 if (fflush (out_file) != 0 || fclose (out_file) != 0)
295 {
296 out_file = NULL;
297 error ("Write error on output file `%s'", out_fname);
298 }
299 out_file = NULL;
300}
301
302
303/* Define or build the name of the output file. If DST_FNAME is not
304 NULL, use it as name of the output file. Otherwise, build the name
305 from INP_FNAME (the input file name) and EXT (the extension). */
306
307static void make_out_fname (const char *dst_fname, const char *inp_fname,
308 const char *ext)
309{
310 static char tmp[MAXPATHLEN+1];
311
312 if (dst_fname == NULL)
313 {
314 if (strlen (inp_fname) + strlen (ext) > MAXPATHLEN)
315 error ("File name `%s' too long", inp_fname);
316 strcpy (tmp, inp_fname);
317 _remext (tmp);
318 strcat (tmp, ext);
319 out_fname = tmp;
320 }
321 else
322 out_fname = dst_fname;
323}
324
325
326static void get_mem (void *dst, int len)
327{
328 if (rec_idx + len > rec_len)
329 error2 ("String beyond end of record");
330 memcpy (dst, rec_buf + rec_idx, len);
331 rec_idx += len;
332}
333
334
335static void get_string (byte *dst)
336{
337 int len;
338
339 if (rec_idx >= rec_len)
340 error2 ("String beyond end of record");
341 len = rec_buf[rec_idx++];
342 get_mem (dst, len);
343 dst[len] = 0;
344}
345
346
347static int get_index (void)
348{
349 int result;
350
351 if (rec_idx >= rec_len)
352 error2 ("Index beyond end of record");
353 result = rec_buf[rec_idx++];
354 if (result & 0x80)
355 {
356 if (rec_idx >= rec_len)
357 error2 ("Index beyond end of record");
358 result = ((result & 0x7f) << 8) | rec_buf[rec_idx++];
359 }
360 return result;
361}
362
363
364static word get_dword (void)
365{
366 dword result;
367
368 if (rec_idx + 4 > rec_len)
369 error2 ("Dword beyond end of record");
370 result = rec_buf[rec_idx++];
371 result |= rec_buf[rec_idx++] << 8;
372 result |= rec_buf[rec_idx++] << 16;
373 result |= rec_buf[rec_idx++] << 24;
374 return result;
375}
376
377
378static word get_word (void)
379{
380 word result;
381
382 if (rec_idx + 2 > rec_len)
383 error2 ("Word beyond end of record");
384 result = rec_buf[rec_idx++];
385 result |= rec_buf[rec_idx++] << 8;
386 return result;
387}
388
389
390static word get_byte (void)
391{
392 if (rec_idx + 1 > rec_len)
393 error2 ("Byte beyond end of record");
394 return rec_buf[rec_idx++];
395}
396
397
398static dword get_word_or_dword (void)
399{
400 return (rec_type & REC32 ? get_dword () : get_word ());
401}
402
403
404static dword get_commlen (void)
405{
406 dword result;
407
408 result = get_byte ();
409 if (result <= 0x80)
410 return result;
411 switch (result)
412 {
413 case 0x81:
414 return get_word ();
415 case 0x84:
416 result = get_byte ();
417 result |= get_byte () << 8;
418 result |= get_byte () << 16;
419 return result;
420 case 0x88:
421 return get_dword ();
422 default:
423 error2 ("Unknown COMDAT length prefix");
424 }
425}
426
427
428static void init_module (void)
429{
430 int i;
431
432 GROW_SETUP (lnames, 8);
433 GROW_SETUP (groups, 8);
434 GROW_SETUP (segments, 8);
435 GROW_SETUP (pubdefs, 16);
436 GROW_SETUP (extdefs, 16);
437 GROW_SETUP (symbols, 16);
438 GROW_SETUP (trelocs, 32);
439 GROW_SETUP (drelocs, 32);
440
441 group_flat = -1;
442 seg_code = -1; seg_data = -1; seg_bss = -1;
443 cur_seg = -1;
444
445 for (i = 0; i < 4; ++i)
446 frame_threads[i].method = target_threads[i].method = -1;
447}
448
449
450static void term_module (void)
451{
452 int i;
453
454 for (i = 0; i < GROW_COUNT (lnames); ++i)
455 free (lnames[i]);
456 GROW_FREE (lnames);
457
458 GROW_FREE (groups);
459
460 for (i = 0; i < GROW_COUNT (segments); ++i)
461 if (segments[i].data != NULL)
462 free (segments[i].data);
463 GROW_FREE (segments);
464
465 for (i = 0; i < GROW_COUNT (pubdefs); ++i)
466 free (pubdefs[i].name);
467 GROW_FREE (pubdefs);
468
469 for (i = 0; i < GROW_COUNT (extdefs); ++i)
470 free (extdefs[i].name);
471 GROW_FREE (extdefs);
472
473 for (i = 0; i < GROW_COUNT (symbols); ++i)
474 if (symbols[i].name != NULL)
475 free (symbols[i].name);
476 GROW_FREE (symbols);
477
478 GROW_FREE (trelocs);
479 GROW_FREE (drelocs);
480}
481
482
483/* Convert an LNAMES record.
484
485 LNAMES record:
486 Ú
487 ³1 String length n
488 ³n Name
489 À
490
491 Name indices are assigned sequentially. */
492
493static void conv_lnames (void)
494{
495 byte string[256];
496 int i;
497
498 while (rec_idx < rec_len)
499 {
500 get_string (string);
501 i = GROW_ADD (lnames);
502 lnames[i] = xstrdup (string);
503 }
504}
505
506
507/* Convert a GRPDEF record.
508
509 GRPDEF record:
510 1/2 Group name index
511 Ú
512 ³1 0xff (use segment index)
513 ³1/2 Segment index
514 À
515
516 Group indices are assigned sequentially. */
517
518static void conv_grpdef (void)
519{
520 int i, name, type, seg;
521 const char *group_name;
522
523 name = get_index ();
524 i = GROW_ADD (groups);
525 groups[i].name = name;
526
527 if (name < 1 || name > GROW_COUNT (lnames))
528 error2 ("GRPDEF: name index out of range");
529 group_name = lnames[name - 1];
530
531 if (strcmp (group_name, "FLAT") == 0)
532 group_flat = i;
533
534 while (rec_idx < rec_len)
535 {
536 type = get_byte ();
537 if (type != 0xff)
538 error2 ("GRPDEF: unknown type");
539 seg = get_index ();
540 }
541}
542
543
544static int is_set_seg (const char *name)
545{
546 return (name[0] == 'S' && name[1] == 'E' && name[2] == 'T'
547 && (name[3] >= '1' && name[3] <= '3')
548 && name[4] == '_' && name[5] == '_' && name[6] == '_'
549 && (name[7] == 'C' || name[7] == 'D')
550 && strcmp (name+8, "TOR_LIST__") == 0);
551}
552
553
554/* Convert a SEGDEF record.
555
556 SEGDEF record:
557 1 Segment attributes
558 0/2 Frame number (present only if A=000)
559 0/1 Offset (present only if A=000)
560 2/4 Segment length (4 bytes for 32-bit SEGDEF record)
561 1/2 Segment name index
562 1/2 Segment class index
563 1/2 Overlay name index
564
565 The segment attributes byte contains the following fields:
566
567 A (bits 5-7) Alignment (101=relocatable, 32-bit alignment)
568 C (bits 2-4) Combination (010=PUBLIC, 101=STACK)
569 B (bit 1) Big (segment length is 64KB)
570 P (bit 0) USE32 */
571
572static void conv_segdef (void)
573{
574 int i, type;
575 int attributes, alignment, combination, frame, offset, name, class, overlay;
576 dword length;
577 const char *seg_name, *class_name;
578
579 attributes = get_byte ();
580 alignment = attributes >> 5;
581 combination = (attributes >> 2) & 7;
582 if (alignment == 0)
583 {
584 frame = get_word ();
585 offset = get_byte ();
586 }
587 length = get_word_or_dword ();
588 name = get_index ();
589 class = get_index ();
590 overlay = get_index ();
591 if (!(rec_type & REC32) && (attributes & 2))
592 length = 1L << 16;
593
594 if (class < 1 || class > GROW_COUNT (lnames))
595 error2 ("SEGDEF: class index out of range");
596 class_name = lnames[class - 1];
597
598 if (name < 1 || name > GROW_COUNT (lnames))
599 error2 ("SEGDEF: name index out of range");
600 seg_name = lnames[name - 1];
601
602 type = SEG_OTHER;
603 if (strcmp (class_name, "CODE") == 0)
604 {
605 if (is_set_seg (seg_name))
606 type = SEG_SET;
607 else
608 type = SEG_CODE;
609 }
610 else if (strcmp (class_name, "DATA") == 0)
611 type = SEG_DATA;
612 else if (strcmp (class_name, "BSS") == 0)
613 type = SEG_BSS;
614 else if (strcmp (class_name, "DEBSYM") == 0)
615 type = SEG_DEBUG;
616 else if (strcmp (class_name, "DEBTYP") == 0)
617 type = SEG_DEBUG;
618
619 if (type != SEG_OTHER)
620 for (i = 0; i < GROW_COUNT (segments); ++i)
621 if (segments[i].type == type)
622 switch (type)
623 {
624 case SEG_CODE:
625 error2 ("Multiple code segments");
626 case SEG_DATA:
627 error2 ("Multiple data segments");
628 case SEG_BSS:
629 error2 ("Multiple bss segments");
630 case SEG_SET:
631 case SEG_DEBUG:
632 break;
633 }
634 i = GROW_ADD (segments);
635 segments[i].name = name;
636 segments[i].size = length;
637 segments[i].data = xmalloc (length);
638 segments[i].type = type;
639 memset (segments[i].data, 0, length);
640 switch (type)
641 {
642 case SEG_CODE:
643 seg_code = i;
644 break;
645 case SEG_DATA:
646 seg_data = i;
647 break;
648 case SEG_BSS:
649 seg_bss = i;
650 break;
651 }
652}
653
654
655/* Convert a PUBDEF record.
656
657 PUBDEF record:
658 1-2 Base group
659 1-2 Base segment
660 0/2 Base frame
661 Ú
662 ³1 String length n
663 ³n Public name
664 ³2/4 Public offset (4 bytes for 32-bit PUBDEF record)
665 ³1-2 Type index
666 À
667
668 The base frame field is present only if the base segment field is
669 0. */
670
671static void conv_pubdef (void)
672{
673 int i, type, group, seg, frame;
674 dword offset;
675 byte name[1+256];
676
677 group = get_index ();
678 seg = get_index ();
679 if (seg == 0)
680 frame = get_word ();
681 else
682 frame = 0;
683
684 while (rec_idx < rec_len)
685 {
686 name[0] = '_';
687 get_string (name+1);
688 offset = get_word_or_dword ();
689 type = get_index ();
690 i = GROW_ADD (pubdefs);
691 pubdefs[i].name = xstrdup (underscores ? name + 1 : name);
692 pubdefs[i].group = group;
693 pubdefs[i].seg = seg;
694 pubdefs[i].frame = frame;
695 pubdefs[i].offset = offset;
696 }
697}
698
699
700/* Convert an EXTDEF record.
701
702 EXTDEF record:
703 Ú
704 ³1 String length n
705 ³n External name
706 ³1-2 Type index
707 À
708
709 Symbol indices are assigned sequentially by EXTDEF and COMDEF. */
710
711static void conv_extdef (void)
712{
713 int i, type;
714 byte name[1+256];
715
716 while (rec_idx < rec_len)
717 {
718 name[0] = '_';
719 get_string (name+1);
720 type = get_index ();
721 i = GROW_ADD (extdefs);
722 extdefs[i].name = xstrdup (underscores ? name + 1 : name);
723 extdefs[i].sym = 0;
724 extdefs[i].size = 0; /* EXTDEF */
725 }
726}
727
728
729/* Convert an COMDEF record.
730
731 COMDEF record:
732 Ú
733 ³1 String length n
734 ³n Communal name
735 ³1-2 Type index
736 ³1 Data type (0x61: FAR data, 0x62: NEAR data)
737 ³1-5 Communal length
738 À
739
740 The length is encoded in 1 to 5 bytes, depending on the value:
741
742 0 through 0x7f 1 byte, containing the value
743 0 through 0xffff 0x81, followed by 16-bit word
744 0 through 0xffffff 0x84, followed by 24-bit word
745 0 through 0xffffffff 0x88, followed by 32-bit word
746
747 Symbol indices are assigned sequentially by EXTDEF and COMDEF. */
748
749static void conv_comdef (void)
750{
751 int i, type;
752 word data_type;
753 dword comm_count, comm_len;
754 byte name[1+256];
755
756 while (rec_idx < rec_len)
757 {
758 name[0] = '_';
759 get_string (name+1);
760 type = get_index ();
761 data_type = get_byte ();
762 switch (data_type)
763 {
764 case 0x61:
765 comm_count = get_commlen ();
766 comm_len = get_commlen ();
767 break;
768 case 0x62:
769 comm_count = 1;
770 comm_len = get_commlen ();
771 break;
772 default:
773 error2 ("COMDEF: unknown data type");
774 }
775 if (comm_count == 0 || comm_len == 0)
776 error2 ("COMDEF: size is zero");
777 i = GROW_ADD (extdefs);
778 extdefs[i].name = xstrdup (underscores ? name + 1 : name);
779 extdefs[i].sym = 0;
780 extdefs[i].size = comm_count * comm_len;
781 }
782}
783
784
785/* Convert a LEDATA record.
786
787 LEDATA record:
788 1-2 Segment index
789 2/4 Enumerated data offset (4 bytes for 32-bit LEDATA record)
790 n Data bytes (n is derived from record length) */
791
792static void conv_ledata (void)
793{
794 int len;
795 dword offset, seg;
796
797 seg = get_index ();
798 offset = get_word_or_dword ();
799 len = rec_len - rec_idx;
800
801 if (seg < 1 || seg > GROW_COUNT (segments))
802 error2 ("LEDATA: segment index out of range");
803
804 cur_seg = -1;
805 if (segments[seg-1].data != NULL)
806 {
807 cur_seg = seg - 1;
808 cur_off = offset;
809 if (segments[seg-1].type != SEG_DEBUG)
810 {
811 if (offset + len > segments[seg-1].size)
812 error2 ("LEDATA: data beyond end of segment");
813 else
814 get_mem (segments[seg-1].data + offset, len);
815 }
816 }
817}
818
819
820/* Convert an iterated data block, for LIDATA.
821
822 Iterated data block:
823 2/4 Repeat count
824 2 Block count (0: data bytes, otherwise nested block)
825 n nested block or data bytes */
826
827static void conv_block (dword *poffset)
828{
829 dword rep_count, block_count, i, j;
830 int len, saved_idx;
831
832 rep_count = get_word_or_dword ();
833 block_count = get_word ();
834 if (rep_count == 0)
835 error2 ("LIDATA: repeat count is zero");
836 if (block_count == 0)
837 {
838 len = get_byte ();
839 if (*poffset + len * rep_count > segments[cur_seg].size)
840 error2 ("LIDATA: data beyond end of segment");
841 get_mem (segments[cur_seg].data + *poffset, len);
842 *poffset += len;
843 for (i = 1; i < rep_count; ++i)
844 {
845 memcpy (segments[cur_seg].data + *poffset,
846 segments[cur_seg].data + *poffset - len, len);
847 *poffset += len;
848 }
849 }
850 else
851 {
852 saved_idx = rec_idx;
853 for (i = 0; i < rep_count; ++i)
854 {
855 rec_idx = saved_idx;
856 for (j = 0; j < block_count; ++j)
857 conv_block (poffset);
858 }
859 }
860}
861
862
863/* Convert a LIDATA record.
864
865 LIDATA record:
866 1-2 Segment index
867 2/4 Iterated data offset (4 bytes for 32-bit LIDATA record)
868 n Data blocks */
869
870static void conv_lidata (void)
871{
872 dword offset, seg;
873
874 seg = get_index ();
875 offset = get_word_or_dword ();
876 if (seg < 1 || seg > GROW_COUNT (segments))
877 error2 ("LIDATA: segment index out of range");
878
879 if (segments[seg-1].data != NULL)
880 {
881 cur_seg = seg - 1;
882 cur_off = offset;
883 if (segments[cur_seg].type != SEG_DEBUG)
884 {
885 while (rec_len - rec_idx >= 4)
886 conv_block (&offset);
887 }
888 }
889 cur_seg = -1; /* FIXUPP for LIDATA not supported */
890}
891
892
893/* Convert a FIXUPP record. This is the single interesting function
894 of this program.
895
896 FIXUPP record:
897 Ú
898 ³? THREAD subrecord or FIXUP subrecord
899 À
900
901 THREAD subrecord:
902 1 Flags
903 0-2 Index (present only for FRAME methods F0, F1 and F2)
904
905 The flags byte contains the following fields:
906
907 0 (bit 7) always 0 to indicate THREAD subrecord
908 D (bit 6) 0=target thread, 1=frame thread
909 0 (bit 5) reserved
910 Method (bits 2-4) method (T0 through T6 and F0 through F6)
911 Thred (bits 0-1) thread number
912
913 FIXUP subrecord:
914 2 Locat
915 0-1 Fix data
916 0-2 Frame datum
917 0-2 Target datum
918 2/4 target displacement (4 bytes for 32-bit FIXUPP record)
919
920 The first locat byte contains the following fields:
921
922 1 (bit 7) always 1 to indicate FIXUP subrecord
923 M (bit 6) 1=segment-relative fixup, 0=self-relative fixup
924 Location (bit 2-5) Type of location to fix up:
925 0010=16-bit selector
926 0011=32-bit long pointer (16:16)
927 1001=32-bit offset
928 Offset (bits 0-1) Most significant bits of offset into LEDATA record
929
930 The second locat byte contains the least significant bits of the
931 offset into the LEDATA record.
932
933 The Fix data byte contains the following fields:
934
935 F (bit 7) 1=frame thread, 0=methods F0 through F5
936 Frame (bits 4-6) frame thread number (F=1) or frame method (F=0)
937 T (bit 3) 1=target thread, 1=methods
938 P (bit 2) Bit 2 of target method
939 Targt (bits 0-1) target thread number (T=1) or target method (T=0) */
940
941static void conv_fixupp (void)
942{
943 int i, first, locat, offset, fix_data, thred;
944 int frame_method, frame_index, target_method, target_index;
945 dword disp;
946 struct reloc r;
947 struct thread th;
948
949 while (rec_idx < rec_len)
950 {
951 first = get_byte ();
952 if (first & 0x80)
953 {
954 /* FIXUP subrecord */
955 offset = get_byte ();
956 offset |= (first & 3) << 8;
957 fix_data = get_byte ();
958 if (first & 0x40)
959 r.pcrel = 0;
960 else
961 r.pcrel = 1;
962 r.address = offset + cur_off;
963 r.unused = 0;
964 locat = (first >> 2) & 0x0f;
965 if (fix_data & 0x80)
966 {
967 thred = (fix_data >> 4) & 3;
968 frame_method = frame_threads[thred].method;
969 frame_index = frame_threads[thred].index;
970 }
971 else
972 {
973 frame_method = (fix_data >> 4) & 7;
974 frame_index = 0;
975 if (frame_method <= 2)
976 frame_index = get_index ();
977 }
978 if (fix_data & 0x08)
979 {
980 thred = fix_data & 3;
981 target_method = target_threads[thred].method;
982 target_index = target_threads[thred].index;
983 }
984 else
985 {
986 target_method = fix_data & 3;
987 target_index = get_index ();
988 }
989 disp = 0;
990 if (!(fix_data & 0x04))
991 disp = get_word_or_dword ();
992
993 if (cur_seg < 0)
994 error2 ("FIXUPP: not preceded by LEDATA or COMDAT");
995
996 /* Ignore all fixups for other segments, such as $$SYMBOLS
997 (which may have SEL-16 fixups). */
998
999 if (cur_seg == seg_code || cur_seg == seg_data)
1000 {
1001 switch (locat)
1002 {
1003 case 0:
1004 error2 ("FIXUPP: LOW-8 fixup not supported");
1005 case 1:
1006 error2 ("FIXUPP: OFFSET-16 fixup not supported");
1007 case 2:
1008 error2 ("FIXUPP: SEL-16 fixup not supported");
1009 case 3:
1010 error2 ("FIXUPP: FAR-16:16 fixup not supported");
1011 case 4:
1012 error2 ("FIXUPP: HIGH-8 fixup not supported");
1013 case 5:
1014 error2 ("FIXUPP: OFFSET-16(LR) fixup not supported");
1015 case 9:
1016 r.length = 2;
1017 break;
1018 case 11:
1019 error2 ("FIXUPP: FAR-16:32 fixup not supported");
1020 case 13:
1021 error2 ("FIXUPP: OFFSET-32(LR) fixup not supported");
1022 default:
1023 error2 ("FIXUPP: unknown location");
1024 }
1025
1026 switch (target_method)
1027 {
1028 case 0: /* T0: SEGDEF */
1029 r.ext = 0;
1030 if (target_index == seg_code + 1)
1031 r.symbolnum = N_TEXT;
1032 else if (target_index == seg_data + 1)
1033 {
1034 r.symbolnum = N_DATA;
1035 disp += (seg_code >= 0 ? segments[seg_code].size : 0);
1036 }
1037 else if (target_index == seg_bss + 1)
1038 {
1039 r.symbolnum = N_BSS;
1040 disp += (seg_code >= 0 ? segments[seg_code].size : 0);
1041 disp += (seg_data >= 0 ? segments[seg_data].size : 0);
1042 }
1043 else if (target_index < 1
1044 || target_index > GROW_COUNT (segments))
1045 error2 ("FIXUPP: invalid segment index");
1046 else
1047 error2 ("FIXUPP: Target segment %s not supported",
1048 lnames[segments[target_index-1].name-1]);
1049 break;
1050 case 2: /* T2: EXTDEF */
1051 r.ext = 1;
1052 if (target_index < 1 || target_index > GROW_COUNT (extdefs))
1053 error2 ("FIXUPP: EXTDEF index out of range");
1054 r.symbolnum = target_index - 1;
1055 break;
1056 default:
1057 error2 ("FIXUPP: TARGET method %d not supported",
1058 target_method);
1059 }
1060
1061 switch (frame_method)
1062 {
1063 case 1: /* F1: GRPDEF */
1064 if (frame_index != group_flat + 1)
1065 error2 ("FIXUPP: only group FLAT is supported "
1066 "for method F1");
1067 break;
1068 default:
1069 error2 ("FIXUPP: FRAME method %d not supported",
1070 frame_method);
1071 }
1072
1073 if (cur_seg == seg_code)
1074 {
1075 i = GROW_ADD (trelocs);
1076 trelocs[i] = r;
1077 }
1078 else if (cur_seg == seg_data)
1079 {
1080 i = GROW_ADD (drelocs);
1081 drelocs[i] = r;
1082 }
1083 else
1084 abort ();
1085
1086 if (r.address + 4 > segments[cur_seg].size)
1087 error2 ("FIXUPP: fixup beyond end of segment");
1088 *((dword *)(segments[cur_seg].data + r.address))
1089 += r.pcrel ? disp - (r.address + 4) : disp;
1090 }
1091 }
1092 else
1093 {
1094 /* THREAD subrecord */
1095 thred = first & 3;
1096 if (first & 0x40)
1097 {
1098 th.method = (first >> 2) & 7;
1099 th.index = 0;
1100 if (th.method <= 2)
1101 th.index = get_index ();
1102 frame_threads[thred] = th;
1103 }
1104 else
1105 {
1106 th.method = (first >> 2) & 3;
1107 th.index = get_index ();
1108 target_threads[thred] = th;
1109 }
1110 }
1111 }
1112}
1113
1114
1115/* Build the symbol table. */
1116
1117static void make_symtab (void)
1118{
1119 int i, j;
1120 struct nlist n;
1121 char skip;
1122
1123 /* Important: Write extdefs first, to be able to use EXTDEF indices
1124 as symbol numbers. */
1125
1126 for (i = 0; i < GROW_COUNT (extdefs); ++i)
1127 {
1128 n.type = N_EXT;
1129 n.string = 0;
1130 n.value = extdefs[i].size;
1131 n.other = 0;
1132 n.desc = 0;
1133 j = GROW_ADD (symbols);
1134 symbols[j].name = xstrdup (extdefs[i].name);
1135 symbols[j].n = n;
1136 extdefs[i].sym = j;
1137 }
1138 for (i = 0; i < GROW_COUNT (pubdefs); ++i)
1139 {
1140 skip = FALSE;
1141 if (pubdefs[i].group != group_flat + 1)
1142 skip = TRUE;
1143 else if (pubdefs[i].seg == seg_code + 1)
1144 n.type = N_TEXT | N_EXT;
1145 else if (pubdefs[i].seg == seg_data + 1)
1146 n.type = N_DATA | N_EXT;
1147 else
1148 skip = TRUE;
1149 if (!skip)
1150 {
1151 n.string = 0;
1152 n.value = pubdefs[i].offset;
1153 n.other = 0;
1154 n.desc = 0;
1155 j = GROW_ADD (symbols);
1156 symbols[j].name = xstrdup (pubdefs[i].name);
1157 symbols[j].n = n;
1158 }
1159 }
1160}
1161
1162
1163/* Write the symbol table. */
1164
1165static void write_symtab (void)
1166{
1167 int i;
1168 dword str_size;
1169
1170 str_size = sizeof (dword);
1171 for (i = 0; i < GROW_COUNT (symbols); ++i)
1172 {
1173 if (symbols[i].name == NULL)
1174 symbols[i].n.string = 0;
1175 else
1176 {
1177 symbols[i].n.string = str_size;
1178 str_size += strlen (symbols[i].name) + 1;
1179 }
1180 fwrite (&symbols[i].n, sizeof (struct nlist), 1, out_file);
1181 }
1182 fwrite (&str_size, sizeof (dword), 1, out_file);
1183 for (i = 0; i < GROW_COUNT (symbols); ++i)
1184 if (symbols[i].name != NULL)
1185 fwrite (symbols[i].name, strlen (symbols[i].name) + 1, 1, out_file);
1186}
1187
1188
1189/* Convert a MODEND record. */
1190
1191static void conv_modend (void)
1192{
1193 struct a_out_header h;
1194 int i;
1195
1196 make_symtab ();
1197 h.magic = 0407;
1198 h.machtype = 0;
1199 h.flags = 0;
1200 h.text_size = (seg_code >= 0 ? segments[seg_code].size : 0);
1201 h.data_size = (seg_data >= 0 ? segments[seg_data].size : 0);
1202 h.bss_size = (seg_bss >= 0 ? segments[seg_bss ].size : 0);
1203 h.sym_size = GROW_COUNT (symbols) * sizeof (struct nlist);
1204 h.entry = 0;
1205 h.trsize = GROW_COUNT (trelocs) * sizeof (struct reloc);
1206 h.drsize = GROW_COUNT (drelocs) * sizeof (struct reloc);
1207 fwrite (&h, sizeof (h), 1, out_file);
1208 if (seg_code >= 0)
1209 fwrite (segments[seg_code].data, segments[seg_code].size, 1, out_file);
1210 if (seg_data >= 0)
1211 fwrite (segments[seg_data].data, segments[seg_data].size, 1, out_file);
1212 for (i = 0; i < GROW_COUNT (trelocs); ++i)
1213 fwrite (&trelocs[i], sizeof (struct reloc), 1, out_file);
1214 for (i = 0; i < GROW_COUNT (drelocs); ++i)
1215 fwrite (&drelocs[i], sizeof (struct reloc), 1, out_file);
1216 write_symtab ();
1217}
1218
1219
1220static void omf_to_o (void)
1221{
1222 struct omf_rec rec;
1223
1224 do
1225 {
1226 if (fread (&rec, sizeof (rec), 1, inp_file) != 1)
1227 goto failure;
1228 rec_type = rec.rec_type;
1229 rec_len = rec.rec_len;
1230 rec_idx = 0;
1231 if (rec_len > sizeof (rec_buf))
1232 {
1233 rec_len = -1; /* See error2() */
1234 error2 ("Record too long");
1235 }
1236 if (fread (rec_buf, rec_len, 1, inp_file) != 1)
1237 goto failure;
1238 /*...check checksum...*/
1239 --rec_len;
1240 switch (rec_type)
1241 {
1242 case THEADR:
1243 break;
1244
1245 case COMENT:
1246 break;
1247
1248 case MODEND:
1249 case MODEND|REC32:
1250 conv_modend ();
1251 break;
1252
1253 case EXTDEF:
1254 conv_extdef ();
1255 break;
1256
1257 case TYPDEF:
1258 break;
1259
1260 case PUBDEF:
1261 case PUBDEF|REC32:
1262 conv_pubdef ();
1263 break;
1264
1265 case LINNUM:
1266 case LINNUM|REC32:
1267 break;
1268
1269 case LNAMES:
1270 conv_lnames ();
1271 break;
1272
1273 case SEGDEF:
1274 case SEGDEF|REC32:
1275 conv_segdef ();
1276 break;
1277
1278 case GRPDEF:
1279 conv_grpdef ();
1280 break;
1281
1282 case FIXUPP:
1283 case FIXUPP|REC32:
1284 conv_fixupp ();
1285 break;
1286
1287 case LEDATA:
1288 case LEDATA|REC32:
1289 conv_ledata ();
1290 break;
1291
1292 case LIDATA:
1293 case LIDATA|REC32:
1294 conv_lidata ();
1295 break;
1296
1297 case COMDEF:
1298 conv_comdef ();
1299 break;
1300
1301 case COMDAT:
1302 case COMDAT|REC32:
1303 break;
1304
1305 default:
1306 error2 ("Unknown record type: %.2x\n", rec.rec_type);
1307 }
1308 } while (rec_type != MODEND && rec_type != (MODEND|REC32));
1309 return;
1310
1311failure:
1312 if (ferror (inp_file))
1313 error ("%s: %s", inp_fname, strerror (errno));
1314 else
1315 error ("%s: Unexpected end of file", inp_fname);
1316}
1317
1318
1319/* Convert the OMF file SRC_FNAME to an a.out file named DST_FNAME.
1320 If DST_FNAME is NULL, the output file name is derived from
1321 SRC_FNAME. */
1322
1323static void convert (const char *src_fname, const char *dst_fname)
1324{
1325 init_module ();
1326
1327 inp_fname = src_fname;
1328 inp_file = fopen (inp_fname, "rb");
1329 if (inp_file == NULL)
1330 error ("Cannot open input file `%s'", inp_fname);
1331
1332 make_out_fname (dst_fname, inp_fname, ".o");
1333 open_output ();
1334 omf_to_o ();
1335 close_output ();
1336 fclose (inp_file);
1337
1338 term_module ();
1339}
1340
1341
1342/* Main function of emxaout. Parse the command line and perform the
1343 requested actions. */
1344
1345int main (int argc, char *argv[])
1346{
1347 int c, i;
1348 char *opt_o;
1349
1350 /* Expand response files (@filename) and wildcard (*.o) on the
1351 command line. */
1352
1353 _response (&argc, &argv);
1354 _wildcard (&argc, &argv);
1355
1356 /* Set default values of some options. */
1357
1358 opt_o = NULL;
1359 opterr = FALSE;
1360
1361 /* Parse the command line options. */
1362
1363 while ((c = getopt (argc, argv, "uo:")) != EOF)
1364 switch (c)
1365 {
1366 case 'o':
1367 if (opt_o != NULL)
1368 usage ();
1369 opt_o = optarg;
1370 break;
1371 case 'u':
1372 underscores = TRUE;
1373 break;
1374 default:
1375 usage ();
1376 }
1377
1378 /* Check for non-option arguments. */
1379
1380 if (argc - optind == 0)
1381 usage ();
1382
1383 if (opt_o != NULL)
1384 {
1385
1386 /* If the -o option is used, there must be exactly one input
1387 file name. */
1388
1389 if (argc - optind != 1)
1390 usage ();
1391 convert (argv[optind], opt_o);
1392 }
1393 else
1394 {
1395
1396 /* The -o option is not used. Convert all the files named on the
1397 command line. */
1398
1399 for (i = optind; i < argc; ++i)
1400 convert (argv[i], NULL);
1401 }
1402
1403 return 0;
1404}
Note: See TracBrowser for help on using the repository browser.