+/*
+ * © 2021 Aaron Taylor <ataylor at subgeniuskitty dot com>
+ * See LICENSE.txt file for copyright and license details.
+ */
+
+/*
+ * This program dumps the text segment of a NED1 a.out format executable as a
+ * binary blob.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "../common/a.out.h"
+
+#define VERSION 1
+
+void
+print_usage(char ** argv)
+{
+ printf( "NED objdump v%d (www.subgeniuskitty.com)\n"
+ "Usage: %s -i <file> -o <file>\n"
+ " -h Help (prints this message)\n"
+ " -i <file> Specify NED a.out format input file.\n"
+ " -o <file> Specify output filename for binary blob.\n"
+ , VERSION, argv[0]
+ );
+}
+
+void
+die(FILE * in, FILE * out, const char * msg)
+{
+ fclose(in);
+ fclose(out);
+ fprintf(stderr, "%s\n", msg);
+ exit(EXIT_FAILURE);
+}
+
+void
+dump_aout_file(FILE * in_file, FILE * out_file)
+{
+ uint32_t read_count = 0;
+ struct exec aout_exec;
+
+ /* Read in and check the a.out header. */
+ for (uint32_t i=0; i<8; i++) {
+ switch (i) {
+ case 0: read_count = fread(&(aout_exec.a_midmag), 4, 1, in_file); break;
+ case 1: read_count = fread(&(aout_exec.a_text), 4, 1, in_file); break;
+ case 2: read_count = fread(&(aout_exec.a_data), 4, 1, in_file); break;
+ case 3: read_count = fread(&(aout_exec.a_bss), 4, 1, in_file); break;
+ case 4: read_count = fread(&(aout_exec.a_syms), 4, 1, in_file); break;
+ case 5: read_count = fread(&(aout_exec.a_entry), 4, 1, in_file); break;
+ case 6: read_count = fread(&(aout_exec.a_trsize), 4, 1, in_file); break;
+ case 7: read_count = fread(&(aout_exec.a_drsize), 4, 1, in_file); break;
+ }
+ if (read_count != 1) {
+ die(in_file, out_file, "ERROR: Invalid a.out header.");
+ }
+ }
+ if (N_BADMAG(aout_exec)) {
+ die(in_file, out_file, "ERROR: Invalid magic number in a.out header.");
+ } else if (N_GETMID(aout_exec) != MID_NED) {
+ die(in_file, out_file, "ERROR: Executable not intended for NED Machine ID.");
+ }
+
+ /* Read in the text segment. */
+ uint32_t text_segment_size = (N_DATOFF(aout_exec) - N_TXTOFF(aout_exec));
+ uint8_t * text_segment = malloc(text_segment_size);
+ read_count = fread(text_segment, 1, text_segment_size, in_file);
+ if (read_count != text_segment_size) {
+ die(in_file, out_file, "ERROR: Failed to read entire text segment.");
+ }
+
+ /* Correct the byte order. */
+ for (uint32_t i=0; i < (text_segment_size / 4); i++) {
+ uint8_t temp_word[4];
+ for (uint8_t j=0; j<4; j++) temp_word[j] = text_segment[((i*4)+j)];
+ for (uint8_t j=0; j<4; j++) text_segment[((i*4)+j)] = temp_word[(3-j)];
+ }
+
+ /* Write text segment to file. */
+ uint32_t write_count = fwrite(text_segment, text_segment_size, 1, out_file);
+ if (write_count != 1) {
+ die(in_file, out_file, "ERROR: Unable to write to output file.");
+ }
+
+ /* Clean up and return */
+ free(text_segment);
+}
+
+int
+main(int argc, char ** argv)
+{
+ /*
+ * Process command line arguments
+ */
+ int c;
+ FILE * in_file = NULL;
+ FILE * out_file = NULL;
+ while ((c = getopt(argc, argv, "hi:o:")) != -1) {
+ switch (c) {
+ case 'i':
+ if ((in_file = fopen(optarg, "r")) == NULL) {
+ fprintf(stderr, "ERROR: %s: %s\n", optarg, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'o':
+ if ((out_file = fopen(optarg, "wx")) == NULL) {
+ fprintf(stderr, "ERROR: %s: %s\n", optarg, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 'h':
+ print_usage(argv);
+ exit(EXIT_SUCCESS);
+ break;
+ default:
+ print_usage(argv);
+ exit(EXIT_FAILURE);
+ break;
+ }
+ }
+ if (in_file == NULL) {
+ fprintf(stderr, "ERROR: Must specify NED1 a.out format file with -i flag.\n");
+ print_usage(argv);
+ exit(EXIT_FAILURE);
+ }
+ if (out_file == NULL) {
+ fprintf(stderr, "ERROR: Must specify destination file with -o flag.\n");
+ print_usage(argv);
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Perform the conversion
+ */
+ dump_aout_file(in_file, out_file);
+
+ /*
+ * Clean up and terminate
+ */
+ fclose(in_file);
+ fclose(out_file);
+ exit(EXIT_SUCCESS);
+}