From: Robert Pengelly Date: Wed, 16 Oct 2024 15:00:23 +0000 (+0100) Subject: Link ELKS objects X-Git-Url: https://git.candlhat.org/?a=commitdiff_plain;h=16625dd3719dae95abff59b13127748a64265d80;p=slink.git Link ELKS objects --- diff --git a/Makefile.p32 b/Makefile.p32 index 4f335bc..40bbfc4 100644 --- a/Makefile.p32 +++ b/Makefile.p32 @@ -6,7 +6,7 @@ CC=gcc386 LD=ld386 COPTS=-S -O2 -fno-common -ansi -I. -I./include -I../pdos/pdpclib -I../pdos/src -D__PDOS386__ -D__32BIT__ -D__NOBIVA__ -D__PDOS__ -Wall -Werror -ansi -m32 -pedantic -COBJ=aout.c hashtab.o ld.o lib.o report.o vector.o write7x.o +COBJ=elks.c hashtab.o ld.o lib.o report.o vector.o write7x.o all: clean slink.exe diff --git a/Makefile.pdw b/Makefile.pdw index b61185a..a1bee13 100644 --- a/Makefile.pdw +++ b/Makefile.pdw @@ -6,7 +6,7 @@ CC=gccwin LD=ldwin COPTS=-S -O2 -fno-common -ansi -I. -I./include -I../pdos/pdpclib -I../pdos/src -D__WIN32__ -D__NOBIVA__ -D__PDOS__ -Wall -Werror -ansi -m32 -pedantic -COBJ=aout.c hashtab.o ld.o lib.o report.o vector.o write7x.o +COBJ=elks.c hashtab.o ld.o lib.o report.o vector.o write7x.o all: clean slink.exe diff --git a/Makefile.unix b/Makefile.unix index 1289dc3..e9625c6 100644 --- a/Makefile.unix +++ b/Makefile.unix @@ -9,7 +9,7 @@ VPATH := $(SRCDIR) CC := gcc CFLAGS := -D_FILE_OFFSET_BITS=64 -I$(OBJDIR) -I$(SRCDIR)/include -O2 -Wall -Werror -Wextra -ansi -pedantic -std=c90 -CSRC := aout.c hashtab.c ld.c lib.c report.c vector.c write7x.c +CSRC := elks.c hashtab.c ld.c lib.c report.c vector.c write7x.c ifeq ($(OS), Windows_NT) all: slink.exe diff --git a/Makefile.w32 b/Makefile.w32 index ee7f0f7..f3aaa1c 100644 --- a/Makefile.w32 +++ b/Makefile.w32 @@ -9,7 +9,7 @@ VPATH := $(SRCDIR) CC := gcc CFLAGS := -D_FILE_OFFSET_BITS=64 -I$(OBJDIR) -I$(SRCDIR)/include -O2 -Wall -Werror -Wextra -ansi -pedantic -std=c90 -CSRC := aout.c hashtab.c ld.c lib.c report.c vector.c write7x.c +CSRC := elks.c hashtab.c ld.c lib.c report.c vector.c write7x.c all: slink.exe diff --git a/aout.c b/aout.c deleted file mode 100644 index a1effc9..0000000 --- a/aout.c +++ /dev/null @@ -1,697 +0,0 @@ -/****************************************************************************** - * @file aout.c - *****************************************************************************/ -#include -#include -#include -#include -#include - -#include "aout.h" -#include "ld.h" -#include "lib.h" -#include "report.h" -#include "write7x.h" - -#include - -typedef signed char int8_t; -typedef signed short int16_t; - -#if INT_MAX == 32767 -typedef signed long int32_t; -#else -typedef signed int int32_t; -#endif - -static unsigned long header_size = 0, output_size = 0; -static void *data = 0, *output = 0, *text = 0; - - -struct gr { - - long relocations_count, relocations_max; - struct relocation_info *relocations; - -}; - -static struct gr tgr = { 0, 64, NULL }; -static struct gr dgr = { 0, 64, NULL }; - -static int get_symbol (struct aout_object **obj_out, long *index, const char *name, int quiet) { - - long object_i, symbol_i; - - for (object_i = 0; object_i < state->nb_aout_objs; ++object_i) { - - struct aout_object *obj = state->aout_objs[object_i]; - - for (symbol_i = 0; symbol_i < obj->symtab_count; symbol_i++) { - - struct nlist *sym = &obj->symtab[symbol_i]; - char *symname = obj->strtab + GET_INT32 (sym->n_strx); - - if ((sym->n_type & N_EXT) == 0) { - continue; - } - - if ((sym->n_type & N_TYPE) != N_TEXT && (sym->n_type & N_TYPE) != N_DATA && (sym->n_type & N_TYPE) != N_BSS && (sym->n_type & N_TYPE) != N_ABS) { - continue; - } - - if (strcmp (symname, name) == 0) { - - if (obj_out) { - *obj_out = obj; - } - - if (index) { - *index = symbol_i; - } - - return 0; - - } - - } - - } - - if (!quiet) { - report_at (program_name, 0, REPORT_ERROR, "undefined symbol '%s'", name); - } - - return 1; - -} - -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; - - for (i = 0; i < size; i++) { - p[i] = (number >> (8 * i)) & 0xff; - } - -} - -static long objtextsize = 0, objdatasize = 0, objbsssize = 0; -static unsigned long text_ptr = 0, data_ptr = 0, bss_ptr = 0; - -static void apply_slides (struct aout_object *object) { - - long i; - - for (i = 0; i < object->symtab_count; i++) { - - struct nlist *symbol = &object->symtab[i]; - unsigned long final_slide = 0, n_value = GET_UINT32 (symbol->n_value); - - if ((symbol->n_type & N_TYPE) != N_TEXT && (symbol->n_type & N_TYPE) != N_DATA && (symbol->n_type & N_TYPE) != N_BSS) { - continue; - } - - switch (symbol->n_type & N_TYPE) { - - case N_BSS: - - final_slide += state->text_size; - final_slide += state->data_size; - final_slide += object->bss_slide; - - break; - - case N_DATA: - - final_slide += state->text_size; - final_slide += object->data_slide; - - break; - - case N_TEXT: - - final_slide += object->text_slide; - break; - - } - - n_value += final_slide; - - switch (symbol->n_type & N_TYPE) { - - case N_BSS: - - n_value -= GET_UINT32 (object->header->a_data); - /* fall through */ - - case N_DATA: - - n_value -= GET_UINT32 (object->header->a_text); - break; - - } - - write741_to_byte_array (symbol->n_value, n_value); - - } - - for (i = 0; i < object->trelocs_count; i++) { - - struct relocation_info *rel = &object->trelocs[i]; - - long r_address = GET_INT32 (rel->r_address); - r_address += object->text_slide; - - write741_to_byte_array ((unsigned char *) rel->r_address, r_address); - - } - - for (i = 0; i < object->drelocs_count; i++) { - - struct relocation_info *rel = &object->drelocs[i]; - - long r_address = GET_INT32 (rel->r_address); - r_address += state->text_size + object->data_slide; - - write741_to_byte_array ((unsigned char *) rel->r_address, r_address); - - } - -} - -static void paste (struct aout_object *object) { - - struct i386_aout_exec *header = object->header; - - char *obj_text, *obj_data; - unsigned long obj_text_size, obj_data_size, obj_bss_size; - - object->text_slide = text_ptr; - obj_text = (char *) object->raw + sizeof (*header); - - if (state->impure) { - obj_text_size = GET_UINT32 (header->a_text); - } else { - obj_text_size = ALIGN_UP (GET_UINT32 (header->a_text), SECTION_ALIGNMENT); - } - - memcpy ((char *) text + text_ptr, obj_text, GET_UINT32 (header->a_text)); - text_ptr += obj_text_size; - - object->data_slide = data_ptr; - obj_data = (char *) object->raw + sizeof (*header) + GET_UINT32 (header->a_text); - - if (state->impure) { - obj_data_size = GET_UINT32 (header->a_data); - } else { - obj_data_size = ALIGN_UP (GET_UINT32 (header->a_data), SECTION_ALIGNMENT); - } - - memcpy ((char *) data + data_ptr, obj_data, GET_UINT32 (header->a_data)); - data_ptr += obj_data_size; - - object->bss_slide = bss_ptr; - - if (state->impure) { - obj_bss_size = GET_UINT32 (header->a_bss); - } else { - obj_bss_size = ALIGN_UP (GET_UINT32 (header->a_bss), SECTION_ALIGNMENT); - } - - bss_ptr += obj_bss_size; - -} - -static void undef_collect (struct aout_object *object) { - - long i, val; - - for (i = 0; i < object->symtab_count; i++) { - - struct nlist *sym = &object->symtab[i]; - char *symname = object->strtab + GET_INT32 (sym->n_strx); - - if ((sym->n_type & N_TYPE) != N_UNDF || GET_UINT32 (sym->n_value) == 0) { - continue; - } - - if (get_symbol (NULL, NULL, symname, 1)) { - continue; - } - - sym->n_type = N_BSS | N_EXT; - val = GET_UINT32 (sym->n_value); - - write741_to_byte_array (sym->n_value, state->text_size + state->data_size + state->bss_size); - state->bss_size += val; - - } - -} - -static int add_relocation (struct gr *gr, struct relocation_info *r) { - - if (gr->relocations == NULL) { - - if ((gr->relocations = malloc (gr->relocations_max * sizeof (*r))) == NULL) { - return 1; - } - - } - - if (gr->relocations_count >= gr->relocations_max) { - - void *tmp; - - gr->relocations_max *= 2; - - if ((tmp = realloc (gr->relocations, gr->relocations_max * sizeof (*r))) == NULL) { - return 1; - } - - gr->relocations = tmp; - - } - - gr->relocations[gr->relocations_count] = *r; - gr->relocations_count++; - - return 0; - -} - -static int relocate (struct aout_object *object, struct relocation_info *r, int is_data) { - - struct nlist *symbol; - unsigned char *p; - - unsigned long r_symbolnum = GET_UINT32 (r->r_symbolnum); - long result = 0, symbolnum = 0; - - int far_call = 0, pcrel = 0, ext = 0, length = 0; - - symbolnum = r_symbolnum & 0x7ffffff; - length = (r_symbolnum & (3LU << 29)) >> 29; - - pcrel = (r_symbolnum & (1LU << 28)) >> 28; - ext = (r_symbolnum & (1LU << 31)) >> 31; - - far_call = (r_symbolnum & (1LU << 27)) >> 27; - - if ((is_data && pcrel) || far_call) { - - report_at (program_name, 0, REPORT_ERROR, "unsupported relocation type"); - return 1; - - } - - switch (length) { - - case 0: - - length = 1; - break; - - case 1: - - length = 2; - break; - - case 2: - - length = 4; - break; - - } - - symbol = &object->symtab[symbolnum]; - p = (unsigned char *) output + header_size + GET_INT32 (r->r_address); - - if (ext) { - - char *symname = object->strtab + GET_INT32 (symbol->n_strx); - - struct aout_object *symobj; - long symidx; - - if (!get_symbol (&symobj, &symidx, symname, 0)) { - symbol = &symobj->symtab[symidx]; - } else { - return 1; - } - - } - - if (pcrel) { - result = (long) GET_UINT32 (symbol->n_value) - (GET_INT32 (r->r_address) + length); - } else { - - long r_address; - - if (!ext || (symbol->n_type & N_TYPE) == N_BSS || (symbol->n_type & N_TYPE) == N_DATA || (symbol->n_type & N_TYPE) == N_TEXT) { - - struct relocation_info new_relocation; - - unsigned long r_symbolnum; - long r_address; - - r_symbolnum = GET_UINT32 (r->r_symbolnum) & (3L << 29); - r_address = GET_INT32 (r->r_address); - - if (state->format == LD_FORMAT_IA16_AOUT || state->format == LD_FORMAT_I386_AOUT || ((r_symbolnum >> 28) & 0xff) != N_ABS) { - - 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; - - } - - if (is_data) { - r_address -= state->text_size; - } - - write741_to_byte_array ((unsigned char *) new_relocation.r_address, r_address); - write741_to_byte_array (new_relocation.r_symbolnum, r_symbolnum); - - add_relocation (is_data ? &dgr : &tgr, &new_relocation); - - } - - } - - r_address = GET_INT32 (r->r_address); - - if (length == 4) { - result = *(int32_t *) ((char *) output + header_size + r_address); - } else if (length == 2) { - result = *(int16_t *) ((char *) output + header_size + r_address); - } else if (length == 1) { - result = *(int8_t *) ((char *) output + header_size + r_address); - } - - if (ext) { - - symbolnum = (symbol->n_type & N_TYPE); - - result += GET_UINT32 (symbol->n_value); - result += state->psp; - - } else { - - if ((symbolnum == 6) || (symbolnum == 8)) { - - result -= GET_UINT32 (object->header->a_text); - result += state->text_size; - - } - - if (symbolnum == 4) { - result += objtextsize; - } - - if (symbolnum == 6) { - result += objdatasize; - } - - if (symbolnum == 8) { - - result -= GET_UINT32 (object->header->a_data); - result += state->data_size; - result += objbsssize; - - } - - result += state->psp; - - } - - } - - number_to_chars (p, result, length); - return 0; - -} - -static int glue (struct aout_object *object) { - - long i, err = 0; - - for (i = 0; i < object->trelocs_count; i++) { - - if (relocate (object, &object->trelocs[i], 0)) { - err = 1; - } - - } - - for (i = 0; i < object->drelocs_count; i++) { - - if (relocate (object, &object->drelocs[i], 1)) { - err = 1; - } - - } - - objtextsize += GET_UINT32 (object->header->a_text); - objdatasize += GET_UINT32 (object->header->a_data); - objbsssize += GET_UINT32 (object->header->a_bss); - - return err; - -} - - -static int init_aout_object (void) { - - if (state->format == LD_FORMAT_I386_AOUT) { - header_size = sizeof (struct i386_aout_exec); - } else if (state->format == LD_FORMAT_IA16_AOUT) { - header_size = sizeof (struct ia16_aout_exec); - } - - 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 1; - } - - memset (output, 0, output_size); - - text = (void *) ((char *) output + header_size); - data = (void *) ((char *) text + state->text_size); - - return 0; - -} - -static int write_aout_object (unsigned long a_entry) { - - if (state->format == LD_FORMAT_I386_AOUT) { - - struct i386_aout_exec *aout_hdr = output; - - 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)); - - } else if (state->format == LD_FORMAT_IA16_AOUT) { - - struct ia16_aout_exec *aout_hdr = output; - - aout_hdr->a_magic[0] = 0x01; - aout_hdr->a_magic[1] = 0x03; - - aout_hdr->a_flags = 0x10; - aout_hdr->a_cpu = 0x04; - aout_hdr->a_hdrlen = sizeof (*aout_hdr); - - 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); - write721_to_byte_array (aout_hdr->a_total, (state->text_size + state->data_size) + 0x8000); - - 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_IA16_AOUT || 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]); - } - - for (i = 0; i < state->nb_aout_objs; ++i) { - apply_slides (state->aout_objs[i]); - } - - for (i = 0; i < state->nb_aout_objs; ++i) { - undef_collect (state->aout_objs[i]); - } - - if (!state->impure) { - state->bss_size = ALIGN_UP (state->bss_size, SECTION_ALIGNMENT); - } - - for (i = 0; i < state->nb_aout_objs; ++i) { - - if (glue (state->aout_objs[i])) { - err = 1; - } - - } - - if (err) { - return EXIT_FAILURE; - } - - if (state->format == LD_FORMAT_IA16_AOUT || state->format == LD_FORMAT_I386_AOUT) { - entry = get_entry (); - } - - for (i = 0; i < state->nb_aout_objs; i++) { - - if ((object = state->aout_objs[i]) == NULL) { - return EXIT_FAILURE; - } - - /*if (state->mapfile) { - init_map (object); - }*/ - - free (object->raw); - free (object); - - } - - state->nb_aout_objs = 0; - - /*if (state->mapfile) { - - set_map_sections_size (state->text_size, state->data_size, state->bss_size); - set_map_sections_start (0, state->text_size, state->text_size + state->data_size); - - generate_map (); - - }*/ - - if ((state->ofp = fopen (state->ofile, "wb")) == NULL) { - - report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", state->ofile); - return EXIT_FAILURE; - - } - - if (state->format == LD_FORMAT_BIN || state->format == LD_FORMAT_COM) { - - 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_IA16_AOUT || 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; - - } - - } - - return EXIT_SUCCESS; - -} diff --git a/aout.h b/aout.h index 87d9e4e..a7443bb 100644 --- a/aout.h +++ b/aout.h @@ -4,30 +4,7 @@ #ifndef _AOUT_H #define _AOUT_H -struct ia16_aout_exec { - - unsigned char a_magic[2]; - unsigned char a_flags; - unsigned char a_cpu; - unsigned char a_hdrlen; - unsigned char a_unused; - unsigned char a_version[2]; - - unsigned char a_text[4]; - unsigned char a_data[4]; - unsigned char a_bss[4]; - unsigned char a_entry[4]; - unsigned char a_total[4]; - unsigned char a_syms[4]; - - unsigned char a_trsize[4]; - unsigned char a_drsize[4]; - unsigned char a_trbase[4]; - unsigned char a_drbase[4]; - -}; - -struct i386_aout_exec { +struct aout_exec { unsigned char a_info[4]; unsigned char a_text[4]; @@ -55,18 +32,6 @@ struct relocation_info { #define N_EXT 0x01 -struct nlist { - - unsigned char n_strx[4]; - unsigned char n_type; - - unsigned char n_value[4]; - -}; - -#define OMAGIC 0407 -#define ZMAGIC 0413 - /*struct aout_nlist { unsigned char n_strx[4]; @@ -82,4 +47,7 @@ struct nlist { #define N_TYPE 0x1e int create_executable_from_aout_objects (void); +#define OMAGIC 0407 +#define ZMAGIC 0413 + #endif /* _AOUT_H */ diff --git a/elks.c b/elks.c new file mode 100644 index 0000000..2e1a244 --- /dev/null +++ b/elks.c @@ -0,0 +1,726 @@ +/****************************************************************************** + * @file elks.c + *****************************************************************************/ +#include +#include +#include +#include +#include + +#include "aout.h" +#include "elks.h" +#include "ld.h" +#include "lib.h" +#include "report.h" +#include "write7x.h" + +#include + +typedef signed char int8_t; +typedef signed short int16_t; + +#if INT_MAX == 32767 +typedef signed long int32_t; +#else +typedef signed int int32_t; +#endif + +static unsigned long header_size = 0, output_size = 0; +static void *data = 0, *output = 0, *text = 0; + + +struct gr { + + long relocations_count, relocations_max; + struct elks_relocation_info *relocations; + +}; + +static struct gr tgr = { 0, 64, NULL }; +static struct gr dgr = { 0, 64, NULL }; + +static int get_symbol (struct elks_object **obj_out, long *index, const char *name, int quiet) { + + long object_i, symbol_i; + + for (object_i = 0; object_i < state->nb_elks_objs; ++object_i) { + + struct elks_object *obj = state->elks_objs[object_i]; + + for (symbol_i = 0; symbol_i < obj->symtab_count; symbol_i++) { + + struct elks_nlist *sym = &obj->symtab[symbol_i]; + char *symname = obj->strtab + GET_INT32 (sym->n_strx); + + if ((sym->n_type & N_EXT) == 0) { + continue; + } + + if ((sym->n_type & N_TYPE) != N_TEXT && (sym->n_type & N_TYPE) != N_DATA && (sym->n_type & N_TYPE) != N_BSS && (sym->n_type & N_TYPE) != N_ABS) { + continue; + } + + if (strcmp (symname, name) == 0) { + + if (obj_out) { + *obj_out = obj; + } + + if (index) { + *index = symbol_i; + } + + return 0; + + } + + } + + } + + if (!quiet) { + report_at (program_name, 0, REPORT_ERROR, "undefined symbol '%s'", name); + } + + return 1; + +} + +static unsigned long get_entry (void) { + + struct elks_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; + + for (i = 0; i < size; i++) { + p[i] = (number >> (8 * i)) & 0xff; + } + +} + +static long objtextsize = 0, objdatasize = 0, objbsssize = 0; +static unsigned long text_ptr = 0, data_ptr = 0, bss_ptr = 0; + +static void apply_slides (struct elks_object *object) { + + long i; + + for (i = 0; i < object->symtab_count; i++) { + + struct elks_nlist *symbol = &object->symtab[i]; + unsigned long final_slide = 0, n_value = GET_UINT32 (symbol->n_value); + + if ((symbol->n_type & N_TYPE) != N_TEXT && (symbol->n_type & N_TYPE) != N_DATA && (symbol->n_type & N_TYPE) != N_BSS) { + continue; + } + + switch (symbol->n_type & N_TYPE) { + + case N_BSS: + + final_slide += state->text_size; + final_slide += state->data_size; + final_slide += object->bss_slide; + + break; + + case N_DATA: + + final_slide += state->text_size; + final_slide += object->data_slide; + + break; + + case N_TEXT: + + final_slide += object->text_slide; + break; + + } + + n_value += final_slide; + + switch (symbol->n_type & N_TYPE) { + + case N_BSS: + + n_value -= GET_UINT32 (object->header->a_data); + /* fall through */ + + case N_DATA: + + n_value -= GET_UINT32 (object->header->a_text); + break; + + } + + write741_to_byte_array (symbol->n_value, n_value); + + } + + for (i = 0; i < object->trelocs_count; i++) { + + struct elks_relocation_info *rel = &object->trelocs[i]; + + long r_address = GET_INT32 (rel->r_address); + r_address += object->text_slide; + + write741_to_byte_array ((unsigned char *) rel->r_address, r_address); + + } + + for (i = 0; i < object->drelocs_count; i++) { + + struct elks_relocation_info *rel = &object->drelocs[i]; + + long r_address = GET_INT32 (rel->r_address); + r_address += state->text_size + object->data_slide; + + write741_to_byte_array ((unsigned char *) rel->r_address, r_address); + + } + +} + +static void paste (struct elks_object *object) { + + struct elks_exec *header = object->header; + + char *obj_text, *obj_data; + unsigned long obj_text_size, obj_data_size, obj_bss_size; + + object->text_slide = text_ptr; + obj_text = (char *) object->raw + sizeof (*header); + + if (state->impure) { + obj_text_size = GET_UINT32 (header->a_text); + } else { + obj_text_size = ALIGN_UP (GET_UINT32 (header->a_text), SECTION_ALIGNMENT); + } + + memcpy ((char *) text + text_ptr, obj_text, GET_UINT32 (header->a_text)); + text_ptr += obj_text_size; + + object->data_slide = data_ptr; + obj_data = (char *) object->raw + sizeof (*header) + GET_UINT32 (header->a_text); + + if (state->impure) { + obj_data_size = GET_UINT32 (header->a_data); + } else { + obj_data_size = ALIGN_UP (GET_UINT32 (header->a_data), SECTION_ALIGNMENT); + } + + memcpy ((char *) data + data_ptr, obj_data, GET_UINT32 (header->a_data)); + data_ptr += obj_data_size; + + object->bss_slide = bss_ptr; + + if (state->impure) { + obj_bss_size = GET_UINT32 (header->a_bss); + } else { + obj_bss_size = ALIGN_UP (GET_UINT32 (header->a_bss), SECTION_ALIGNMENT); + } + + bss_ptr += obj_bss_size; + +} + +static void undef_collect (struct elks_object *object) { + + long i, val; + + for (i = 0; i < object->symtab_count; i++) { + + struct elks_nlist *sym = &object->symtab[i]; + char *symname = object->strtab + GET_INT32 (sym->n_strx); + + if ((sym->n_type & N_TYPE) != N_UNDF || GET_UINT32 (sym->n_value) == 0) { + continue; + } + + if (get_symbol (NULL, NULL, symname, 1)) { + continue; + } + + sym->n_type = N_BSS | N_EXT; + val = GET_UINT32 (sym->n_value); + + write741_to_byte_array (sym->n_value, state->text_size + state->data_size + state->bss_size); + state->bss_size += val; + + } + +} + +static int add_relocation (struct gr *gr, struct elks_relocation_info *r) { + + if (gr->relocations == NULL) { + + if ((gr->relocations = malloc (gr->relocations_max * sizeof (*r))) == NULL) { + return 1; + } + + } + + if (gr->relocations_count >= gr->relocations_max) { + + void *tmp; + + gr->relocations_max *= 2; + + if ((tmp = realloc (gr->relocations, gr->relocations_max * sizeof (*r))) == NULL) { + return 1; + } + + gr->relocations = tmp; + + } + + gr->relocations[gr->relocations_count] = *r; + gr->relocations_count++; + + return 0; + +} + +static int relocate (struct elks_object *object, struct elks_relocation_info *r, int is_data) { + + struct elks_nlist *symbol; + unsigned char *p; + + unsigned long r_symbolnum = GET_UINT32 (r->r_symbolnum); + long result = 0, symbolnum = 0; + + int far_call = 0, pcrel = 0, ext = 0, length = 0; + + symbolnum = r_symbolnum & 0x7ffffff; + length = (r_symbolnum & (3LU << 29)) >> 29; + + pcrel = (r_symbolnum & (1LU << 28)) >> 28; + ext = (r_symbolnum & (1LU << 31)) >> 31; + + far_call = (r_symbolnum & (1LU << 27)) >> 27; + + if ((is_data && pcrel) || far_call) { + + report_at (program_name, 0, REPORT_ERROR, "unsupported relocation type"); + return 1; + + } + + switch (length) { + + case 0: + + length = 1; + break; + + case 1: + + length = 2; + break; + + case 2: + + length = 4; + break; + + } + + symbol = &object->symtab[symbolnum]; + p = (unsigned char *) output + header_size + GET_INT32 (r->r_address); + + if (ext) { + + char *symname = object->strtab + GET_INT32 (symbol->n_strx); + + struct elks_object *symobj; + long symidx; + + if (!get_symbol (&symobj, &symidx, symname, 0)) { + symbol = &symobj->symtab[symidx]; + } else { + return 1; + } + + } + + if (pcrel) { + result = (long) GET_UINT32 (symbol->n_value) - (GET_INT32 (r->r_address) + length); + } else { + + long r_address; + + if (!ext || (symbol->n_type & N_TYPE) == N_BSS || (symbol->n_type & N_TYPE) == N_DATA || (symbol->n_type & N_TYPE) == N_TEXT) { + + struct elks_relocation_info new_relocation; + + unsigned long r_symbolnum; + long r_address; + + r_symbolnum = GET_UINT32 (r->r_symbolnum) & (3L << 29); + r_address = GET_INT32 (r->r_address); + + if (state->format == LD_FORMAT_IA16_AOUT || state->format == LD_FORMAT_I386_AOUT || ((r_symbolnum >> 28) & 0xff) != N_ABS) { + + 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; + + } + + if (is_data) { + r_address -= state->text_size; + } + + write741_to_byte_array ((unsigned char *) new_relocation.r_address, r_address); + write741_to_byte_array (new_relocation.r_symbolnum, r_symbolnum); + + add_relocation (is_data ? &dgr : &tgr, &new_relocation); + + } + + } + + r_address = GET_INT32 (r->r_address); + + if (length == 4) { + result = *(int32_t *) ((char *) output + header_size + r_address); + } else if (length == 2) { + result = *(int16_t *) ((char *) output + header_size + r_address); + } else if (length == 1) { + result = *(int8_t *) ((char *) output + header_size + r_address); + } + + if (ext) { + + symbolnum = (symbol->n_type & N_TYPE); + + result += GET_UINT32 (symbol->n_value); + result += state->psp; + + } else { + + if ((symbolnum == 6) || (symbolnum == 8)) { + + result -= GET_UINT32 (object->header->a_text); + result += state->text_size; + + } + + if (symbolnum == 4) { + result += objtextsize; + } + + if (symbolnum == 6) { + result += objdatasize; + } + + if (symbolnum == 8) { + + result -= GET_UINT32 (object->header->a_data); + result += state->data_size; + result += objbsssize; + + } + + result += state->psp; + + } + + } + + number_to_chars (p, result, length); + return 0; + +} + +static int glue (struct elks_object *object) { + + long i, err = 0; + + for (i = 0; i < object->trelocs_count; i++) { + + if (relocate (object, &object->trelocs[i], 0)) { + err = 1; + } + + } + + for (i = 0; i < object->drelocs_count; i++) { + + if (relocate (object, &object->drelocs[i], 1)) { + err = 1; + } + + } + + objtextsize += GET_UINT32 (object->header->a_text); + objdatasize += GET_UINT32 (object->header->a_data); + objbsssize += GET_UINT32 (object->header->a_bss); + + return err; + +} + + +static int init_elks_object (void) { + + if (state->format == LD_FORMAT_I386_AOUT) { + header_size = sizeof (struct aout_exec); + } else if (state->format == LD_FORMAT_IA16_AOUT) { + header_size = sizeof (struct elks_exec); + } + + 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 1; + } + + memset (output, 0, output_size); + + text = (void *) ((char *) output + header_size); + data = (void *) ((char *) text + state->text_size); + + return 0; + +} + +static int write_elks_object (unsigned long a_entry) { + + if (state->format == LD_FORMAT_I386_AOUT) { + + struct aout_exec *header = output; + + write741_to_byte_array (header->a_info, state->impure ? OMAGIC : ZMAGIC); + write741_to_byte_array (header->a_text, state->text_size); + write741_to_byte_array (header->a_data, state->data_size); + write741_to_byte_array (header->a_bss, state->bss_size); + write741_to_byte_array (header->a_entry, a_entry); + write741_to_byte_array (header->a_trsize, tgr.relocations_count * sizeof (struct relocation_info)); + write741_to_byte_array (header->a_drsize, dgr.relocations_count * sizeof (struct relocation_info)); + + } else if (state->format == LD_FORMAT_IA16_AOUT) { + + struct elks_exec *header = output; + + header->a_magic[0] = (ELKS_MAGIC >> 8) & 0xff; + header->a_magic[1] = ELKS_MAGIC & 0xff; + + header->a_flags = 0x10; + header->a_cpu = 0x04; + header->a_hdrlen = sizeof (*header); + + write741_to_byte_array (header->a_text, state->text_size); + write741_to_byte_array (header->a_data, state->data_size); + write741_to_byte_array (header->a_bss, state->bss_size); + write741_to_byte_array (header->a_entry, a_entry); + write721_to_byte_array (header->a_total, (state->text_size + state->data_size) + 0x8000); + + write741_to_byte_array (header->a_trsize, tgr.relocations_count * sizeof (struct elks_relocation_info)); + write741_to_byte_array (header->a_drsize, dgr.relocations_count * sizeof (struct elks_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 (state->format == LD_FORMAT_I386_AOUT) { + + 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; + + } + + } + + } else if (state->format == LD_FORMAT_IA16_AOUT) { + + if (tgr.relocations_count > 0) { + + if (fwrite (tgr.relocations, tgr.relocations_count * sizeof (struct elks_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 elks_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_elks_objects (void) { + + struct elks_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_IA16_AOUT || state->format == LD_FORMAT_I386_AOUT) { + + if (init_elks_object ()) { + + report_at (program_name, 0, REPORT_ERROR, "failed to initialize a.out object"); + return EXIT_FAILURE; + + } + + } + + for (i = 0; i < state->nb_elks_objs; ++i) { + paste (state->elks_objs[i]); + } + + for (i = 0; i < state->nb_elks_objs; ++i) { + apply_slides (state->elks_objs[i]); + } + + for (i = 0; i < state->nb_elks_objs; ++i) { + undef_collect (state->elks_objs[i]); + } + + if (!state->impure) { + state->bss_size = ALIGN_UP (state->bss_size, SECTION_ALIGNMENT); + } + + for (i = 0; i < state->nb_elks_objs; ++i) { + + if (glue (state->elks_objs[i])) { + err = 1; + } + + } + + if (err) { + return EXIT_FAILURE; + } + + if (state->format == LD_FORMAT_IA16_AOUT || state->format == LD_FORMAT_I386_AOUT) { + entry = get_entry (); + } + + for (i = 0; i < state->nb_elks_objs; i++) { + + if ((object = state->elks_objs[i]) == NULL) { + return EXIT_FAILURE; + } + + /*if (state->mapfile) { + init_map (object); + }*/ + + free (object->raw); + free (object); + + } + + state->nb_elks_objs = 0; + + /*if (state->mapfile) { + + set_map_sections_size (state->text_size, state->data_size, state->bss_size); + set_map_sections_start (0, state->text_size, state->text_size + state->data_size); + + generate_map (); + + }*/ + + if ((state->ofp = fopen (state->ofile, "wb")) == NULL) { + + report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", state->ofile); + return EXIT_FAILURE; + + } + + if (state->format == LD_FORMAT_BIN || state->format == LD_FORMAT_COM) { + + 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_IA16_AOUT || state->format == LD_FORMAT_I386_AOUT) { + + if (write_elks_object (entry)) { + + report_at (program_name, 0, REPORT_ERROR, "failed to write a.out object"); + return EXIT_FAILURE; + + } + + } + + return EXIT_SUCCESS; + +} diff --git a/elks.h b/elks.h new file mode 100644 index 0000000..dfbe08f --- /dev/null +++ b/elks.h @@ -0,0 +1,62 @@ +/****************************************************************************** + * @file aout.h + *****************************************************************************/ +#ifndef _ELKS_H +#define _ELKS_H + +struct elks_exec { + + unsigned char a_magic[2]; + unsigned char a_flags; + unsigned char a_cpu; + unsigned char a_hdrlen; + unsigned char a_unused; + unsigned char a_version[2]; + + unsigned char a_text[4]; + unsigned char a_data[4]; + unsigned char a_bss[4]; + unsigned char a_entry[4]; + unsigned char a_total[4]; + unsigned char a_syms[4]; + + unsigned char a_trsize[4]; + unsigned char a_drsize[4]; + unsigned char a_trbase[4]; + unsigned char a_drbase[4]; + +}; + +#define N_UNDF 0x00 +#define N_ABS 0x02 +#define N_TEXT 0x04 +#define N_DATA 0x06 +#define N_BSS 0x08 + +struct elks_relocation_info { + + unsigned char r_address[4]; + unsigned char r_symbolnum[4]; + +}; + +#define N_EXT 0x01 + +struct elks_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_elks_objects (void); + +#define ELKS_MAGIC 0403 + +#endif /* _ELKS_H */ diff --git a/ld.c b/ld.c index cf640e8..5fc9b81 100644 --- a/ld.c +++ b/ld.c @@ -5,7 +5,7 @@ #include #include -#include "aout.h" +#include "elks.h" #include "hashtab.h" #include "ld.h" #include "lib.h" @@ -31,9 +31,9 @@ static void cleanup (void) { } - for (i = 0; i < state->nb_aout_objs; ++i) { + for (i = 0; i < state->nb_elks_objs; ++i) { - struct aout_object *obj = state->aout_objs[i]; + struct elks_object *obj = state->elks_objs[i]; if (obj == NULL) { continue; @@ -68,15 +68,15 @@ static unsigned long conv_dec (char *str, long max) { static struct hashtab hashtab_globals = { 0 }; static struct vector vec_undef = { 0 }; -static int process_aout (void *obj, unsigned long sz, const char *fname, int quiet) { +static int process_elks (void *obj, unsigned long sz, const char *fname, int quiet) { - struct i386_aout_exec *hdr = obj; + struct elks_exec *hdr = obj; - struct aout_object *data_obj; - struct nlist *symtab; + struct elks_object *data_obj; + struct elks_nlist *symtab; - struct relocation_info *trelocs; - struct relocation_info *drelocs; + struct elks_relocation_info *trelocs; + struct elks_relocation_info *drelocs; long symtab_count, trelocs_count, drelocs_count; unsigned long symtab_off, strtab_off, trelocs_off, drelocs_off; @@ -84,7 +84,7 @@ static int process_aout (void *obj, unsigned long sz, const char *fname, int qui char *strtab; long i; - if (!(hdr->a_info[0] == 0x39 && hdr->a_info[1] == 0x01 && hdr->a_info[2] == 0x64 && hdr->a_info[3] == 0x00)) { + if (!(hdr->a_magic[0] == ((ELKS_MAGIC >> 8) & 0xff) && hdr->a_magic[1] == (ELKS_MAGIC & 0xff))) { if (!quiet) { report_at (program_name, 0, REPORT_ERROR, "'%s' is not a valid object", fname); @@ -94,9 +94,9 @@ static int process_aout (void *obj, unsigned long sz, const char *fname, int qui } - for (i = 0; i < state->nb_aout_objs; ++i) { + for (i = 0; i < state->nb_elks_objs; ++i) { - struct aout_object *obj_to_compare = state->aout_objs[i]; + struct elks_object *obj_to_compare = state->elks_objs[i]; if (obj_to_compare->size != sz) { continue; @@ -155,11 +155,11 @@ static int process_aout (void *obj, unsigned long sz, const char *fname, int qui data_obj->drelocs_count = drelocs_count; data_obj->symtab_count = symtab_count; - dynarray_add (&state->aout_objs, &state->nb_aout_objs, data_obj); + dynarray_add (&state->elks_objs, &state->nb_elks_objs, data_obj); for (i = 0; i < symtab_count; ++i) { - struct nlist *sym = &symtab[i]; + struct elks_nlist *sym = &symtab[i]; char *symname = strtab + GET_INT32 (sym->n_strx); if ((sym->n_type & N_TYPE) == N_UNDF) { @@ -284,7 +284,7 @@ static int read_ar_obj (FILE *ar_file, const char *root_fname, unsigned long ind memset (path, 0, len); sprintf (path, "%s(%s)", root_fname, fname); - if (process_aout (obj, sz, path, 1)) { + if (process_elks (obj, sz, path, 1)) { free (obj); return 1; @@ -293,7 +293,7 @@ static int read_ar_obj (FILE *ar_file, const char *root_fname, unsigned long ind } else { - if (process_aout (obj, sz, "", 1)) { + if (process_elks (obj, sz, "", 1)) { free (obj); return 1; @@ -510,13 +510,13 @@ static int process_archive (FILE *ar_file, const char *root_fname) { memset (path, 0, len); sprintf (path, "%s(%s)", root_fname, fname); - if ((err = process_aout (obj, sz, path, 1))) { + if ((err = process_elks (obj, sz, path, 1))) { free (obj); } } else { - if ((err = process_aout (obj, sz, "", 1))) { + if ((err = process_elks (obj, sz, "", 1))) { free (obj); } @@ -609,7 +609,7 @@ static int process_file (const char *fname) { } - if ((err = process_aout (obj, obj_sz, fname, 1))) { + if ((err = process_elks (obj, obj_sz, fname, 1))) { report_at (fname, 0, REPORT_ERROR, "file format not recognized"); free (obj); @@ -677,9 +677,9 @@ int main (int argc, char **argv) { } - if (state->nb_aout_objs > 0) { + if (state->nb_elks_objs > 0) { - if (create_executable_from_aout_objects ()) { + if (create_executable_from_elks_objects ()) { return EXIT_FAILURE; } diff --git a/ld.h b/ld.h index 32ce20c..852066b 100644 --- a/ld.h +++ b/ld.h @@ -6,17 +6,17 @@ #include "aout.h" -struct aout_object { +struct elks_object { const char *filename; void *raw; unsigned long size; - struct i386_aout_exec *header; - struct relocation_info *trelocs, *drelocs; + struct elks_exec *header; + struct elks_relocation_info *trelocs, *drelocs; - struct nlist *symtab; + struct elks_nlist *symtab; char *strtab; long symtab_count, trelocs_count, drelocs_count; @@ -40,8 +40,8 @@ struct ld_state { int format, impure; int psp; - struct aout_object **aout_objs; - long nb_aout_objs; + struct elks_object **elks_objs; + long nb_elks_objs; unsigned long text_size, data_size, bss_size; char *entry;