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