Initial OMF object support
authorRobert Pengelly <robertapengelly@hotmail.com>
Tue, 29 Apr 2025 22:27:35 +0000 (23:27 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Tue, 29 Apr 2025 22:27:35 +0000 (23:27 +0100)
Makefile.p32
Makefile.pdw
Makefile.std
Makefile.unix
Makefile.w32
elks.h
ld.c
omf.c [new file with mode: 0644]
omf.h [new file with mode: 0644]

index cadf210525fa3491a93b4d9ce6ae466d23a76ac3..91479e4763f40f8679d85cf6652355ebd91dd322 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 mz.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 omf.o pe.o report.o section.o symbol.o vector.o write7x.o
 
 all: clean slink.exe
 
index 41cf2fe564bc1d61e9a57fb8f3e88c5d99a4c485..0799d40192736687855489b02a816e7949204e6d 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 mz.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 omf.o pe.o report.o section.o symbol.o vector.o write7x.o
 
 all: clean slink.exe
 
index 6a670ccf81352e573bf10aac4f1f6ccc88b35ff4..0d0f8110bf24e6a0fc31b0c04695f3db9531c5fe 100644 (file)
@@ -4,7 +4,7 @@ LD=pdld
 
 COPTS=-S -O2 -fno-common -ansi -I. -I../pdos/pdpclib -D__WIN32__ -D__NOBIVA__ -D__PDOS__
 COBJ=aout.obj coff.obj elks.obj hashtab.obj ld.obj lib.obj link.obj map.obj \
-     mz.obj pe.obj report.obj section.obj symbol.obj vector.obj write7x.obj
+     mz.obj omf.obj pe.obj report.obj section.obj symbol.obj vector.obj write7x.obj
 
 all: clean slink.exe
 
index 48f3b0ad5a8972cb9f84e78fdf42b8db90e85091..17b1945c948fe369d72d8d0b56fd40e5ca07a916 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 mz.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 omf.c pe.c report.c section.c symbol.c vector.c write7x.c
 
 ifeq ($(OS), Windows_NT)
 all: slink.exe
index 27c237d58004dcecddd3bdd8ec11981768aca4d7..a34c7e284245fdd8b77948da44c43533a95919a0 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 mz.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 omf.c pe.c report.c section.c symbol.c vector.c write7x.c
 
 all: slink.exe
 
diff --git a/elks.h b/elks.h
index 6f9b13603d91bfd5f16e1d243ad93ca5b2a54d50..668dc2302f81675e5991b40bb2a1c735774db88f 100644 (file)
--- a/elks.h
+++ b/elks.h
@@ -1,5 +1,5 @@
 /******************************************************************************
- * @file            aout.h
+ * @file            elks.h
  *****************************************************************************/
 #ifndef     _ELKS_H
 #define     _ELKS_H
diff --git a/ld.c b/ld.c
index 2b1798bb592f7b4d4b162451c61d817270f06f45..9c3d68e7872413be4505b98f63269c2834a43a8c 100644 (file)
--- a/ld.c
+++ b/ld.c
@@ -12,6 +12,7 @@
 #include    "ld.h"
 #include    "lib.h"
 #include    "mz.h"
+#include    "omf.h"
 #include    "pe.h"
 #include    "report.h"
 #include    "section.h"
@@ -74,6 +75,8 @@ static void read_object_file (const char *filename, unsigned char *data, unsigne
         read_elks_object (filename, data, data_size);
     } else if (data[0] == 0x07 && data[1] == 0x01) {
         read_aout_object (filename, data, data_size);
+    } else if (data[0] == RECORD_TYPE_THEADR) {
+        read_omf_object (filename, data, data_size);
     } else {
         report_at (program_name, 0, REPORT_ERROR, "%s: unrecognised file format", filename);
     }
diff --git a/omf.c b/omf.c
new file mode 100644 (file)
index 0000000..cb3cdf1
--- /dev/null
+++ b/omf.c
@@ -0,0 +1,600 @@
+/******************************************************************************
+ * @file            omf.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "ld.h"
+#include    "lib.h"
+#include    "omf.h"
+#include    "reloc.h"
+#include    "report.h"
+#include    "section.h"
+#include    "symbol.h"
+
+static void estimate (void *data, unsigned long data_size, const char *filename, unsigned long *num_segments_p, unsigned long *num_extdefs_p, unsigned long *num_pubdefs_p, unsigned long *num_lnames_p) {
+
+    unsigned char *pos = (unsigned char *) data;
+    
+    unsigned char record_type;
+    unsigned short record_len;
+    
+    unsigned char *pubdef_name, *pubdef_name_end;
+    unsigned char pubdef_name_len;
+    
+    unsigned char *extdef_name, *extdef_name_end;
+    unsigned char extdef_name_len;
+    
+    unsigned char *lname, *lname_end;
+    unsigned char lname_len;
+    
+    unsigned long num_segments = 0, num_extdefs = 0, num_pubdefs = 0, num_lnames = 0;
+    int big_fields;
+    
+    while (pos < (unsigned char *) data + data_size) {
+    
+        record_type = pos[0];
+        
+        big_fields = record_type & 1;
+        record_type &= ~1;
+        
+        record_len = array_to_integer (pos + 1, 2);
+        
+        {
+        
+            unsigned char checksum = 0;
+            unsigned long i;
+            
+            for (i = 0; i < (unsigned long) record_len + 3; i++) {
+                checksum += pos[i];
+            }
+            
+            if (checksum != 0) {
+                report_at (program_name, 0, REPORT_WARNING, "%s: invalid checksum", filename);
+            }
+        
+        }
+        
+        pos += 3;
+        
+        if (record_type == RECORD_TYPE_EXTDEF) {
+        
+            extdef_name_end = (extdef_name = pos) + record_len - 1;
+            
+            while (extdef_name != extdef_name_end) {
+            
+                extdef_name_len = extdef_name[0];
+                
+                if (extdef_name + 1 + extdef_name_len + 1 > extdef_name_end) {
+                
+                    report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: incorrect extdef string length", filename);
+                    exit (EXIT_FAILURE);
+                
+                }
+                
+                num_extdefs++;
+                extdef_name = extdef_name + 1 + extdef_name_len + 1;
+            
+            }
+        
+        } else if (record_type == RECORD_TYPE_PUBDEF) {
+        
+            pubdef_name_end = (pubdef_name = pos) + record_len - 3;
+            
+            if (big_fields) {
+            
+                report_at (program_name, 0, REPORT_INTERNAL_ERROR, "%s: big fields not supported for record %#x", filename, record_type);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            while (pubdef_name != pubdef_name_end) {
+            
+                pubdef_name_len = pubdef_name[2];
+                
+                if (pubdef_name + 2 + 1 + pubdef_name_len + 1 > pubdef_name_end) {
+                
+                    report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: incorrect pubdef string length", filename);
+                    exit (EXIT_FAILURE);
+                
+                }
+                
+                num_pubdefs++;
+                pubdef_name = pubdef_name + 2 + 1 + pubdef_name_len + 1;
+            
+            }
+        
+        } else if (record_type == RECORD_TYPE_LNAMES) {
+        
+            lname_end = (lname = pos) + record_len - 1;
+            
+            while (lname != lname_end) {
+            
+                lname_len = lname[0];
+                
+                if (lname + 1 + lname_len > lname_end) {
+                
+                    report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: incorrect lname string length", filename);
+                    exit (EXIT_FAILURE);
+                
+                }
+                
+                num_lnames++;
+                lname = lname + 1 + lname_len;
+            
+            }
+        
+        } else if (record_type == RECORD_TYPE_SEGDEF) {
+            num_segments++;
+        }
+        
+        pos += record_len;
+    
+    }
+    
+    *num_segments_p = num_segments;
+    *num_extdefs_p = num_extdefs;
+    *num_pubdefs_p = num_pubdefs;
+    *num_lnames_p = num_lnames;
+
+}
+
+
+void read_omf_object (const char *filename, unsigned char *data, unsigned long data_size) {
+
+    unsigned char *pos = (unsigned char *) data;
+    
+    unsigned char base_segment_index;
+    unsigned short public_offset;
+    
+    struct {
+    
+        struct section_part *part;
+        unsigned long offset, size;
+    
+    } prev_ledata = { 0 };
+    
+    char **lnames;
+    int big_fields;
+    
+    unsigned char record_type;
+    unsigned short record_len;
+    
+    unsigned char *pubdef_name, *pubdef_name_end;
+    unsigned char pubdef_name_len;
+    
+    unsigned char *extdef_name, *extdef_name_end;
+    unsigned char extdef_name_len;
+    
+    unsigned char *lname, *lname_end;
+    unsigned char lname_len;
+    
+    unsigned long num_segments, num_extdefs, num_pubdefs, num_lnames;
+    unsigned long i_segments, i_extdefs, i_pubdefs, i_lnames;
+    
+    struct section_part **part_p_array, *part;
+    struct section *section;
+    
+    struct object_file *of;
+    struct symbol *symbol;
+    
+    estimate (data, data_size, filename, &num_segments, &num_extdefs, &num_pubdefs, &num_lnames);
+    
+    num_lnames++;
+    num_segments++;
+    
+    i_lnames = 1;
+    i_segments = 1;
+    i_pubdefs = num_segments;
+    i_extdefs = i_pubdefs + num_pubdefs;
+    
+    lnames = xmalloc (num_lnames * sizeof (*lnames));
+    
+    part_p_array = xmalloc (sizeof (*part_p_array) * num_segments);
+    of = object_file_make (filename, num_segments + num_pubdefs + num_extdefs);
+    
+    while (pos < (unsigned char *) data + data_size) {
+    
+        record_type = pos[0];
+        
+        big_fields = record_type & 1;
+        record_type &= ~1;
+        
+        record_len = array_to_integer (pos + 1, 2);
+        pos += 3;
+        
+        if (record_type == RECORD_TYPE_THEADR) {
+        
+            unsigned char string_length = pos[0];
+            
+            if (string_length > record_len - 2) {
+            
+                report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: incorrect string length", filename);
+                exit (EXIT_FAILURE);
+            
+            }
+        
+        } else if (record_type == RECORD_TYPE_COMENT) {
+            /* Nothing needs to be done. */
+        } else if (record_type == RECORD_TYPE_MODEND) {
+        
+            if (pos + record_len != data + data_size) {
+            
+                report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: MODEND record is not the last record", filename);
+                exit (EXIT_FAILURE);
+            
+            }
+        
+        } else if (record_type == RECORD_TYPE_EXTDEF) {
+        
+            extdef_name_end = (extdef_name = pos) + record_len - 1;
+            
+            while (extdef_name != extdef_name_end) {
+            
+                extdef_name_len = extdef_name[0];
+                
+                symbol = of->symbol_arr + i_extdefs;
+                i_extdefs++;
+                
+                symbol->name = xstrndup ((char *) extdef_name + 1, extdef_name_len);
+                symbol->value = 0;
+                symbol->part = 0;
+                symbol->section_number = UNDEFINED_SECTION_NUMBER;
+                
+                symbol_record_external_symbol (symbol);
+                extdef_name = extdef_name + 1 + extdef_name_len + 1;
+            
+            }
+        
+        } else if (record_type == RECORD_TYPE_PUBDEF) {
+        
+            pubdef_name_end = (pubdef_name = pos) + record_len - 3;
+            base_segment_index = pubdef_name[1];
+            
+            while (pubdef_name != pubdef_name_end) {
+            
+                pubdef_name_len = pubdef_name[2];
+                
+                public_offset = array_to_integer (pubdef_name + 3 + pubdef_name_len, 2);
+                symbol = of->symbol_arr + i_extdefs++;
+                
+                if (base_segment_index >= i_segments || !base_segment_index) {
+            
+                    report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid base segment index %d", filename, base_segment_index);
+                    exit (EXIT_FAILURE);
+                
+                }
+                
+                symbol->name = xstrndup ((char *) pubdef_name + 3, pubdef_name_len);
+                symbol->value = public_offset;
+                symbol->part = part_p_array[base_segment_index];
+                symbol->section_number = base_segment_index;
+                
+                symbol_record_external_symbol (symbol);
+                pubdef_name = pubdef_name + 2 + 1 + pubdef_name_len + 1;
+            
+            }
+        
+        } else if (record_type == RECORD_TYPE_LNAMES) {
+        
+            lname_end = (lname = pos) + record_len - 1;
+            
+            while (lname != lname_end) {
+            
+                lname_len = lname[0];
+                
+                lnames[i_lnames++] = xstrndup ((char *) lname + 1, lname_len);
+                lname = lname + 1 + lname_len;
+            
+            }
+        
+        } else if (record_type == RECORD_TYPE_SEGDEF) {
+        
+            unsigned char attributes = pos[0];
+            
+            unsigned short segment_name_index;
+            unsigned short class_name_index;
+            
+            unsigned long segment_len;
+            
+            if (!(attributes & SEGMENT_ATTR_P)) {
+            
+                report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: OMF USE16 segments are not supported", filename);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            if ((attributes >> 5) == 0) {
+            
+                report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: OMF absolute segments are not supported", filename);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            if (big_fields) {
+            
+                segment_len = array_to_integer (pos + 1, 4);
+                
+                segment_name_index = pos[5];
+                class_name_index = pos[6];
+            
+            } else {
+            
+                report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: non big fields not supported for record %#x", filename, record_type);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            if (segment_name_index >= i_lnames  || !segment_name_index) {
+            
+                report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid segment name index", filename);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            if (class_name_index >= i_lnames  || !class_name_index) {
+            
+                report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid class name index", filename);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            section = section_find_or_make (lnames[segment_name_index]);
+            
+            if (strcmp (lnames[class_name_index], "CODE") == 0) {
+                section->flags = SECTION_FLAG_ALLOC | SECTION_FLAG_LOAD | SECTION_FLAG_READONLY | SECTION_FLAG_CODE;
+            } else if (strcmp (lnames[class_name_index], "DATA") == 0) {
+                section->flags = SECTION_FLAG_ALLOC | SECTION_FLAG_LOAD | SECTION_FLAG_DATA;
+            } else {
+                section->flags = SECTION_FLAG_ALLOC | SECTION_FLAG_LOAD | SECTION_FLAG_DATA;
+            }
+            
+            part = section_part_new (section, of);
+            
+            switch (attributes >> 5) {
+            
+                case 1:
+                
+                    part->alignment = 1;
+                    break;
+                
+                case 2:
+                
+                    part->alignment = 2;
+                    break;
+                
+                case 3:
+                
+                    part->alignment = 16;
+                    break;
+                
+                case 4:
+                
+                    part->alignment = 4096;
+                    break;
+                
+                case 5:
+                
+                    part->alignment = 4;
+                    break;
+                
+                default:
+                
+                    report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid segment alignment", filename);
+                    exit (EXIT_FAILURE);
+            
+            }
+            
+            part->content = xmalloc (part->content_size = segment_len);
+            symbol = of->symbol_arr + i_segments;
+            
+            symbol->name = xstrdup (section->name);
+            symbol->flags = SYMBOL_FLAG_SECTION_SYMBOL;
+            symbol->value = 0;
+            symbol->size = 0;
+            symbol->part = part;
+            symbol->section_number = i_segments;
+            
+            section_append_section_part (section, part);
+            part_p_array[i_segments++] = part;
+        
+        } else if (record_type == RECORD_TYPE_GRPDEF) {
+            /* Nothing needs to be done. */
+        } else if (record_type == RECORD_TYPE_FIXUPP) {
+        
+            struct section_part *part = prev_ledata.part;
+            
+            unsigned char *subrec = pos;
+            unsigned char *end = pos + record_len - 1;
+            
+            if (!part) {
+            
+                report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: FIXUPP record has no preceding LEDATA record", filename);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            if (!big_fields) {
+            
+                report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: non big field not supported for record %#x", filename, record_type);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            while (subrec != end) {
+            
+                if (subrec[0] & 0x80) {
+                
+                    struct reloc_entry *reloc;
+                    unsigned long old_reloc_count;
+                    
+                    unsigned char fixdat, frame_method, target_method;
+                    unsigned short data_record_offset, target_datum;
+                    
+                    if (subrec[0] & 0x40) {
+                    
+                        report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: only self-relative OMF fixups are supported", filename);
+                        exit (EXIT_FAILURE);
+                    
+                    }
+                    
+                    if (((subrec[0] >> 2) & 0x0f) != 9) {
+                    
+                        report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: only 32-bit offset OMF fixups are supported", filename);
+                        exit (EXIT_FAILURE);
+                    
+                    }
+                    
+                    data_record_offset = ((unsigned short) (subrec[0] & 0x03)) << 8;
+                    data_record_offset |= subrec[1];
+                    
+                    if (data_record_offset >= prev_ledata.size) {
+                    
+                        report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid data record", filename);
+                        exit (EXIT_FAILURE);
+                    
+                    }
+                    
+                    fixdat = subrec[2];
+                    
+                    if (fixdat & 0x80) {
+                    
+                        report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: only explicit frame methods in OMF fixups are supported", filename);
+                        exit (EXIT_FAILURE);
+                    
+                    }
+                    
+                    if (fixdat & 0x08) {
+                    
+                        report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: only explicit targets methods in OMF fixups are supported", filename);
+                        exit (EXIT_FAILURE);
+                    
+                    }
+                    
+                    if (!(fixdat & 0x04)) {
+                    
+                        report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: displacement fields in OMF fixups are supported", filename);
+                        exit (EXIT_FAILURE);
+                    
+                    }
+                    
+                    frame_method = (fixdat & 0x70) >> 4;
+                    
+                    target_method = fixdat & 0x03;
+                    target_datum = subrec[3];
+                    
+                    if (frame_method != METHOD_F5) {
+                        
+                        report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: only F5 frame methods in OMF fixups are supported", filename);
+                        exit (EXIT_FAILURE);
+                    
+                    }
+                    
+                    if (target_method != METHOD_T2_EXTDEF) {
+                        
+                        report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: only T2 target methods in OMF fixups are supported", filename);
+                        exit (EXIT_FAILURE);
+                    
+                    }
+                    
+                    old_reloc_count = part->reloc_cnt;
+                    part->reloc_cnt += 1;
+                    
+                    part->reloc_arr = xrealloc (part->reloc_arr, part->reloc_cnt * sizeof (*part->reloc_arr));
+                    memset (part->reloc_arr + old_reloc_count, 0, (part->reloc_cnt - old_reloc_count) * sizeof *part->reloc_arr);
+                    
+                    reloc = part->reloc_arr + old_reloc_count;
+                    
+                    if (target_method == METHOD_T2_EXTDEF) {
+                    
+                        if (target_datum > num_extdefs || !target_datum) {
+                        
+                            report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid target datum", filename);
+                            exit (EXIT_FAILURE);
+                        
+                        }
+                        
+                        reloc->symbol = of->symbol_arr + num_segments + num_pubdefs + target_datum - 1;
+                    
+                    }
+                    
+                    reloc->offset = data_record_offset;
+                    reloc->addend = 0;
+                    reloc->howto = &reloc_howtos[RELOC_TYPE_PC32];
+                    
+                    subrec += 4;
+                
+                } else {
+                
+                    report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: THREAD subrecords are not yet supported", filename);
+                    exit (EXIT_FAILURE);
+                
+                }
+            
+            }
+        
+        } else if (record_type == RECORD_TYPE_LEDATA) {
+        
+            unsigned char seg_index = pos[0];
+            
+            unsigned char *data_bytes;
+            unsigned short size;
+            
+            unsigned long offset;
+            
+            if (big_fields) {
+            
+                offset = array_to_integer (pos + 1, 4);
+                size = record_len - 6;
+                data_bytes = pos + 5;
+            
+            } else {
+            
+                offset = array_to_integer (pos + 1, 2);
+                size = record_len - 4;
+                data_bytes = pos + 3;
+            
+            }
+            
+            if (seg_index >= i_segments || !seg_index) {
+            
+                report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid seg index", filename);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            part = part_p_array[seg_index];
+            
+            if (offset + size > part->content_size) {
+            
+                report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid LEDATA offset and size combination for segment", filename);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            memcpy (part->content + offset, data_bytes, size);
+            
+            prev_ledata.part = part;
+            prev_ledata.offset = offset;
+            prev_ledata.size = size;
+        
+        } else {
+        
+            report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: not yet supported record type %#x", filename, record_type | big_fields);
+            exit (EXIT_FAILURE);
+        
+        }
+        
+        pos += record_len;
+    
+    }
+    
+    for (i_lnames = 0; i_lnames < num_lnames; i_lnames++) {
+        free (lnames[i_lnames]);
+    }
+    
+    free (lnames);
+    free (part_p_array);
+
+}
diff --git a/omf.h b/omf.h
new file mode 100644 (file)
index 0000000..b8bfef3
--- /dev/null
+++ b/omf.h
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * @file            omf.h
+ *****************************************************************************/
+#ifndef     _OMF_H
+#define     _OMF_H
+
+#define     RECORD_TYPE_THEADR          0x80
+#define     RECORD_TYPE_COMENT          0x88
+#define     RECORD_TYPE_MODEND          0x8A
+#define     RECORD_TYPE_EXTDEF          0x8C
+#define     RECORD_TYPE_PUBDEF          0x90
+#define     RECORD_TYPE_LNAMES          0x96
+#define     RECORD_TYPE_SEGDEF          0x98
+#define     RECORD_TYPE_GRPDEF          0x9A
+#define     RECORD_TYPE_FIXUPP          0x9C
+#define     RECORD_TYPE_LEDATA          0xA0
+
+#define     SEGMENT_ATTR_P              0x1
+
+#define     METHOD_T2_EXTDEF            2
+#define     METHOD_F5                   5
+
+void read_omf_object (const char *filename, unsigned char *data, unsigned long data_size);
+
+#endif      /* _OMF_H */