* added compilers lcc and bcc (linux86)
[mascara-docs.git] / compilers / linux86-0.16.17 / ld / objdump86.c
blob003f04ca23b3d2e9adf73f43b1cda0b639ed6a8a
1 /*
2 * This is a combination of three tools for decoding information from
3 * Dev86/ELKS object files and executables.
5 * This executable can be given the names:
7 * objdump86: Dumps detailed information about a binary file.
8 * size86: Summary sizes of the data in a binary file.
9 * nm86: The symbol table of the binary file.
11 * None of these programs have any options.
12 * This may be a minor problem with nm86.
14 * Copyright (c) 1999 by Greg Haerr <greg@censoft.com>
15 * Added archive file reading capabilties
18 #include <stdio.h>
19 #ifdef __STDC__
20 #include <stdlib.h>
21 #else
22 #include <malloc.h>
23 #endif
24 #include <string.h>
25 #include "const.h"
26 #include "ar.h"
27 #include "obj.h"
29 FILE * ifd;
30 char * ifname;
32 #ifdef __STDC__
33 #define _(x) x
34 #else
35 #define _(x) ()
36 #endif
38 long get_long _((void));
39 long get_sized _((int sz));
40 unsigned int get_word _((void));
41 int get_byte _((void));
42 int main _((int argc, char**argv));
43 void do_file _((char * fname));
44 long read_arheader _((char *archentry));
45 void do_module _((char * fname, char *archive));
46 int error _((char * str));
47 int read_objheader _((void));
48 int read_sectheader _((void));
49 int read_syms _((void));
50 void disp_sectheader _((void));
51 int disp_syms _((void));
52 void read_databytes _((void));
53 void hex_output _((int ch));
54 void fetch_aout_hdr _((void));
55 void dump_aout _((void));
56 void size_aout _((void));
57 void nm_aout _((void));
59 int obj_ver;
60 int sections;
61 long segsizes[16];
62 long textoff;
63 long textlen;
64 long str_off;
65 long str_len;
66 long filepos;
67 int num_syms;
68 long code_bytes;
70 char ** symnames;
71 char * strtab;
73 struct {
74 unsigned int nameoff, symtype;
75 long offset;
76 } *symtab;
78 int display_mode = 0;
79 int multiple_files = 0;
80 int byte_order = 0;
82 int opt_o;
84 long size_text, size_data, size_bss;
85 long tot_size_text=0, tot_size_data=0, tot_size_bss=0;
87 int
88 main(argc, argv)
89 int argc;
90 char ** argv;
92 int ar;
93 char * p;
95 ifd = stdin; /* In Libc6 stdin is weird */
97 p = strrchr(argv[0], '/');
98 if(p) p++; else p=argv[0];
100 if( p[0] == 's' ) display_mode = 1;
101 if( p[0] == 'n' ) display_mode = 2;
103 multiple_files = 0;
104 for(ar=1; ar<argc; ar++)
106 if( argv[ar][0] == '-' ) switch(argv[ar][1])
108 case 's': display_mode = 1; break;
109 case 'n': display_mode = 2; break;
110 case 'o': opt_o++; break;
112 else
113 multiple_files++;
116 if( !multiple_files ) exit(1);
118 multiple_files = (multiple_files>1);
120 if( display_mode == 1 )
121 printf("text\tdata\tbss\tdec\thex\tfilename\n");
123 for(ar=1; ar<argc; ar++) if(argv[ar][0] != '-')
124 do_file(argv[ar]);
126 if( display_mode == 1 && multiple_files)
127 printf("%ld\t%ld\t%ld\t%ld\t%lx\tTotal\n",
128 tot_size_text, tot_size_data, tot_size_bss,
129 tot_size_text+ tot_size_data+ tot_size_bss,
130 tot_size_text+ tot_size_data+ tot_size_bss);
132 return 0;
135 void
136 do_file(fname)
137 char * fname;
139 unsigned int magic;
140 long filelength;
141 char archentry[sizeof(struct ar_hdr)]; /* sizeof ar_hdr.ar_name*/
142 char filemagic[SARMAG];
144 ifname = fname;
145 if( (ifd=fopen(fname, "rb")) == 0 )
147 error("Cannot open file");
148 return;
150 filepos = 0L;
152 /* check if file is an archive*/
153 if(fread(filemagic, sizeof(filemagic), 1, ifd) == 1
154 && strncmp(filemagic, ARMAG, sizeof filemagic) == 0)
156 filepos = SARMAG;
157 while((filelength = read_arheader(archentry)) > 0)
159 filepos += sizeof(struct ar_hdr);
160 magic = get_word();
161 if(magic == 0x86A3)
162 { /* OMAGIC*/
163 fseek(ifd, filepos, 0);
164 do_module(archentry, fname);
166 else if(magic == 0x3C21 ) /* "!<" */
167 filelength = SARMAG;
168 filepos += ld_roundup(filelength, 2, long);
169 fseek(ifd, filepos, 0);
172 else
174 fseek(ifd, 0L, 0);
175 do_module(fname, NULL);
177 fclose(ifd);
180 /* read archive header and return length */
181 long
182 read_arheader(archentry)
183 char *archentry;
185 char * endptr;
186 struct ar_hdr arheader;
188 if(fread((char *)&arheader, sizeof(arheader), 1, ifd) != 1)
189 return 0;
190 strncpy(archentry, arheader.ar_name, sizeof(arheader.ar_name));
191 archentry[sizeof(arheader.ar_name)] = 0;
192 endptr = archentry + sizeof(arheader.ar_name);
195 *endptr-- = 0;
196 } while(endptr > archentry && (*endptr == ' ' || *endptr == '/'));
197 return strtoul(arheader.ar_size, (char **)NULL, 0);
200 void
201 do_module(fname, archive)
202 char * fname;
203 char * archive;
205 int modno, i;
207 size_text = size_data = size_bss = 0;
208 byte_order = 0;
210 if( !display_mode )
212 if(archive)
213 printf("ARCHIVEFILE '%s'\n", archive);
214 printf("OBJECTFILE '%s'\n", fname);
217 switch( read_objheader() )
219 case 0: /* as86 object file */
221 for(modno=1; modno<=sections; modno++)
223 if( modno != 1 && !display_mode )
224 printf("OBJECTSECTION %d\n", modno);
225 if( read_sectheader() < 0 ) break;
227 /* segments 0, 4-E are text, 1-3 are data*/
228 for(i=0; i<16; i++)
230 if(i < 1 || i > 4)
231 size_text += segsizes[i];
232 else size_data += segsizes[i];
235 if( read_syms() < 0 ) break;
237 strtab = malloc((unsigned int)str_len+1);
238 if( strtab == 0 ) { error("Out of memory"); break; }
239 str_off = ftell(ifd);
240 fread(strtab, 1, (unsigned int)str_len, ifd);
242 disp_sectheader();
243 disp_syms();
245 if( display_mode == 0 )
246 printf("text\tdata\tbss\tdec\thex\tfilename\n");
247 if( display_mode != 2 )
249 printf("%ld\t%ld\t%ld\t%ld\t%lx\t",
250 size_text, size_data, size_bss,
251 size_text+ size_data+ size_bss,
252 size_text+ size_data+ size_bss);
254 if(archive) printf("%s(%s)\n", archive, fname);
255 else printf("%s\n", fname);
257 tot_size_text += size_text;
258 tot_size_data += size_data;
259 tot_size_bss += size_bss;
262 if( sections == 1 && display_mode != 0 )
263 break;
265 read_databytes();
267 break;
269 case 1: /* ELKS executable */
270 fseek(ifd, 0L, 0);
271 fetch_aout_hdr();
273 switch(display_mode)
275 case 0: dump_aout(); break;
276 case 1: size_aout(); break;
277 case 2: nm_aout(); break;
279 break;
282 if( strtab ) free(strtab);
283 if( symnames ) free(symnames);
284 strtab = 0;
285 symnames = 0;
289 error(str)
290 char * str;
292 switch( display_mode )
294 case 1: fprintf(stderr, "size: %s: %s\n", ifname, str); break;
295 case 2: fprintf(stderr, "nm: %s: %s\n", ifname, str); break;
296 default:
297 printf("Error: %s\n", str);
298 break;
300 return -1;
304 read_objheader()
306 unsigned char buf[5];
308 if( fread(buf, 1, 5, ifd) != 5 )
309 return error("Cannot read object header");
311 if( buf[0] != 0xA3 || buf[1] != 0x86 )
313 if( buf[0] == 1 && buf[1] == 3 )
315 sections = 1;
316 return 1;
318 return error("Bad magic number");
321 if( (unsigned char)(buf[0] + buf[1] + buf[2] + buf[3]) != buf[4] )
322 return error("Bad header checksum");
324 sections= buf[2]+256*buf[3];
326 return 0;
330 read_sectheader()
332 long ssenc;
333 int i;
335 textoff = get_long(); /* Offset of bytecode in file */
336 textlen = get_long(); /* Length of text+data (no bss) in memory */
337 str_len = get_word(); /* Length of string table in file */
338 obj_ver = get_word(); /* 0.0 */
340 (void)get_long(); /* Ignore fives */
341 ssenc = get_long(); /* Sixteen segment size sizes */
343 for(i=0; i<16; i++)
345 int ss;
346 ss = (i^3);
347 ss = ((ssenc>>(2*(15-ss)))&3);
348 segsizes[i] = get_sized(ss);
351 num_syms = get_word(); /* Number of symbol codes */
353 return 0;
356 void
357 disp_sectheader()
359 int i;
360 if( display_mode ) return;
362 printf("MODULE '%s'\n", strtab);
363 printf("BYTEPOS %08lx\n", textoff);
364 printf("BINLEN %08lx\n", textlen);
365 printf("STRINGS %04lx +%04lx\n", str_off, str_len);
366 printf("VERSION %d.%d\n", obj_ver/256, obj_ver%256);
368 for(i=0; i<16; i++)
369 if( segsizes[i] )
370 printf("SEG%x %08lx\n", i, segsizes[i]);
372 printf("\n");
373 printf("SYMS %u\n", num_syms);
377 read_syms()
379 int i;
381 if( num_syms < 0 ) return error("Bad symbol table");
383 symnames = malloc(num_syms*sizeof(char*)+1);
384 if( symnames == 0 ) return error("Out of memory");
386 symtab = calloc(num_syms, sizeof(*symtab));
387 if( symtab == 0 ) return error("Out of memory");
389 for(i=0; i<num_syms; i++)
391 unsigned int symtype;
393 symtab[i].nameoff = get_word();
394 symtab[i].symtype = get_word();
395 symtype = (symtab[i].symtype & 0x3FFF);
397 if (symtab[i].nameoff == -1 || symtab[i].symtype == -1) {
398 printf("!!! EOF in symbol table\n");
399 break;
401 symtab[i].offset = get_sized((symtab[i].symtype>>14)&3);
403 if( symtype == 0x43 || symtype == 0x2003 )
404 size_bss += symtab[i].offset;
407 return 0;
411 disp_syms()
413 int i;
415 if(display_mode == 2 && multiple_files && !opt_o)
416 printf("\n%s:\n", ifname);
418 for(i=0; i<num_syms; i++)
420 long offset=0;
421 unsigned int nameoff, symtype;
423 nameoff = symtab[i].nameoff;
424 symtype = symtab[i].symtype;
425 offset = symtab[i].offset;
427 symtype &= 0x3FFF;
428 if (nameoff > str_len || nameoff < 0)
429 symnames[i] = strtab + str_len;
430 else
431 symnames[i] = strtab+nameoff;
433 if( !display_mode )
435 printf("SYM %-4d %08lx ", i, offset);
437 printf("%s", (symtype&0x2000)?"C":".");
438 printf("%s", (symtype&0x0100)?"N":".");
439 printf("%s", (symtype&0x0080)?"E":".");
440 printf("%s", (symtype&0x0040)?"I":".");
441 printf("%c", "T12D456789abcdeUAhijklmnopqrstuv"[symtype&0x1F]);
442 if( symtype &0x1E20 )
443 printf(" %04x", symtype);
444 printf(" %s\n", symnames[i]);
446 if( display_mode == 2 )
448 if (opt_o)
449 printf("%s: ", ifname);
450 if( symtype == 0x004f || symtype == 0x0040 )
451 printf(" ");
452 else
453 printf("%08lx ", offset);
454 switch(symtype)
456 case 0x004F: putchar('U'); break;
457 case 0x0000: putchar('t'); break;
458 case 0x0003: putchar('d'); break;
459 case 0x2003: putchar('b'); break;
460 case 0x0043: putchar('C'); break;
461 case 0x0083: putchar('D'); break;
462 case 0x0080: putchar('T'); break;
463 case 0x0040: putchar('T'); break;
464 case 0x0180: putchar('N'); break;
465 case 0x0010: putchar('a'); break;
466 case 0x0090: putchar('A'); break;
467 default:
468 if((symtype & ~0xF) == 0x40 )
469 putchar('u');
470 else if((symtype & ~0xF) == 0x80 )
471 printf("%c", "T12D456789abcdeU"[symtype&0xF]);
472 else
473 putchar('?');
474 break;
476 printf(" %s\n", symnames[i]);
479 if( !display_mode )
480 printf("\n");
482 return 0;
485 void
486 read_databytes()
488 static char * relstr[] = {"ERR", "DB", "DW", "DD"};
489 long l, cpos;
490 int ch, i;
491 int curseg = 0;
492 int relsize = 0;
494 cpos = ftell(ifd);
495 fseek(ifd, filepos+textoff, 0);
497 printf("\nBYTECODE\n");
498 for(;;)
500 if( (ch=get_byte()) == -1 ) break;
502 if( ch == 0 ) break;
504 switch( ch & 0xC0 )
506 case 0x00: switch(ch & 0xF0)
508 case 0x00: /* Relocator size */
509 printf("RELSZ %d\n", relsize= (ch&0xF));
510 if(relsize>3) relsize=3;
511 break;
512 case 0x10: /* Skip bytes */
513 printf("SKP %ld\n", get_sized(ch&0xF));
514 break;
515 case 0x20: /* Segment */
516 printf("SEG %x\n", curseg= (ch&0xF));
517 break;
518 default: printf("CODE %02x - unknown\n", ch);
519 goto break_break ;
521 break;
522 case 0x40: /* Raw bytes */
524 int abscnt = (ch&0x3F);
525 if( abscnt == 0 ) abscnt = 64;
526 for( i=0; i<abscnt; i++ )
528 if( (ch=get_byte()) == -1 ) break;
529 hex_output(ch);
531 hex_output(EOF);
533 if( ch == -1 ) goto break_break;
535 break;
536 case 0x80: /* Relocator - simple */
537 l = get_sized(relsize);
538 printf("%s SEG%x%s%s", relstr[relsize],
539 (ch&0xF),
540 (ch&0x20)?"-PC":"",
541 (ch&0x10)?"+?":"");
542 if(l)
543 printf("+0x%04lx", l);
544 putchar('\n');
545 break;
546 case 0xC0: /* Relocator - symbol relative */
547 if( ch & 0x18 )
549 printf("CODE %02x - unknown\n", ch);
550 goto break_break;
552 if( ch & 4 ) i = get_word();
553 else i = get_byte();
554 l = get_sized(ch&3);
556 printf("%s %s%s%s", relstr[relsize],
557 symnames[i],
558 (ch&0x20)?"-PC":"",
559 (ch&0x18)?"+?":"");
560 if(l)
561 printf("+0x%04lx", l);
562 putchar('\n');
563 break;
566 break_break:;
567 printf("\n");
568 fseek(ifd, cpos, 0);
571 long
572 get_sized(sz)
573 int sz;
575 switch(sz)
577 case 0: return 0;
578 case 1: return get_byte();
579 case 2: return get_word();
580 case 3: return get_long();
582 return -1;
585 long
586 get_long()
588 long retv = 0;
589 int i;
590 for(i=0; i<32; i+=16)
592 unsigned int v = get_word();
593 if( byte_order & 2 )
594 retv += ((long)v<<(16-i));
595 else
596 retv += ((long)v<<i);
598 return retv;
601 unsigned int
602 get_word()
604 long retv = 0;
605 int i;
606 for(i=0; i<16; i+=8)
608 int v = getc(ifd);
609 if( v == EOF ) return -1;
610 code_bytes++;
611 if( byte_order & 1 )
612 retv += (v<<(8-i));
613 else
614 retv += (v<<i);
616 return retv;
620 get_byte()
622 int v = getc(ifd);
623 if (v == EOF) return -1;
624 code_bytes++;
625 return v;
628 void
629 hex_output(ch)
630 int ch;
632 static char linebuf[80];
633 static char buf[20];
634 static int pos = 0;
636 if( ch == EOF )
638 if(pos)
639 printf(": %.66s\n", linebuf);
640 pos = 0;
642 else
644 if(!pos)
645 memset(linebuf, ' ', sizeof(linebuf));
646 sprintf(buf, "%02x", ch&0xFF);
647 memcpy(linebuf+pos*3+(pos>7), buf, 2);
648 if( ch > ' ' && ch <= '~' ) linebuf[50+pos] = ch;
649 else linebuf[50+pos] = '.';
650 pos = ((pos+1) & 0xF);
651 if( pos == 0 )
653 printf(": %.66s\n", linebuf);
654 memset(linebuf, ' ', sizeof(linebuf));
659 /************************************************************************/
660 /* ELKS a.out versions
663 long header[12];
664 int h_len, h_flgs, h_cpu;
666 void
667 fetch_aout_hdr()
669 int i;
671 header[0] = get_long();
672 header[1] = get_long();
673 byte_order = ((header[0]>>24) & 3);
675 h_len = (header[1] & 0xFF);
676 h_flgs = ((header[0]>>16) & 0xFF);
677 h_cpu = ((header[0]>>24) & 0xFF);
679 for(i=2; i<8; i++)
681 if( i*4 <= h_len )
682 header[i] = get_long();
683 else
684 header[i] = 0;
688 void
689 dump_aout()
691 static char * cpu[] = { "unknown", "8086", "m68k", "ns16k", "i386", "sparc" };
692 static char * byteord[] = { "LITTLE_ENDIAN", "(2143)","(3412)","BIG_ENDIAN" };
693 int i;
694 long l;
696 if( h_cpu > 0x17 ) h_cpu &= 3;
698 printf("HLEN %d\n", h_len);
699 printf("CPU %s %s\n", cpu[h_cpu>>2], byteord[h_cpu&3]);
701 printf("FLAGS:");
702 if( h_flgs & 0x01 ) printf(" A_UZP");
703 if( h_flgs & 0x02 ) printf(" A_PAL");
704 if( h_flgs & 0x04 ) printf(" A_NSYM");
705 if( h_flgs & 0x08 ) printf(" FLG-08");
706 if( h_flgs & 0x10 ) printf(" A_EXEC");
707 if( h_flgs & 0x20 ) printf(" A_SEP");
708 if( h_flgs & 0x40 ) printf(" A_PURE");
709 if( h_flgs & 0x80 ) printf(" A_TOVLY");
710 printf("\n");
712 if( header[5] )
713 printf("a_entry = 0x%08lx\n", header[5]);
714 printf("a_total = 0x%08lx\n", header[6]);
715 if( header[7] )
716 printf("a_syms = 0x%08lx\n", header[7]);
718 if( h_len >= 36 )
719 printf("a_trsize = 0x%08lx\n", header[8]);
720 if( h_len >= 40 )
721 printf("a_drsize = 0x%08lx\n", header[9]);
722 if( h_len >= 44 )
723 printf("a_tbase = 0x%08lx\n", header[10]);
724 if( h_len >= 48 )
725 printf("a_dbase = 0x%08lx\n", header[11]);
726 printf("\n");
728 size_aout();
729 printf("\n");
731 if( header[7] )
733 printf("SYMBOLS\n");
734 nm_aout();
736 else
737 printf("NO SYMBOLS\n");
738 printf("\n");
740 printf("TEXTSEG\n");
741 fseek(ifd, (long)h_len, 0);
742 for(l=0; l<header[2]; l++)
744 if( (i=getc(ifd)) == EOF ) break;
745 hex_output(i);
747 hex_output(EOF);
749 printf("DATASEG\n");
750 fseek(ifd, (long)h_len+header[2], 0);
751 for(l=0; l<header[3]; l++)
753 if( (i=getc(ifd)) == EOF ) break;
754 hex_output(i);
756 hex_output(EOF);
759 void
760 size_aout()
762 if( display_mode == 0 )
763 printf("text\tdata\tbss\tdec\thex\tfilename\n");
765 printf("%ld\t%ld\t%ld\t%ld\t%lx\t%s\n",
766 header[2], header[3], header[4],
767 header[2]+ header[3]+ header[4],
768 header[2]+ header[3]+ header[4],
769 ifname);
771 tot_size_text += header[2];
772 tot_size_data += header[3];
773 tot_size_bss += header[4];
776 void
777 nm_aout()
779 char n_name[10];
780 long n_value;
781 int n_sclass, n_numaux, n_type;
782 long bytes_left;
783 int pending_nl = 0;
785 fseek(ifd, h_len+header[2]+header[3]+header[8]+header[9], 0);
787 if( h_flgs & 4 )
788 { error("Executable has new format symbol table.\n"); return; }
790 bytes_left = header[7];
792 if( bytes_left == 0 )
793 printf("No symbols in '%s'\n", ifname);
794 else if(multiple_files && !opt_o)
795 printf("\n%s:\n", ifname);
797 while(bytes_left > 16)
799 if( fread(n_name, 1, 8, ifd) != 8 ) break;
800 n_name[8] = 0;
801 n_value = get_long();
802 if( (n_sclass = getc(ifd)) == EOF ) break;
803 if( (n_numaux = getc(ifd)) == EOF ) break;
804 n_type = get_word();
806 if( pending_nl && n_sclass == 0 )
808 printf("%s", n_name);
809 continue;
812 if( pending_nl ) putchar('\n');
813 if (opt_o)
814 printf("%s: ", ifname);
815 if( n_sclass == 0x10 )
816 printf(" ");
817 else
818 printf("%08lx ", n_value);
819 switch(n_sclass)
821 case 0x01: printf("a "); break;
822 case 0x12: printf("T "); break;
823 case 0x13: printf("D "); break;
824 case 0x14: printf("C "); break;
825 case 0x1a: printf("t "); break;
826 case 0x1b: printf("d "); break;
827 case 0x1c: printf("b "); break;
828 case 0x10: printf("U "); break;
829 default: if( display_mode )
831 printf("? "); break;
834 printf("n_sclass=");
835 switch(n_sclass>>3)
837 case 0: printf("C_NULL,"); break;
838 case 2: printf("C_EXT,"); break;
839 case 3: printf("C_STAT,"); break;
840 default: printf("%04o,", n_sclass&0xF8);
842 switch(n_sclass&7)
844 case 0: printf("N_UNDF "); break;
845 case 1: printf("N_ABS "); break;
846 case 2: printf("N_TEXT "); break;
847 case 3: printf("N_DATA "); break;
848 case 4: printf("N_BSS "); break;
849 case 5: printf("N_COMM "); break;
850 default: printf("%o ", n_sclass&7); break;
852 break;
855 if( display_mode == 0 )
857 if( n_numaux )
858 printf("n_numaux=%02x ", n_numaux);
859 if( n_type )
860 printf("n_type=%04x ", n_type);
863 printf("%s", n_name);
865 pending_nl=1;
868 if( pending_nl ) putchar('\n');