1 static char *sccsid
= "@(#) dismain.c, Ver. 2.1 created 00:00:00 87/09/01";
3 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
5 * Copyright (C) 1987 G. M. Harding, all rights reserved *
7 * Permission to copy and redistribute is hereby granted, *
8 * provided full source code, with all copyright notices, *
9 * accompanies any redistribution. *
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). *
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. *
30 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
32 #include "dis.h" /* Disassembler declarations */
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 */
45 #if unix && i8086 && ibmpc /* Set the CPU identifier */
51 _PROTOTYPE(static void usage
, (char *s
));
52 _PROTOTYPE(static void fatal
, (char *s
, char *t
));
53 _PROTOTYPE(static void zdump
, (unsigned long beg
));
54 _PROTOTYPE(static void prolog
, (void));
55 _PROTOTYPE(static void distext
, (void));
56 _PROTOTYPE(static void disdata
, (void));
57 _PROTOTYPE(static void disbss
, (void));
59 _PROTOTYPE(static char *invoker
, (char *s
));
60 _PROTOTYPE(static int objdump
, (char *c
));
61 _PROTOTYPE(static char *getlab
, (int type
));
62 _PROTOTYPE(static void prolog
, (void));
64 /* * * * * * * MISCELLANEOUS UTILITY FUNCTIONS * * * * * * */
70 fprintf(stderr
,"Usage: %s [-o] ifile [ofile]\n",s
);
78 fprintf(stderr
,"\07%s: %s\n",s
,t
);
88 printf("\t.zerow\t%ld\n",(beg
>> 1));
90 printf("\t.byte\t0\n");
112 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
114 * This rather tricky routine supports the disdata() func- *
115 * tion. Its job is to output the code for a sequence of *
116 * data bytes whenever the object buffer is full, or when *
117 * a symbolic label is to be output. However, it must also *
118 * keep track of consecutive zero words so that lengthy *
119 * stretches of null data can be compressed by the use of *
120 * an appropriate assembler pseudo-op. It does this by *
121 * setting and testing a file-wide flag which counts suc- *
122 * cessive full buffers of null data. The function returns *
123 * a logical TRUE value if it outputs anything, logical *
124 * FALSE otherwise. (This enables disdata() to determine *
125 * whether to output a new synthetic label when there is *
126 * no symbol table.) *
128 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
135 {/* * * * * * * * * * START OF objdump() * * * * * * * * * */
140 if (objptr
== OBJMAX
)
142 for (k
= 0; k
< OBJMAX
; ++k
)
156 printf("\t.zerow\t%ld\n",(zcount
>> 1));
169 for (k
= 0; k
< objptr
; ++k
)
171 printf("0x%02.2x",objbuf
[k
]);
172 if (k
< (objptr
- 1))
182 }/* * * * * * * * * * END OF objdump() * * * * * * * * * */
184 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
186 * This routine, called at the beginning of the input *
187 * cycle for each object byte, and before any interpreta- *
188 * tion is attempted, searches the symbol table for any *
189 * symbolic name with a value corresponding to the cur- *
190 * rent PC and a type corresponding to the segment type *
191 * (i.e., text, data, or bss) specified by the function's *
192 * argument. If any such name is found, a pointer to it is *
193 * returned; otherwise, a NULL pointer is returned. *
195 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
200 {/* * * * * * * * * * START OF getlab() * * * * * * * * * */
203 static char b
[32], c
[10];
207 || ((type
== N_DATA
) && ( ! objptr
) && ( ! zcount
)))
210 sprintf(b
,"T%05.5lx:",PC
);
212 sprintf(b
,"D%05.5lx:",PC
);
218 for (k
= 0; k
<= symptr
; ++k
)
219 if ((symtab
[k
].n_value
== PC
)
220 && ((symtab
[k
].n_sclass
& N_SECT
) == type
))
222 sprintf(b
,"%s:\n",getnam(k
));
223 if (objflg
&& (type
!= N_TEXT
))
224 sprintf(c
,"| %05.5lx\n",PC
);
231 }/* * * * * * * * * * * END OF getlab() * * * * * * * * * * */
233 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
235 * This routine performs a preliminary scan of the symbol *
236 * table, before disassembly begins, and outputs declara- *
237 * tions of globals and constants. *
239 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
244 {/* * * * * * * * * * START OF prolog() * * * * * * * * * */
246 register int j
, flag
;
251 for (j
= flag
= 0; j
<= symptr
; ++j
)
252 if ((symtab
[j
].n_sclass
& N_CLASS
) == C_EXT
)
253 if (((symtab
[j
].n_sclass
& N_SECT
) > N_UNDF
)
254 && ((symtab
[j
].n_sclass
& N_SECT
) < N_COMM
))
257 printf("\t.globl\t%s",c
);
263 printf("| Internal global\n");
269 if (symtab
[j
].n_value
)
272 printf("\t.comm\t%s,0x%08.8lx",c
,
275 printf("\t| Internal global\n");
283 for (j
= flag
= 0; j
<= relptr
; ++j
)
284 if (relo
[j
].r_symndx
< S_BSS
)
286 char *c
= getnam(relo
[j
].r_symndx
);
288 printf("\t.globl\t%s",c
);
292 printf("| Undef: %05.5lx\n",relo
[j
].r_vaddr
);
298 for (j
= flag
= 0; j
<= symptr
; ++j
)
299 if ((symtab
[j
].n_sclass
& N_SECT
) == N_ABS
)
302 printf("%s=0x%08.8lx",c
,symtab
[j
].n_value
);
308 printf("| Literal\n");
317 }/* * * * * * * * * * * END OF prolog() * * * * * * * * * * */
319 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
321 * This function is responsible for disassembly of the *
322 * object file's text segment. *
324 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
329 {/* * * * * * * * * * START OF distext() * * * * * * * * * */
333 register void (*f
)();
335 for (j
= 0; j
< (int)(HDR
.a_hdrlen
); ++j
)
338 printf("| %s, %s\n\n",PRG
,release
);
342 printf("#)\tDisassembly of %s",IFILE
);
345 printf(" (no symbols)\n\n");
349 if (HDR
.a_flags
& A_EXEC
)
350 printf("| File is executable\n\n");
352 if (HDR
.a_flags
& A_SEP
)
354 printf("| File has split I/D space, and may have\n");
355 printf("| extraneous instructions in text segment\n\n");
360 printf("\t.text\t\t\t| loc = %05.5lx, size = %05.5lx\n\n",
365 for (PC
= 0L; PC
< HDR
.a_text
; ++PC
)
367 j
= getchar() & 0xff;
368 if ((j
== 0) && ((PC
+ 1L) == HDR
.a_text
))
373 if ((c
= getlab(N_TEXT
)) != NULL
)
379 }/* * * * * * * * * * END OF distext() * * * * * * * * * */
381 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
383 * This function handles the object file's data segment. *
384 * There is no good way to disassemble a data segment, be- *
385 * cause it is impossible to tell, from the object code *
386 * alone, what each data byte refers to. If it refers to *
387 * an external symbol, the reference can be resolved from *
388 * the relocation table, if there is one. However, if it *
389 * refers to a static symbol, it cannot be distinguished *
390 * from numeric, character, or other pointer data. In some *
391 * cases, one might make a semi-educated guess as to the *
392 * nature of the data, but such guesses are inherently *
393 * haphazard, and they are bound to be wrong a good por- *
394 * tion of the time. Consequently, the data segment is *
395 * disassembled as a byte stream, which will satisfy no *
396 * one but which, at least, will never mislead anyone. *
398 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
403 {/* * * * * * * * * * START OF disdata() * * * * * * * * * */
411 if (HDR
.a_flags
& A_SEP
)
417 end
= HDR
.a_text
+ HDR
.a_data
;
419 printf("\t.data\t\t\t| loc = %05.5lx, size = %05.5lx\n\n",
424 for (objptr
= 0, zcount
= 0L; PC
< end
; ++PC
)
426 if ((c
= getlab(N_DATA
)) != NULL
)
431 if (objptr
>= OBJMAX
)
432 if (objdump(NULL
) && (symptr
< 0))
433 printf("D%05.5lx:",PC
);
434 j
= getchar() & 0xff;
435 objbuf
[objptr
++] = j
;
440 }/* * * * * * * * * * END OF disdata() * * * * * * * * * */
442 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
444 * This function handles the object file's bss segment. *
445 * Disassembly of the bss segment is easy, because every- *
446 * thing in it is zero by definition. *
448 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
452 {/* * * * * * * * * * START OF disbss() * * * * * * * * * */
456 unsigned long beg
, end
;
460 if (HDR
.a_flags
& A_SEP
)
461 end
= HDR
.a_data
+ HDR
.a_bss
;
463 end
= HDR
.a_text
+ HDR
.a_data
+ HDR
.a_bss
;
465 printf("\t.bss\t\t\t| loc = %05.5lx, size = %05.5lx\n\n",
470 for (beg
= PC
; PC
< end
; ++PC
)
471 if ((c
= getlab(N_BSS
)) != NULL
)
484 }/* * * * * * * * * * * END OF disbss() * * * * * * * * * * */
486 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
488 * This is the program entry point. The command line is *
489 * searched for an input file name, which must be present. *
490 * An optional output file name is also permitted; if none *
491 * is found, standard output is the default. One command- *
492 * line option is available: "-o", which causes the pro- *
493 * gram to include object code in comments along with its *
496 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
501 int argc
; /* Command-line args from OS */
502 register char **argv
;
504 {/* * * * * * * * * * * START OF main() * * * * * * * * * * */
511 PRG
= invoker(*argv
);
513 while (*++argv
!= NULL
) /* Process command-line args */
529 else if (OFILE
== NULL
)
537 if ((fd
= open(IFILE
,0)) < 0)
539 sprintf(a
,"can't access input file %s",IFILE
);
544 if (freopen(OFILE
,"w",stdout
) == NULL
)
546 sprintf(a
,"can't open output file %s",OFILE
);
551 fprintf(stderr
,"\07%s: warning: host/cpu clash\n",PRG
);
553 read(fd
, (char *) &HDR
,sizeof(struct exec
));
557 sprintf(a
,"input file %s not in object format",IFILE
);
561 if (HDR
.a_cpu
!= A_I8086
)
563 sprintf(a
,"%s is not an 8086/8088 object file",IFILE
);
567 if (HDR
.a_hdrlen
<= A_MINHDR
)
568 HDR
.a_trsize
= HDR
.a_drsize
= 0L;
569 HDR
.a_tbase
= HDR
.a_dbase
= 0L;
570 /* AST emergency patch
571 HDR.a_lnums = HDR.a_toffs = 0L;
574 reloff
= HDR
.a_text
/* Compute reloc data offset */
576 + (long)(HDR
.a_hdrlen
);
579 (HDR
.a_trsize
+ HDR
.a_drsize
) / sizeof(struct reloc
);
581 taboff
= reloff
/* Compute name table offset */
585 tabnum
= HDR
.a_syms
/ sizeof(struct nlist
);
588 fatal(PRG
,"reloc table overflow");
591 fatal(PRG
,"symbol table overflow");
593 if (relnum
) /* Get reloc data */
594 if (lseek(fd
,reloff
,0) != reloff
)
595 fatal(PRG
,"lseek error");
598 for (relptr
= 0; relptr
< relnum
; ++relptr
)
599 read(fd
, (char *) &relo
[relptr
],sizeof(struct reloc
));
603 if (tabnum
) /* Read in symtab */
604 if (lseek(fd
,taboff
,0) != taboff
)
605 fatal(PRG
,"lseek error");
608 for (symptr
= 0; symptr
< tabnum
; ++symptr
)
609 read(fd
, (char *) &symtab
[symptr
],sizeof(struct nlist
));
613 fprintf(stderr
,"\07%s: warning: no symbols\n",PRG
);
617 if (freopen(IFILE
,"r",stdin
) == NULL
)
619 sprintf(a
,"can't reopen input file %s",IFILE
);
631 }/* * * * * * * * * * * END OF main() * * * * * * * * * * */