From 0cb3d3cac3c3f4efe8c3f312643767f76f564c34 Mon Sep 17 00:00:00 2001 From: Robert Pengelly Date: Sat, 8 Jun 2024 18:07:30 +0100 Subject: [PATCH] Create a.out executables --- aout.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- aout.h | 15 ++++++ ld.c | 8 +++- ld.h | 6 ++- lib.c | 41 ++++++++++++---- 5 files changed, 189 insertions(+), 27 deletions(-) diff --git a/aout.c b/aout.c index c2d6e91..27cf88d 100644 --- a/aout.c +++ b/aout.c @@ -27,6 +27,8 @@ typedef signed int int32_t; static unsigned long header_size = 0, output_size = 0; static void *data = 0, *output = 0, *text = 0; +static struct aout_exec *aout_hdr; + struct gr { @@ -85,6 +87,22 @@ static int get_symbol (struct aout_object **obj_out, long *index, const char *na } +static unsigned long get_entry (void) { + + struct aout_object *symobj; + long symidx; + + if (get_symbol (&symobj, &symidx, state->entry, 1)) { + + report_at (program_name, 0, REPORT_WARNING, "cannot find entry symbol %s; defaulting to 00000000", state->entry); + return 0; + + } + + return GET_UINT32 (symobj->symtab[symidx].n_value); + +} + static void number_to_chars (unsigned char *p, unsigned long number, unsigned long size) { unsigned long i; @@ -358,9 +376,9 @@ static int relocate (struct aout_object *object, struct relocation_info *r, int r_symbolnum = GET_UINT32 (r->r_symbolnum) & (3L << 29); r_address = GET_INT32 (r->r_address); - if (((r_symbolnum >> 28) & 0xff) != N_ABS) { + if (/*state->format == LD_FORMAT_I386_AOUT || */((r_symbolnum >> 28) & 0xff) != N_ABS) { - if (state->format == LD_OUTPUT_BIN || state->format == LD_OUTPUT_COM) { + if (state->format == LD_FORMAT_BIN || state->format == LD_FORMAT_COM) { report_at (object->filename, 0, REPORT_ERROR, "segment relocation at %04x:%04x", r_address / 0xffff, r_address % 0xffff); return 1; @@ -462,23 +480,106 @@ static int glue (struct aout_object *object) { } -int create_executable_from_aout_objects (void) { +static int init_aout_object (void) { - struct aout_object *object; - long i; + header_size = sizeof (*aout_hdr); - int err = 0; - output_size = state->text_size + state->data_size; + if (!state->impure) { + header_size = ALIGN_UP (header_size, SECTION_ALIGNMENT); + } + + output_size = header_size + state->text_size + state->data_size; if ((output = malloc (output_size)) == NULL) { - return EXIT_FAILURE; + return 1; } memset (output, 0, output_size); + aout_hdr = output; - text = (void *) (char *) output; + text = (void *) ((char *) output + header_size); data = (void *) ((char *) text + state->text_size); + return 0; + +} + +static int write_aout_object (unsigned long a_entry) { + + write741_to_byte_array (aout_hdr->a_info, state->impure ? OMAGIC : ZMAGIC); + write741_to_byte_array (aout_hdr->a_text, state->text_size); + write741_to_byte_array (aout_hdr->a_data, state->data_size); + write741_to_byte_array (aout_hdr->a_bss, state->bss_size); + write741_to_byte_array (aout_hdr->a_entry, a_entry); + write741_to_byte_array (aout_hdr->a_trsize, tgr.relocations_count * sizeof (struct relocation_info)); + write741_to_byte_array (aout_hdr->a_drsize, dgr.relocations_count * sizeof (struct relocation_info)); + + if (fwrite ((char *) output, output_size, 1, state->ofp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed to write data to '%s'", state->ofile); + return 1; + + } + + if (tgr.relocations_count > 0) { + + if (fwrite (tgr.relocations, tgr.relocations_count * sizeof (struct relocation_info), 1, state->ofp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed to write text relocations to '%s'", state->ofile); + return 1; + + } + + } + + if (dgr.relocations_count > 0) { + + if (fwrite (dgr.relocations, dgr.relocations_count * sizeof (struct relocation_info), 1, state->ofp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed to write data relocations to '%s'", state->ofile); + return 1; + + } + + } + + return 0; + +} + + +int create_executable_from_aout_objects (void) { + + struct aout_object *object; + long i; + + unsigned long entry = 0; + int err = 0; + + if (state->format == LD_FORMAT_BIN || state->format == LD_FORMAT_COM) { + + output_size = state->text_size + state->data_size; + + if ((output = malloc (output_size)) == NULL) { + return EXIT_FAILURE; + } + + memset (output, 0, output_size); + + text = (void *) (char *) output; + data = (void *) ((char *) text + state->text_size); + + } else if (state->format == LD_FORMAT_I386_AOUT) { + + if (init_aout_object ()) { + + report_at (program_name, 0, REPORT_ERROR, "failed to initialize a.out object"); + return EXIT_FAILURE; + + } + + } + for (i = 0; i < state->nb_aout_objs; ++i) { paste (state->aout_objs[i]); } @@ -503,7 +604,13 @@ int create_executable_from_aout_objects (void) { } - if (err) { return EXIT_FAILURE; } + if (err) { + return EXIT_FAILURE; + } + + if (state->format == LD_FORMAT_I386_AOUT) { + entry = get_entry (); + } for (i = 0; i < state->nb_aout_objs; i++) { @@ -538,10 +645,23 @@ int create_executable_from_aout_objects (void) { } - if (fwrite ((char *) output, output_size, 1, state->ofp) != 1) { + if (state->format == LD_FORMAT_BIN || state->format == LD_FORMAT_COM) { - report_at (program_name, 0, REPORT_ERROR, "failed to write data to '%s'", state->ofile); - return EXIT_FAILURE; + if (fwrite ((char *) output, output_size, 1, state->ofp) != 1) { + + report_at (program_name, 0, REPORT_ERROR, "failed to write data to '%s'", state->ofile); + return EXIT_FAILURE; + + } + + } else if (state->format == LD_FORMAT_I386_AOUT) { + + if (write_aout_object (entry)) { + + report_at (program_name, 0, REPORT_ERROR, "failed to write a.out object"); + return EXIT_FAILURE; + + } } diff --git a/aout.h b/aout.h index 885ff80..e30be07 100644 --- a/aout.h +++ b/aout.h @@ -41,6 +41,21 @@ struct nlist { }; +#define OMAGIC 0407 +#define ZMAGIC 0413 + +/*struct aout_nlist { + + unsigned char n_strx[4]; + unsigned char n_type; + + unsigned char n_other; + unsigned char n_desc[2]; + + unsigned char n_value[4]; + +};*/ + #define N_TYPE 0x1e int create_executable_from_aout_objects (void); diff --git a/ld.c b/ld.c index 76eaa15..f9612a5 100644 --- a/ld.c +++ b/ld.c @@ -651,13 +651,17 @@ int main (int argc, char **argv) { } + if (!state->entry || strcmp (state->entry, "") == 0) { + state->entry = "_start"; + } + if (!state->ofile) { state->ofile = xstrdup ("a.out"); } - if (state->format == LD_OUTPUT_BIN || state->format == LD_OUTPUT_COM) { + if (state->format == LD_FORMAT_BIN || state->format == LD_FORMAT_COM) { - if (state->format == LD_OUTPUT_COM) { + if (state->format == LD_FORMAT_COM) { state->psp = 0x100; } diff --git a/ld.h b/ld.h index 741a068..5c1f393 100644 --- a/ld.h +++ b/ld.h @@ -44,11 +44,13 @@ struct ld_state { long nb_aout_objs; unsigned long text_size, data_size, bss_size; + char *entry; }; -#define LD_OUTPUT_COM 0x00 -#define LD_OUTPUT_BIN 0x01 +#define LD_FORMAT_COM 0x00 +#define LD_FORMAT_BIN 0x01 +#define LD_FORMAT_I386_AOUT 0x02 extern struct ld_state *state; extern const char *program_name; diff --git a/lib.c b/lib.c index 07fb4f6..f92ad15 100644 --- a/lib.c +++ b/lib.c @@ -27,14 +27,17 @@ struct ld_option { #define LD_OPTION_HAS_ARG 1 #define LD_OPTION_NONE 0 -#define LD_OPTION_FORMAT 1 -#define LD_OPTION_HELP 2 -#define LD_OPTION_IMPURE 3 -#define LD_OPTION_MAP 4 -#define LD_OPTION_OUTFILE 5 +#define LD_OPTION_ENTRY 1 +#define LD_OPTION_FORMAT 2 +#define LD_OPTION_HELP 3 +#define LD_OPTION_IMPURE 4 +#define LD_OPTION_MAP 5 +#define LD_OPTION_OUTFILE 6 static struct ld_option opts[] = { + { "-N", LD_OPTION_IMPURE, LD_OPTION_NO_ARG }, + { "-e", LD_OPTION_ENTRY, LD_OPTION_HAS_ARG }, { "-o", LD_OPTION_OUTFILE, LD_OPTION_HAS_ARG }, { "--oformat", LD_OPTION_FORMAT, LD_OPTION_HAS_ARG }, @@ -53,13 +56,13 @@ static void print_usage (void) { fprintf (stderr, "Options:\n\n"); fprintf (stderr, " -N Do not page align data.\n"); - /*fprintf (stderr, " -T OFFSET Offset addresses by the specified offset\n");*/ + /*fprintf (stderr, " -T OFFSET Offset addresses by the specified offset.\n");*/ fprintf (stderr, " --oformat FORMAT Specify the format of output file (default msdos)\n"); fprintf (stderr, " Supported formats are:\n"); - fprintf (stderr, " binary, msdos\n"); + fprintf (stderr, " a.out-i386, binary, msdos\n"); - /*fprintf (stderr, " -e ADDRESS Set start address.\n");*/ + fprintf (stderr, " -e ADDRESS Set start address.\n"); fprintf (stderr, " -s Ignored.\n"); fprintf (stderr, " -o FILE Set output file name (default a.out).\n"); @@ -219,18 +222,36 @@ void parse_args (int argc, char **argv, int optind) { switch (popt->idx) { + case LD_OPTION_ENTRY: { + + if (state->entry) { + free (state->entry); + } + + state->entry = xstrdup (optarg); + break; + + } + case LD_OPTION_FORMAT: { if (xstrcasecmp (optarg, "binary") == 0) { - state->format = LD_OUTPUT_BIN; + state->format = LD_FORMAT_BIN; break; } if (xstrcasecmp (optarg, "msdos") == 0) { - state->format = LD_OUTPUT_COM; + state->format = LD_FORMAT_COM; + break; + + } + + if (xstrcasecmp (optarg, "a.out-i386") == 0) { + + state->format = LD_FORMAT_I386_AOUT; break; } -- 2.34.1