From: Robert Pengelly Date: Thu, 10 Apr 2025 13:02:48 +0000 (+0100) Subject: Experimental MZ creation support X-Git-Url: https://git.candlhat.org/?a=commitdiff_plain;h=a6bb4a23fd1649eb203278c11b2ac0fe6ea8937d;p=slink.git Experimental MZ creation support --- diff --git a/Makefile.p32 b/Makefile.p32 index c6a6bda..cadf210 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.o coff.o elks.o hashtab.o ld.o lib.o link.o map.o pe.o report.o section.o symbol.o vector.o write7x.o +COBJ=aout.o coff.o elks.o hashtab.o ld.o lib.o link.o map.o mz.o pe.o report.o section.o symbol.o vector.o write7x.o all: clean slink.exe diff --git a/Makefile.pdw b/Makefile.pdw index 6768ad4..41cf2fe 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.o coff.o elks.o hashtab.o ld.o lib.o link.o map.o pe.o report.o section.o symbol.o vector.o write7x.o +COBJ=aout.o coff.o elks.o hashtab.o ld.o lib.o link.o map.o mz.o pe.o report.o section.o symbol.o vector.o write7x.o all: clean slink.exe diff --git a/Makefile.unix b/Makefile.unix index e91df01..48f3b0a 100644 --- a/Makefile.unix +++ b/Makefile.unix @@ -7,7 +7,7 @@ VPATH := $(SRCDIR) CC := gcc CFLAGS := -D_FILE_OFFSET_BITS=64 -O2 -Wall -Werror -Wextra -ansi -pedantic -std=c90 -CSRC := aout.c coff.c elks.c hashtab.c ld.c lib.c link.c map.c pe.c report.c section.c symbol.c vector.c write7x.c +CSRC := aout.c coff.c elks.c hashtab.c ld.c lib.c link.c map.c mz.c pe.c report.c section.c symbol.c vector.c write7x.c ifeq ($(OS), Windows_NT) all: slink.exe diff --git a/Makefile.w32 b/Makefile.w32 index dea27fc..27c237d 100644 --- a/Makefile.w32 +++ b/Makefile.w32 @@ -7,7 +7,7 @@ VPATH := $(SRCDIR) CC := gcc CFLAGS := -D_FILE_OFFSET_BITS=64 -O2 -Wall -Werror -Wextra -ansi -pedantic -std=c90 -CSRC := aout.c coff.c elks.c hashtab.c ld.c lib.c link.c map.c pe.c report.c section.c symbol.c vector.c write7x.c +CSRC := aout.c coff.c elks.c hashtab.c ld.c lib.c link.c map.c mz.c pe.c report.c section.c symbol.c vector.c write7x.c all: slink.exe diff --git a/Makefile.wat b/Makefile.wat index 9e6719d..9119233 100644 --- a/Makefile.wat +++ b/Makefile.wat @@ -4,7 +4,7 @@ SRCDIR ?= $(CURDIR) VPATH := $(SRCDIR) -SRC := aout.c coff.c elks.c hashtab.c ld.c lib.c link.c map.c pe.c report.c section.c symbol.c vector.c write7x.c +SRC := aout.c coff.c elks.c hashtab.c ld.c lib.c link.c map.c mz.c pe.c report.c section.c symbol.c vector.c write7x.c all: slink.exe diff --git a/aout.c b/aout.c index 19b08a4..1427ec5 100644 --- a/aout.c +++ b/aout.c @@ -52,6 +52,8 @@ static void translate_relocation (struct reloc_entry *reloc, struct aout_relocat reloc->symbolnum = r_symbolnum; reloc->offset = r_address; + reloc->n_type = 24; + reloc->n_ext = 27; switch (1U << ((r_symbolnum >> 25) & 3)) { diff --git a/elks.c b/elks.c index f4263db..6db7e50 100644 --- a/elks.c +++ b/elks.c @@ -53,6 +53,8 @@ static void translate_relocation (struct reloc_entry *reloc, struct elks_relocat reloc->symbolnum = r_symbolnum; reloc->offset = r_address; + reloc->n_type = 28; + reloc->n_ext = 31; switch (1U << ((r_symbolnum >> 29) & 3)) { diff --git a/ld.c b/ld.c index 2541ac0..602e4c8 100644 --- a/ld.c +++ b/ld.c @@ -11,6 +11,7 @@ #include "elks.h" #include "ld.h" #include "lib.h" +#include "mz.h" #include "pe.h" #include "report.h" #include "section.h" @@ -226,7 +227,7 @@ int main (int argc, char **argv) { } - if (state->format == LD_FORMAT_I386_AOUT || state->format == LD_FORMAT_I386_ELKS || state->format == LD_FORMAT_IA16_ELKS) { + if (state->format == LD_FORMAT_I386_AOUT || state->format == LD_FORMAT_I386_ELKS || state->format == LD_FORMAT_IA16_ELKS || state->format == LD_FORMAT_MZ) { section_find_or_make (".text"); section_find_or_make (".data"); @@ -310,6 +311,8 @@ int main (int argc, char **argv) { free (data); fclose (fp); + } else if (state->format == LD_FORMAT_MZ) { + mz_write (state->output_filename); } else if (state->format == LD_FORMAT_I386_AOUT) { aout_write (state->output_filename); } else if (state->format == LD_FORMAT_I386_ELKS || state->format == LD_FORMAT_IA16_ELKS) { diff --git a/ld.h b/ld.h index 2a4f36d..fd9d871 100644 --- a/ld.h +++ b/ld.h @@ -28,14 +28,16 @@ struct ld_state { }; #define LD_FORMAT_COM 0x00 -#define LD_FORMAT_BIN 0x01 +#define LD_FORMAT_MZ 0x01 +#define LD_FORMAT_BIN 0x02 -#define LD_FORMAT_IA16_ELKS 0x02 -#define LD_FORMAT_I386_ELKS 0x03 +#define LD_FORMAT_IA16_ELKS 0x03 +#define LD_FORMAT_I386_ELKS 0x04 -#define LD_FORMAT_I386_AOUT 0x04 -#define LD_FORMAT_I386_COFF 0x05 -#define LD_FORMAT_I386_PE 0x06 +#define LD_FORMAT_I386_AOUT 0x05 +#define LD_FORMAT_I386_COFF 0x06 + +#define LD_FORMAT_I386_PE 0x07 extern struct ld_state *state; extern const char *program_name; diff --git a/lib.c b/lib.c index 4a56ca5..fc1976f 100644 --- a/lib.c +++ b/lib.c @@ -159,6 +159,13 @@ static void use_option (const char *cmd_arg, int idx, const char *optarg) { } + if (xstrcasecmp (optarg, "msdos-mz") == 0) { + + state->format = LD_FORMAT_MZ; + break; + + } + if (xstrcasecmp (optarg, "elks-ia16") == 0) { state->format = LD_FORMAT_IA16_ELKS; diff --git a/link.c b/link.c index 313275e..8723bce 100644 --- a/link.c +++ b/link.c @@ -366,16 +366,32 @@ static void reloc_generic (struct section_part *part, struct reloc_entry *rel, s if (state->format == LD_FORMAT_BIN || state->format == LD_FORMAT_COM) { - if (!((rel->symbolnum >> 31) & 1)/* || (symbol->n_type & N_TYPE) == N_BSS || (symbol->n_type & N_TYPE) == N_DATA || (symbol->n_type & N_TYPE) == N_TEXT*/) { + if (!((rel->symbolnum >> rel->n_ext) & 1)/* || (symbol->n_type & N_TYPE) == N_BSS || (symbol->n_type & N_TYPE) == N_DATA || (symbol->n_type & N_TYPE) == N_TEXT*/) { /*report_at (__FILE__, __LINE__, REPORT_FATAL_ERROR, "symbol: %s, %lx", symbol->name, ((rel->symbolnum) >> 28));*/ - if (((rel->symbolnum >> 27) & 1) || (((rel->symbolnum) >> 28) & 0xff) != N_ABS) { + if (((rel->symbolnum >> 27) & 1) || ((rel->symbolnum >> rel->n_type) & 0xff) != N_ABS) { report_at (program_name, 0, REPORT_ERROR, "%s:(%s+%#lu): segment relocation", part->of->filename, part->section->name, offset); } } + } else if (state->format == LD_FORMAT_MZ) { + + if (((rel->symbolnum >> rel->n_type) & 0xff) == N_ABS) { + + if (rel->howto == &reloc_howtos[RELOC_TYPE_64]) { + rel->howto = &reloc_howtos[RELOC_TYPE_PC64]; + } else if (rel->howto == &reloc_howtos[RELOC_TYPE_32]) { + rel->howto = &reloc_howtos[RELOC_TYPE_PC32]; + } else if (rel->howto == &reloc_howtos[RELOC_TYPE_16]) { + rel->howto = &reloc_howtos[RELOC_TYPE_PC16]; + } else if (rel->howto == &reloc_howtos[RELOC_TYPE_8]) { + rel->howto = &reloc_howtos[RELOC_TYPE_PC8]; + } + + } + } if (xstrcasecmp (symbol->name, "__etext") == 0 || xstrcasecmp (symbol->name, "__edata") == 0 || xstrcasecmp (symbol->name, "__end") == 0) { diff --git a/mz.c b/mz.c new file mode 100644 index 0000000..0a943c7 --- /dev/null +++ b/mz.c @@ -0,0 +1,201 @@ +/****************************************************************************** + * @file mz.c + *****************************************************************************/ +#include +#include +#include + +#include "ld.h" +#include "lib.h" +#include "mz.h" +#include "report.h" +#include "section.h" +#include "symbol.h" +#include "write7x.h" + +static unsigned long section_get_num_relocs (struct section *section) { + + unsigned long num_relocs = 0, i; + + struct section_part *part; + struct reloc_howto *howto; + + for (part = section->first_part; part; part = part->next) { + + for (i = 0; i < part->reloc_cnt; i++) { + + howto = part->reloc_arr[i].howto; + + if (howto == &reloc_howtos[RELOC_TYPE_32] || howto == &reloc_howtos[RELOC_TYPE_16] || howto == &reloc_howtos[RELOC_TYPE_8]) { + num_relocs++; + } + + } + + } + + return num_relocs; + +} + +static unsigned char *write_relocs_for_section (unsigned char *pos, struct section *section) { + + struct section_part *part; + unsigned long i, addr; + + for (part = section->first_part; part; part = part->next) { + + for (i = 0; i < part->reloc_cnt; i++) { + + if (part->reloc_arr[i].howto == &reloc_howtos[RELOC_TYPE_8] || part->reloc_arr[i].howto == &reloc_howtos[RELOC_TYPE_16] || part->reloc_arr[i].howto == &reloc_howtos[RELOC_TYPE_32]) { + + addr = part->rva + part->reloc_arr[i].offset; + + integer_to_array (addr % 16, pos, 2); + pos += 2; + + integer_to_array (addr / 16, pos, 2); + pos += 2; + + } + + } + + } + + return pos; + +} + +void mz_write (const char *filename) { + + FILE *fp; + + unsigned char *data, *pos; + unsigned long data_size; + + struct section *text_section, *data_section, *bss_section; + unsigned long header_size; + + unsigned long reloc_size = 0, reloc_count = 0; + unsigned long ibss_addr = 0, ibss_size = 0; + unsigned long stack_addr = 0, stack_size = 0; + + struct mz_exec exec; + memset (&exec, 0, sizeof (exec)); + + if (!(fp = fopen (filename, "wb"))) { + + report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", filename); + return; + + } + + text_section = section_find (".text"); + data_section = section_find (".data"); + bss_section = section_find (".bss"); + + if (text_section) { + reloc_count += section_get_num_relocs (text_section); + } + + if (data_section) { + reloc_count += section_get_num_relocs (data_section); + } + + reloc_size = ALIGN (reloc_count * 4, 32); + header_size = ALIGN (sizeof (exec), 16); + + if (data_section) { + + ibss_addr += data_section->rva; + + if (bss_section) { + ibss_addr += bss_section->rva - data_section->rva; + } else { + ibss_addr += data_section->total_size; + } + + } else { + + if (bss_section) { + ibss_addr += bss_section->rva; + } else { + ibss_addr += text_section ? text_section->total_size : 0; + } + + } + + ibss_addr = ibss_addr + reloc_size; + + if (bss_section) { + ibss_size = bss_section->total_size; + } + + stack_addr = ibss_addr + ibss_size; + stack_size = 0x1000; /* Maybe get this from command line in future. */ + + exec.e_magic[0] = 'M'; + exec.e_magic[1] = 'Z'; + + write721_to_byte_array (exec.e_cblp, (ibss_addr % 512)); + write721_to_byte_array (exec.e_cp, ALIGN (ibss_addr, 512) / 512); + + write721_to_byte_array (exec.e_crlc, reloc_count); + write721_to_byte_array (exec.e_cparhdr, (header_size + reloc_size) / 16); + + write721_to_byte_array (exec.e_minalloc, (ALIGN (ibss_size + stack_size, 16) / 16)); + write721_to_byte_array (exec.e_maxalloc, 0xFFFF); + + write721_to_byte_array (exec.e_ss, (stack_addr / 16)); + write721_to_byte_array (exec.e_sp, ALIGN (stack_addr % 16 + stack_size, 16)); + + write721_to_byte_array (exec.e_ip, state->entry_point % 16); + write721_to_byte_array (exec.e_cs, state->entry_point / 16); + + write721_to_byte_array (exec.e_lfarlc, header_size); + + data_size = header_size + reloc_size; + + if (text_section) { + data_size += text_section->total_size; + } + + if (data_section) { + data_size += data_section->total_size; + } + + data = xmalloc (data_size); + memcpy (data, &exec, sizeof (exec)); + + pos = data + header_size; + + if (text_section) { + pos = write_relocs_for_section (pos, text_section); + } + + if (data_section) { + pos = write_relocs_for_section (pos, data_section); + } + + pos = data + header_size + reloc_size; + + if (text_section) { + + section_write (text_section, pos); + pos += text_section->total_size; + + } + + if (data_section) { + section_write (data_section, pos); + } + + if (fwrite (data, data_size, 1, fp) != 1) { + report_at (program_name, 0, REPORT_ERROR, "failed to write data to '%s'", filename); + } + + free (data); + fclose (fp); + +} diff --git a/mz.h b/mz.h new file mode 100644 index 0000000..309a10b --- /dev/null +++ b/mz.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * @file pe.h + *****************************************************************************/ +#ifndef _MZ_H +#define _MZ_H + +#define DEFAULT_SECTION_ALIGNMENT 0x1000 +#define DEFAULT_FILE_ALIGNMENT 0x0200 + +struct mz_exec { + + unsigned char e_magic[2]; /* Magic number */ + unsigned char e_cblp[2]; /* Bytes on last page of file */ + unsigned char e_cp[2]; /* Pages in file */ + unsigned char e_crlc[2]; /* Relocations */ + unsigned char e_cparhdr[2]; /* Size of header in paragraphs */ + unsigned char e_minalloc[2]; /* Minimum extra paragraphs needed */ + unsigned char e_maxalloc[2]; /* Maximum extra paragraphs needed */ + unsigned char e_ss[2]; /* Initial (relative) SS value */ + unsigned char e_sp[2]; /* Initial SP value */ + unsigned char e_csum[2]; /* Checksum */ + unsigned char e_ip[2]; /* Initial IP value */ + unsigned char e_cs[2]; /* Initial (relative) CS value */ + unsigned char e_lfarlc[2]; /* File address of relocation table */ + unsigned char e_ovno[2]; /* Overlay number */ + +}; + +void mz_write (const char *filename); + +#endif /* _MZ_H */ diff --git a/pe.h b/pe.h index f195e55..f209942 100644 --- a/pe.h +++ b/pe.h @@ -4,8 +4,8 @@ #ifndef _PE_H #define _PE_H -#define DEFAULT_SECTION_ALIGNMENT 0x1000 -#define DEFAULT_FILE_ALIGNMENT 0x0200 +#define DEFAULT_SECTION_ALIGNMENT 0x1000 +#define DEFAULT_FILE_ALIGNMENT 0x0200 struct msdos_header { diff --git a/reloc.h b/reloc.h index 8aa26e9..4c5edd0 100644 --- a/reloc.h +++ b/reloc.h @@ -49,7 +49,9 @@ struct reloc_entry { unsigned long offset; unsigned long addend; + unsigned int n_type, n_ext; unsigned long symbolnum; + struct reloc_howto *howto; };