source: trunk/emx/src/emxomf/emxaout.c@ 3669

Last change on this file since 3669 was 1517, checked in by bird, 21 years ago

Fixing warnings. -Znofork

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