1 static char *sccsid = "@(#) dismain.c, Ver. 2.1 created 00:00:00 87/09/01";
2
3 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
4 * *
5 * Copyright (C) 1987 G. M. Harding, all rights reserved *
6 * *
7 * Permission to copy and redistribute is hereby granted, *
8 * provided full source code, with all copyright notices, *
9 * accompanies any redistribution. *
10 * *
11 * This file contains the source code for the machine- *
12 * independent portions of a disassembler program to run *
13 * in a Unix (System III) environment. It expects, as its *
14 * input, a file in standard a.out format, optionally con- *
15 * taining symbol table information. If a symbol table is *
16 * present, it will be used in the disassembly; otherwise, *
17 * all address references will be literal (absolute). *
18 * *
19 * The disassembler program was originally written for an *
20 * Intel 8088 CPU. However, all details of the actual CPU *
21 * architecture are hidden in three machine-specific files *
22 * named distabs.c, dishand.c, and disfp.c (the latter *
23 * file is specific to the 8087 numeric co-processor). The *
24 * code in this file is generic, and should require mini- *
25 * mal revision if a different CPU is to be targeted. If a *
26 * different version of Unix is to be targeted, changes to *
27 * this file may be necessary, and if a completely differ- *
28 * ent OS is to be targeted, all bets are off. *
29 * *
30 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
31
32 #include "dis.h" /* Disassembler declarations */
33
34 extern char *release; /* Contains release string */
35 static char *IFILE = NULL; /* Points to input file name */
36 static char *OFILE = NULL; /* Points to output file name */
37 static char *PRG; /* Name of invoking program */
38 static unsigned long zcount; /* Consecutive "0" byte count */
39 int objflg = 0; /* Flag: output object bytes */
40 int force = 0; /* Flag: override some checks */
41
42 #define unix 1
43 #define i8086 1
44 #define ibmpc 1
45
46 #if unix && i8086 && ibmpc /* Set the CPU identifier */
47 static int cpuid = 1;
48 #else
49 static int cpuid = 0;
50 #endif
51
52 _PROTOTYPE(static void usage, (char *s ));
53 _PROTOTYPE(static void fatal, (char *s, char *t ));
54 _PROTOTYPE(static void zdump, (unsigned long beg ));
55 _PROTOTYPE(static void prolog, (void));
56 _PROTOTYPE(static void distext, (void));
57 _PROTOTYPE(static void disdata, (void));
58 _PROTOTYPE(static void disbss, (void));
59
60 _PROTOTYPE(static char *invoker, (char *s));
61 _PROTOTYPE(static int objdump, (char *c));
62 _PROTOTYPE(static char *getlab, (int type));
63 _PROTOTYPE(static void prolog, (void));
64
65 /* * * * * * * MISCELLANEOUS UTILITY FUNCTIONS * * * * * * */
66
67 static void
usage(s)68 usage(s)
69 register char *s;
70 {
71 fprintf(stderr,"Usage: %s [-o] ifile [ofile]\n",s);
72 exit(-1);
73 }
74
75 static void
fatal(s,t)76 fatal(s,t)
77 register char *s, *t;
78 {
79 fprintf(stderr,"%s: %s\n",s,t);
80 exit(-1);
81 }
82
83 static void
zdump(beg)84 zdump(beg)
85 unsigned long beg;
86 {
87 beg = PC - beg;
88 if (beg > 1L)
89 printf("\t.zerow\t%ld\n",(beg >> 1));
90 if (beg & 1L)
91 printf("\t.byte\t0\n");
92 }
93
94 static char *
invoker(s)95 invoker(s)
96 register char *s;
97 {
98 register int k;
99
100 k = strlen(s);
101
102 while (k--)
103 if (s[k] == '/')
104 {
105 s += k;
106 ++s;
107 break;
108 }
109
110 return (s);
111 }
112
113 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
114 * *
115 * This rather tricky routine supports the disdata() func- *
116 * tion. Its job is to output the code for a sequence of *
117 * data bytes whenever the object buffer is full, or when *
118 * a symbolic label is to be output. However, it must also *
119 * keep track of consecutive zero words so that lengthy *
120 * stretches of null data can be compressed by the use of *
121 * an appropriate assembler pseudo-op. It does this by *
122 * setting and testing a file-wide flag which counts suc- *
123 * cessive full buffers of null data. The function returns *
124 * a logical TRUE value if it outputs anything, logical *
125 * FALSE otherwise. (This enables disdata() to determine *
126 * whether to output a new synthetic label when there is *
127 * no symbol table.) *
128 * *
129 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
130
131 static int
objdump(c)132 objdump(c)
133
134 register char *c;
135
136 {/* * * * * * * * * * START OF objdump() * * * * * * * * * */
137
138 register int k,j;
139 int retval = 0;
140
141 if (objptr == OBJMAX)
142 {
143 for (k = 0; k < OBJMAX; ++k)
144 if (objbuf[k])
145 break;
146 if (k == OBJMAX)
147 {
148 zcount += k;
149 objptr = 0;
150 if (c == NULL)
151 return (retval);
152 }
153 }
154
155 if (zcount)
156 {
157 printf("\t.zerow\t%ld\n",(zcount >> 1));
158 ++retval;
159 zcount = 0L;
160 }
161
162 if (objptr)
163 {
164 printf("\t.byte\t");
165 ++retval;
166 }
167 else
168 return (retval);
169
170 for (k = 0; k < objptr; ++k)
171 {
172 printf("$%02.2x",objbuf[k]);
173 if (k < (objptr - 1))
174 putchar(',');
175 }
176
177 for (k = objptr; k < OBJMAX; ++k)
178 printf(" ");
179
180 printf(" | \"");
181
182 for (k = 0; k < objptr; ++k)
183 {
184 if (objbuf[k] > ' ' && objbuf[k] <= '~' )
185 putchar(objbuf[k]);
186 else switch(objbuf[k])
187 {
188 case '\t': printf("\\t"); break;
189 case '\n': printf("\\n"); break;
190 case '\f': printf("\\f"); break;
191 case '\r': printf("\\r"); break;
192 default: putchar('.'); break;
193 }
194 }
195 printf("\"\n");
196
197 objptr = 0;
198
199 return (retval);
200
201 }/* * * * * * * * * * END OF objdump() * * * * * * * * * */
202
203 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
204 * *
205 * This routine, called at the beginning of the input *
206 * cycle for each object byte, and before any interpreta- *
207 * tion is attempted, searches the symbol table for any *
208 * symbolic name with a value corresponding to the cur- *
209 * rent PC and a type corresponding to the segment type *
210 * (i.e., text, data, or bss) specified by the function's *
211 * argument. If any such name is found, a pointer to it is *
212 * returned; otherwise, a NULL pointer is returned. *
213 * *
214 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
215
216 static char *
getlab(type)217 getlab(type)
218 register int type;
219 {/* * * * * * * * * * START OF getlab() * * * * * * * * * */
220
221 register int k;
222 static char b[48], c[32];
223
224 if (symptr < 0)
225 if ((type == N_TEXT)
226 || ((type == N_DATA) && ( ! objptr ) && ( ! zcount )))
227 {
228 if (type == N_TEXT)
229 sprintf(b,"T%05.5lx:",PC);
230 else
231 sprintf(b,"D%05.5lx:",PC);
232 return (b);
233 }
234 else
235 return (NULL);
236
237 for (k = 0; k <= symptr; ++k)
238 if ((symtab[k].n_value == PC)
239 && ((symtab[k].n_sclass & N_SECT) == type))
240 {
241 sprintf(b,"%s:\n",getnam(k));
242 if (objflg && (type != N_TEXT))
243 sprintf(c,"| %05.5lx\n",PC);
244 strcat(b,c);
245 return (b);
246 }
247
248 return (NULL);
249
250 }/* * * * * * * * * * * END OF getlab() * * * * * * * * * * */
251
252 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
253 * *
254 * This routine performs a preliminary scan of the symbol *
255 * table, before disassembly begins, and outputs declara- *
256 * tions of globals and constants. *
257 * *
258 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
259
260 static void
prolog()261 prolog()
262
263 {/* * * * * * * * * * START OF prolog() * * * * * * * * * */
264
265 register int j, flag;
266
267 fflush(stdout);
268
269 if (symptr < 0)
270 return;
271
272 for (j = flag = 0; j <= symptr; ++j)
273 if ((symtab[j].n_sclass & N_CLASS) == C_EXT)
274 if (((symtab[j].n_sclass & N_SECT) > N_UNDF)
275 && ((symtab[j].n_sclass & N_SECT) < N_COMM))
276 {
277 char *c = getnam(j);
278 printf("\t.globl\t%s",c);
279 if (++flag == 1)
280 {
281 putchar('\t');
282 if (strlen(c) < 8)
283 putchar('\t');
284 printf("| Internal global\n");
285 }
286 else
287 putchar('\n');
288 }
289 else
290 if (symtab[j].n_value)
291 {
292 char *c = getnam(j);
293 printf("\t.comm\t%s,0x%08.8lx",c,
294 symtab[j].n_value);
295 if (++flag == 1)
296 printf("\t| Internal global\n");
297 else
298 putchar('\n');
299 }
300
301 if (flag)
302 putchar('\n');
303 fflush(stdout);
304
305 for (j = flag = 0; j <= relptr; ++j)
306 if (relo[j].r_symndx < S_BSS)
307 {
308 char *c = getnam(relo[j].r_symndx);
309 ++flag;
310 printf("\t.globl\t%s",c);
311 putchar('\t');
312 if (strlen(c) < 8)
313 putchar('\t');
314 printf("| Undef: %05.5lx\n",relo[j].r_vaddr);
315 }
316
317 if (flag)
318 putchar('\n');
319 fflush(stdout);
320
321 for (j = flag = 0; j <= symptr; ++j)
322 if ((symtab[j].n_sclass & N_SECT) == N_ABS)
323 {
324 char *c = getnam(j);
325 printf("%s=0x%08.8lx",c,symtab[j].n_value);
326 if (++flag == 1)
327 {
328 printf("\t\t");
329 if (strlen(c) < 5)
330 putchar('\t');
331 printf("| Literal\n");
332 }
333 else
334 putchar('\n');
335 }
336
337 if (flag)
338 putchar('\n');
339 fflush(stdout);
340
341 }/* * * * * * * * * * * END OF prolog() * * * * * * * * * * */
342
343 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
344 * *
345 * This function is responsible for disassembly of the *
346 * object file's text segment. *
347 * *
348 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
349
350 static void
distext()351 distext()
352
353 {/* * * * * * * * * * START OF distext() * * * * * * * * * */
354
355 char *c;
356 register int j;
357 register void (*f)();
358
359 for (j = 0; j < (int)(HDR.a_hdrlen); ++j)
360 getchar();
361
362 printf("| %s, %s\n\n",PRG,release);
363
364 printf("| @(");
365
366 printf("#)\tDisassembly of %s",IFILE);
367
368 if (symptr < 0)
369 printf(" (no symbols)\n\n");
370 else
371 printf("\n\n");
372
373 if (HDR.a_flags & A_EXEC)
374 printf("| File is executable\n\n");
375
376 if (HDR.a_flags & A_SEP)
377 printf("| File has split I/D space\n\n");
378
379 prolog();
380
381 printf("\t.text\t\t\t| loc = %05.5lx, size = %05.5lx\n\n",
382 PC,HDR.a_text);
383 fflush(stdout);
384
385 segflg = 0;
386
387 for (PC = 0L; PC < HDR.a_text; ++PC)
388 {
389 j = getchar();
390 if( j == EOF ) break;
391 j &= 0xFF;
392 if ((j == 0) && ((PC + 1L) == HDR.a_text))
393 {
394 ++PC;
395 break;
396 }
397 if ((c = getlab(N_TEXT)) != NULL)
398 printf("%s",c);
399 if( j>=0 && j<256 )
400 {
401 f = optab[j].func;
402 (*f)(j);
403 }
404 fflush(stdout);
405 }
406
407 }/* * * * * * * * * * END OF distext() * * * * * * * * * */
408
Fetch()409 Fetch()
410 {
411 int p;
412 ++PC;
413 if( symptr>=0 && getlab(N_TEXT) != NULL ) { --PC; return -1; }
414
415 /* #define FETCH(p) ++PC; p = getchar() & 0xff; objbuf[objptr++] = p */
416 p = getchar();
417 objbuf[objptr++] = p;
418 return p;
419 }
420
421 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
422 * *
423 * This function handles the object file's data segment. *
424 * There is no good way to disassemble a data segment, be- *
425 * cause it is impossible to tell, from the object code *
426 * alone, what each data byte refers to. If it refers to *
427 * an external symbol, the reference can be resolved from *
428 * the relocation table, if there is one. However, if it *
429 * refers to a static symbol, it cannot be distinguished *
430 * from numeric, character, or other pointer data. In some *
431 * cases, one might make a semi-educated guess as to the *
432 * nature of the data, but such guesses are inherently *
433 * haphazard, and they are bound to be wrong a good por- *
434 * tion of the time. Consequently, the data segment is *
435 * disassembled as a byte stream, which will satisfy no *
436 * one but which, at least, will never mislead anyone. *
437 * *
438 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
439
440 static void
disdata()441 disdata()
442
443 {/* * * * * * * * * * START OF disdata() * * * * * * * * * */
444
445 register char *c;
446 register int j;
447 unsigned long end;
448
449 putchar('\n');
450 if( HDR.a_data == 0 ) return;
451
452 if (HDR.a_flags & A_SEP)
453 {
454 PC = 0L;
455 end = HDR.a_data;
456 }
457 else
458 end = HDR.a_text + HDR.a_data;
459
460 printf("\t.data\t\t\t| loc = %05.5lx, size = %05.5lx\n\n",
461 PC,HDR.a_data);
462
463 segflg = 0;
464
465 for (objptr = 0, zcount = 0L; PC < end; ++PC)
466 {
467 if ((c = getlab(N_DATA)) != NULL)
468 {
469 objdump(c);
470 printf("%s",c);
471 }
472 if (objptr >= OBJMAX)
473 if (objdump(NULL) && (symptr < 0))
474 printf("D%05.5lx:",PC);
475 j = getchar() & 0xff;
476 objbuf[objptr++] = j;
477 }
478
479 objdump("");
480
481 }/* * * * * * * * * * END OF disdata() * * * * * * * * * */
482
483 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
484 * *
485 * This function handles the object file's bss segment. *
486 * Disassembly of the bss segment is easy, because every- *
487 * thing in it is zero by definition. *
488 * *
489 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
490
disbss()491 static void disbss()
492
493 {/* * * * * * * * * * START OF disbss() * * * * * * * * * */
494
495 register int j;
496 register char *c;
497 unsigned long beg, end;
498
499 putchar('\n');
500
501 if( HDR.a_bss == 0 ) return;
502
503 if (HDR.a_flags & A_SEP)
504 end = HDR.a_data + HDR.a_bss;
505 else
506 end = HDR.a_text + HDR.a_data + HDR.a_bss;
507
508 printf("\t.bss\t\t\t| loc = %05.5lx, size = %05.5lx\n\n",
509 PC,HDR.a_bss);
510
511 segflg = 0;
512
513 for (beg = PC; PC < end; ++PC)
514 if ((c = getlab(N_BSS)) != NULL)
515 {
516 if (PC > beg)
517 {
518 zdump(beg);
519 beg = PC;
520 }
521 printf("%s",c);
522 }
523
524 if (PC > beg)
525 zdump(beg);
526
527 }/* * * * * * * * * * * END OF disbss() * * * * * * * * * * */
528
529 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
530 * *
531 * This is the program entry point. The command line is *
532 * searched for an input file name, which must be present. *
533 * An optional output file name is also permitted; if none *
534 * is found, standard output is the default. One command- *
535 * line option is available: "-o", which causes the pro- *
536 * gram to include object code in comments along with its *
537 * mnemonic output. *
538 * *
539 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
540
541 void
main(argc,argv)542 main(argc,argv)
543
544 int argc; /* Command-line args from OS */
545 register char **argv;
546
547 {/* * * * * * * * * * * START OF main() * * * * * * * * * * */
548
549 char a[1024];
550 register int fd;
551 long taboff, tabnum;
552 long reloff, relnum;
553
554 PRG = invoker(*argv);
555
556 while (*++argv != NULL) /* Process command-line args */
557 if (**argv == '-')
558 switch (*++*argv)
559 {
560 case 'o' :
561 if (*++*argv)
562 usage(PRG);
563 else
564 ++objflg;
565 break;
566 case 'f' :
567 force++;
568 break;
569 default :
570 usage(PRG);
571 }
572 else
573 if (IFILE == NULL)
574 IFILE = *argv;
575 else if (OFILE == NULL)
576 OFILE = *argv;
577 else
578 usage(PRG);
579
580 if (IFILE == NULL)
581 usage(PRG);
582 else
583 if ((fd = open(IFILE,0)) < 0)
584 {
585 sprintf(a,"can't access input file %s",IFILE);
586 fatal(PRG,a);
587 }
588
589 if (OFILE != NULL)
590 if (freopen(OFILE,"w",stdout) == NULL)
591 {
592 sprintf(a,"can't open output file %s",OFILE);
593 fatal(PRG,a);
594 }
595
596 if ( ! cpuid )
597 fprintf(stderr,"%s: warning: host/cpu clash\n",PRG);
598
599 read(fd, (char *) &HDR,sizeof(struct exec));
600
601 if (BADMAG(HDR))
602 {
603 if (!force)
604 {
605 sprintf(a,"input file %s not in object format",IFILE);
606 fatal(PRG,a);
607 }
608
609 memset(&HDR, '\0', sizeof(struct exec));
610 HDR.a_text = 0x10000L;
611 }
612
613 if (HDR.a_cpu != A_I8086 && !force)
614 {
615 sprintf(a,"%s is not an 8086/8088 object file",IFILE);
616 fatal(PRG,a);
617 }
618
619 if (HDR.a_hdrlen <= A_MINHDR)
620 {
621 HDR.a_trsize = HDR.a_drsize = 0L;
622 HDR.a_tbase = HDR.a_dbase = 0L;
623 /* HDR.a_lnums = HDR.a_toffs = 0L; */
624 }
625
626 reloff = HDR.a_text /* Compute reloc data offset */
627 + HDR.a_data
628 + (long)(HDR.a_hdrlen);
629
630 relnum =
631 (HDR.a_trsize + HDR.a_drsize) / sizeof(struct reloc);
632
633 taboff = reloff /* Compute name table offset */
634 + HDR.a_trsize
635 + HDR.a_drsize;
636
637 tabnum = HDR.a_syms / sizeof(struct nlist);
638
639 if (relnum > MAXSYM)
640 fatal(PRG,"reloc table overflow");
641
642 if (tabnum > MAXSYM)
643 fatal(PRG,"symbol table overflow");
644
645 if (relnum) /* Get reloc data */
646 if (lseek(fd,reloff,0) != reloff)
647 fatal(PRG,"lseek error");
648 else
649 {
650 for (relptr = 0; relptr < relnum; ++relptr)
651 read(fd, (char *) &relo[relptr],sizeof(struct reloc));
652 relptr--;
653 }
654
655 if (tabnum) /* Read in symtab */
656 if (lseek(fd,taboff,0) != taboff)
657 fatal(PRG,"lseek error");
658 else
659 {
660 for (symptr = 0; symptr < tabnum; ++symptr)
661 read(fd, (char *) &symtab[symptr],sizeof(struct nlist));
662 symptr--;
663 }
664
665 close(fd);
666
667 if (freopen(IFILE,"r",stdin) == NULL)
668 {
669 sprintf(a,"can't reopen input file %s",IFILE);
670 fatal(PRG,a);
671 }
672
673 distext();
674
675 disdata();
676
677 disbss();
678
679 exit(0);
680
681 }/* * * * * * * * * * * END OF main() * * * * * * * * * * */
682