* © 2018 Aaron Taylor <ataylor at subgeniuskitty dot com>
* See LICENSE.txt file for copyright and license details.
#include "../common/a.out.h"
#define WIDTH_MNEMONICS 14
* 10 characters for address in hexadecimal
* 10 characters for hex dump of 32-bit word
* 40 characters for binary representation of 32-bit word
* remainder of line for mnemonics
printf(" Offset || Hex || Binary "
"============================================================"
"============================================================"
"===================\n");
print_usage(char ** argv
)
printf( "NED Disassembler v%d (www.subgeniuskitty.com)\n"
"Usage: %s -i <file> [-l] [-s]\n"
" -h Help (prints this message)\n"
" -i <file> Specify a binary image file to disassemble.\n"
" -s Print summary of information in a.out exec header.\n"
" -l Print labels and organize disassembled code by label.\n"
print_formatA_binary(uint32_t word
)
for (int bit_index
= 30; bit_index
>= 0; bit_index
--) {
/* Insert space every 8 bits. Leading space is intentional. */
if ((chunk_length
++ % 8) == 0) printf(" ");
if ((word
>> bit_index
) & 0b1) {
print_formatA_mnemonics(uint32_t word
)
printf("WORD =====>%n", &position
);
while (position
++ != WIDTH_MNEMONICS
) printf(" ");
printf("0x%x%n", ((word
& 0b01111111111111111111111111111111) << 1), &position
);
while (position
++ != WIDTH_MNEMONICS
) printf(" ");
printf("0%o%n", ((word
& 0b01111111111111111111111111111111) << 1), &position
);
while (position
++ != WIDTH_MNEMONICS
) printf(" ");
printf("%u%n", ((word
& 0b01111111111111111111111111111111) << 1), &position
);
while (position
++ != WIDTH_MNEMONICS
) printf(" ");
extract_syllable_from_word(uint32_t word
, uint8_t index
)
uint32_t mask
= 0b111111 << 6*(4-index
);
return (word
& mask
) >> 6*(4-index
);
print_formatC_binary(uint32_t word
)
for (int syllable_index
= 0; syllable_index
< 5; syllable_index
++) {
uint8_t syllable
= extract_syllable_from_word(word
, syllable_index
);
for (int i
= 5; i
>= 0; i
--) {
if (((syllable
>> i
) & 0b1) == 1) {
print_formatC_mnemonics(uint32_t word
)
for (int syllable_index
= 0; syllable_index
< 5; syllable_index
++) {
uint8_t syllable
= extract_syllable_from_word(word
, syllable_index
);
if (syllable
& 0b100000) { /* Check the first bit of the syllable. 1 means IM_x. */
printf("IM_%d%n", (syllable
& 0b11111), &position
);
} else if (syllable
& 0b10000) { /* 1 in 2nd bit means LDSP+x or STSP+x instruction. */
if (syllable
& 0b1000) { /* LDSP+x */
printf("LDSP+%d%n", (syllable
& 0b111), &position
);
printf("STSP+%d%n", (syllable
& 0b111), &position
);
case AND
: printf("AND%n", &position
); break;
case OR
: printf("OR%n", &position
); break;
case NOT
: printf("NOT%n", &position
); break;
case XOR
: printf("XOR%n", &position
); break;
case ADD
: printf("ADD%n", &position
); break;
case MVSTCK
: printf("MVSTCK%n", &position
); break;
case SHIFT
: printf("SHIFT%n", &position
); break;
case CMPSWP
: printf("CMPSWP%n", &position
); break;
case TEST
: printf("TEST%n", &position
); break;
case BRZ
: printf("BRZ%n", &position
); break;
case LOAD
: printf("LOAD%n", &position
); break;
case STORE
: printf("STORE%n", &position
); break;
case NOP
: printf("NOP%n", &position
); break;
case HALT
: printf("HALT%n", &position
); break;
case JMP
: printf("JMP%n", &position
); break;
case SWAP
: printf("SWAP%n", &position
); break;
default: printf("?ERR?%n", &position
); break;
while (position
++ != WIDTH_MNEMONICS
) printf(" ");
parse_aout_file(FILE * input
, struct exec
* aout_exec
, uint32_t ** text_segment
,
struct nlist
** symbol_table
, uint32_t * symbol_count
)
/* Read in and check the a.out header. */
for (uint32_t i
=0; i
<8; i
++) {
case 0: read_count
= fread(&(aout_exec
->a_midmag
), 4, 1, input
); break;
case 1: read_count
= fread(&(aout_exec
->a_text
), 4, 1, input
); break;
case 2: read_count
= fread(&(aout_exec
->a_data
), 4, 1, input
); break;
case 3: read_count
= fread(&(aout_exec
->a_bss
), 4, 1, input
); break;
case 4: read_count
= fread(&(aout_exec
->a_syms
), 4, 1, input
); break;
case 5: read_count
= fread(&(aout_exec
->a_entry
), 4, 1, input
); break;
case 6: read_count
= fread(&(aout_exec
->a_trsize
), 4, 1, input
); break;
case 7: read_count
= fread(&(aout_exec
->a_drsize
), 4, 1, input
); break;
fprintf(stderr
, "ERROR: Invalid a.out header.\n");
if (N_BADMAG(*aout_exec
)) {
fprintf(stderr
, "ERROR: Invalid magic number in a.out header.\n");
} else if (N_GETMID(*aout_exec
) != MID_NED
) {
fprintf(stderr
, "ERROR: Executable not intended for NED Machine ID.\n");
/* Read in the text segment. */
uint32_t text_segment_size
= (N_DATOFF(*aout_exec
) - N_TXTOFF(*aout_exec
));
*text_segment
= malloc(text_segment_size
+ 4);
(*text_segment
)[0] = text_segment_size
/ 4;
read_count
= fread(&((*text_segment
)[1]), 1, text_segment_size
, input
);
if (read_count
!= text_segment_size
) {
fprintf(stderr
, "ERROR: Failed to read entire text segment.\n");
/* Read in the symbol table. */
*symbol_count
= ((N_STROFF(*aout_exec
) - N_SYMOFF(*aout_exec
)) / 20); /* 20 bytes per symbol. */
*symbol_table
= malloc((*symbol_count
) * sizeof(struct nlist
));
for (uint32_t i
=0; i
< *symbol_count
; i
++) {
for (uint32_t j
=0; j
<5; j
++) {
case 0: read_count
= fread(&((*symbol_table
)[i
].n_un
.n_strx
), 4, 1, input
); break;
case 1: read_count
= fread(&((*symbol_table
)[i
].n_type
), 4, 1, input
); break;
case 2: read_count
= fread(&((*symbol_table
)[i
].n_other
), 4, 1, input
); break;
case 3: read_count
= fread(&((*symbol_table
)[i
].n_desc
), 4, 1, input
); break;
case 4: read_count
= fread(&((*symbol_table
)[i
].n_value
), 4, 1, input
); break;
fprintf(stderr
, "ERROR: Unable to read entire symbol table.\n");
/* Read in the string table and update the symbol table entries with pointers to new strings. */
uint32_t string_table_size
;
read_count
= fread(&string_table_size
, 4, 1, input
);
fprintf(stderr
, "ERROR: Failed to read string table size.\n");
for (uint32_t i
=0; i
< *symbol_count
; i
++) {
if (i
< ((*symbol_count
)-1)) {
len
= ((*symbol_table
)[i
+1].n_un
.n_strx
- (*symbol_table
)[i
].n_un
.n_strx
);
len
= (string_table_size
- (*symbol_table
)[i
].n_un
.n_strx
);
(*symbol_table
)[i
].n_un
.n_name
= malloc(len
);
read_count
= fread((*symbol_table
)[i
].n_un
.n_name
, 1, len
, input
);
fprintf(stderr
, "ERROR: Failed to read a string from the string table.\n");
print_aout_summary(struct exec
* aout_exec
)
" =====================================\n"
" Text Size: 0x%08x bytes\n"
" Data Size: 0x%08x bytes\n"
" BSS Size: 0x%08x bytes\n"
" Symbol Table Size: 0x%08x bytes\n"
" Text Reloc. Size: 0x%08x bytes\n"
" Data Reloc. Size: 0x%08x bytes\n\n\n",
N_GETMAGIC(*aout_exec
), N_GETMID(*aout_exec
), N_GETFLAG(*aout_exec
),
aout_exec
->a_text
, aout_exec
->a_data
, aout_exec
->a_bss
, aout_exec
->a_syms
,
aout_exec
->a_entry
, aout_exec
->a_trsize
, aout_exec
->a_drsize
main(int argc
, char ** argv
)
* Process command line arguments
bool display_summary
= false;
bool display_labels
= false;
while ((c
= getopt(argc
,argv
,"i:hsl")) != -1) {
if ((input
= fopen(optarg
, "r")) == NULL
) {
fprintf(stderr
, "ERROR: %s: %s\n", optarg
, strerror(errno
));
fprintf(stderr
, "ERROR: Must specify a binary image file with -i flag.\n");
struct nlist
* symbol_table
;
parse_aout_file(input
, &aout_exec
, &text_segment
, &symbol_table
, &symbol_count
);
if (display_summary
) print_aout_summary(&aout_exec
);
uint32_t offset
= aout_exec
.a_entry
;
/* Since all NED instructions are one word (4 bytes) wide, read in one word increments. */
while (i
<= text_segment
[0]) {
for (uint32_t i
=0; i
< symbol_count
; i
++) {
if (offset
== symbol_table
[i
].n_value
) {
printf("\n%s:\n", symbol_table
[i
].n_un
.n_name
);
printf("0x%08x", offset
);
if (word
& (0b1 << 31)) { /* Format A instruction word */
print_formatA_binary(word
);
print_formatA_mnemonics(word
);
} else if ((word
& (0b11 << 30)) == 0) { /* Format C instruction word */
print_formatC_binary(word
);
print_formatC_mnemonics(word
);
fprintf(stderr
, "ERROR: Malformed instruction word: %o\n", word
);
offset
+= 4; /* Increment by one word (4 bytes). */