Experimental MZ creation support
authorRobert Pengelly <robertapengelly@hotmail.com>
Thu, 10 Apr 2025 13:02:48 +0000 (14:02 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Thu, 10 Apr 2025 13:02:48 +0000 (14:02 +0100)
15 files changed:
Makefile.p32
Makefile.pdw
Makefile.unix
Makefile.w32
Makefile.wat
aout.c
elks.c
ld.c
ld.h
lib.c
link.c
mz.c [new file with mode: 0644]
mz.h [new file with mode: 0644]
pe.h
reloc.h

index c6a6bda0b8414a8973097a33db3e7948f4841958..cadf210525fa3491a93b4d9ce6ae466d23a76ac3 100644 (file)
@@ -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
 
index 6768ad47588833aeb39408d5e237bf6859fe2447..41cf2fe564bc1d61e9a57fb8f3e88c5d99a4c485 100644 (file)
@@ -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
 
index e91df018dd3102d2a5c79a920c40e8d156dde2f2..48f3b0ad5a8972cb9f84e78fdf42b8db90e85091 100644 (file)
@@ -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
index dea27fc90eba92f1ddc3533c42ac94e842d340ed..27c237d58004dcecddd3bdd8ec11981768aca4d7 100644 (file)
@@ -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
 
index 9e6719de1ad6bfa112dd2d13764d3c350c8e7e90..9119233460eb6f5b52e198d4c8ecc3d01cca18d9 100644 (file)
@@ -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 19b08a4c14fc417907d8934a17c6db7b03233a79..1427ec5f9b85fe5cc06bc58be35f7d0c0b224fba 100644 (file)
--- 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 f4263db1f23af01cc740401ad5e5c14e78ba003b..6db7e50b6c396d3516d2e72dbee29b5242f5ab33 100644 (file)
--- 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 2541ac01d6e89cf8db70a5f48f9f476c5530eb92..602e4c8f12664e452ef6d5a1f64dd7076968edf1 100644 (file)
--- 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 2a4f36d83aad4f5f9c44e156911539a36ae0962d..fd9d8719364fd4745082d2b1333d1d42ca19e8c7 100644 (file)
--- 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 4a56ca5c43824eee0f7c41593da963fa98de796e..fc1976fef3ff6b8e38dceb3431329c142454b8f8 100644 (file)
--- 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 313275e4205c49a5893d052ac7d257c977d8a070..8723bcefa7dfa993e693b6eaece2012a4a4445e2 100644 (file)
--- 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 (file)
index 0000000..0a943c7
--- /dev/null
+++ b/mz.c
@@ -0,0 +1,201 @@
+/******************************************************************************
+ * @file            mz.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#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 (file)
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 f195e55bb8ce2b584bb5edc1db825a30ba4c83e6..f20994259b07ab278dd2a8371c51835f7365b545 100644 (file)
--- 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 8aa26e91e7a457f3df7827e9d1ff5bd74ed6e571..4c5edd095df07ed615483c089e094e165ab8b43f 100644 (file)
--- 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;
 
 };