Create 32-bit PE executables
authorRobert Pengelly <robertapengelly@hotmail.com>
Mon, 18 Nov 2024 23:57:02 +0000 (23:57 +0000)
committerRobert Pengelly <robertapengelly@hotmail.com>
Mon, 18 Nov 2024 23:57:02 +0000 (23:57 +0000)
elks.c
ld.c
ld.h
lib.c
pe.h [new file with mode: 0644]

diff --git a/elks.c b/elks.c
index c15db37b2cda9515f337307bcf7f228363ffcd64..84d56de7185c990db428ad526d9d561f107dcf30 100644 (file)
--- a/elks.c
+++ b/elks.c
@@ -6,11 +6,13 @@
 #include    <stdio.h>
 #include    <stdlib.h>
 #include    <string.h>
+#include    <time.h>
 
 #include    "aout.h"
 #include    "elks.h"
 #include    "ld.h"
 #include    "lib.h"
+#include    "pe.h"
 #include    "report.h"
 #include    "write7x.h"
 
@@ -352,8 +354,8 @@ static int relocate (struct elks_object *object, struct elks_relocation_info *r,
         
         if (strcmp (symname, "__edata") == 0) {
         
-            int32_t data_addr = ((char *) data - (char *) output) - header_size;
-            data_addr += state->data_size;
+            int32_t data_addr = ((char *) text - (char *) output) - header_size;
+            data_addr += state->text_size;
             
             write741_to_byte_array (symbol->n_value, data_addr / 16);
             /*need_relocate = 0;*/
@@ -627,6 +629,261 @@ static int write_elks_object (unsigned long a_entry) {
 }
 
 
+static struct msdos_header *doshdr;
+static struct pe_header *pehdr;
+static struct pe_optional_header *opthdr;
+
+static struct section_table_entry *section_text;
+static struct section_table_entry *section_data;
+
+unsigned char dos_stub[] = {
+
+    0x0E,   0x1F,   0xBA,   0x0E,   0x00,   0xB4,   0x09,   0xCD,
+    0x21,   0xB8,   0x01,   0x4C,   0xCD,   0x21,   0x54,   0x68,
+    
+    0x69,   0x73,   0x20,   0x70,   0x72,   0x6F,   0x67,   0x72,
+    0x61,   0x6D,   0x20,   0x63,   0x61,   0x6E,   0x6E,   0x6F,
+    
+    0x74,   0x20,   0x62,   0x65,   0x20,   0x72,   0x75,   0x6E,
+    0x20,   0x69,   0x6E,   0x20,   0x44,   0x4F,   0x53,   0x20,
+    
+    0x6D,   0x6F,   0x64,   0x65,   0x2E,   0x0D,   0x0D,   0x0A,
+    0x24,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00
+
+};
+
+static int no_sections = 0;
+
+static unsigned short chksum (unsigned int checksum, void *base, int count) {
+
+    register int sum = 0;
+    int *data;
+    
+    if (count && base != NULL) {
+    
+        data = (int *) base;
+        
+        do {
+        
+            sum = *(unsigned short *) data + checksum;
+            data = (int *) ((char *) data + 2);
+            
+            checksum = (unsigned short) sum + (sum >> 16);
+        
+        } while (--count);
+    
+    }
+    
+    return checksum + (checksum >> 16);
+
+}
+
+static int pe_chksum (void *base, unsigned int size) {
+
+    void *remaining_data;
+    int remaining_data_size;
+    
+    unsigned int pe_header_chksum, file_chksum;
+    unsigned int pe_header_size;
+    
+    pe_header_size = (unsigned long) pehdr - (unsigned long) base + \
+        ((unsigned long) &opthdr->Checksum - (unsigned long) pehdr);
+    
+    remaining_data_size = (size - pe_header_size - 4) >> 1;
+    remaining_data = &opthdr->Subsystem;
+    
+    pe_header_chksum = chksum (0, base, pe_header_size >> 1);
+    file_chksum = chksum (pe_header_chksum, remaining_data, remaining_data_size);
+    
+    if (size & 1) {
+        file_chksum += (unsigned short) *((char *) base + size - 1);
+    }
+    
+    return size + file_chksum;
+
+}
+
+static int init_pe_object (void) {
+
+    header_size = sizeof (*doshdr) + sizeof (dos_stub) + sizeof (*pehdr) + sizeof (*opthdr);
+    no_sections = 0;
+    
+    if (state->raw_text_size > 0) {
+    
+        header_size += sizeof (*section_text);
+        no_sections++;
+    
+    }
+    
+    if (state->raw_data_size > 0) {
+    
+        header_size += sizeof (*section_data);
+        no_sections++;
+    
+    }
+    
+    header_size = ALIGN_UP (header_size, SECTION_ALIGNMENT);
+    output_size = header_size + ALIGN_UP (state->text_size, SECTION_ALIGNMENT) + ALIGN_UP (state->data_size, SECTION_ALIGNMENT);
+    
+    if ((output = malloc (output_size)) == NULL) {
+        return 2;
+    }
+    
+    memset (output, 0, output_size);
+    
+    doshdr = (struct msdos_header *) output;
+    pehdr  = (struct pe_header *) ((char *) doshdr + sizeof (*doshdr) + sizeof (dos_stub));
+    opthdr = (struct pe_optional_header *) ((char *) pehdr + sizeof (*pehdr));
+    
+    section_text = (struct section_table_entry *) ((char *) opthdr + sizeof (*opthdr));
+    section_data = (struct section_table_entry *) ((char *) section_text + sizeof (*section_text));
+    
+    text = (void *) ((char *) output + header_size);
+    data = (void *) ((char *) text + ALIGN_UP (state->text_size, SECTION_ALIGNMENT));
+    
+    return 0;
+
+}
+
+static int write_pe_object (unsigned long entry) {
+
+    doshdr->e_magic[0] = 'M';
+    doshdr->e_magic[1] = 'Z';
+    
+    write721_to_byte_array (doshdr->e_cblp, 0x0090);
+    write721_to_byte_array (doshdr->e_cp, 0x0003);
+    
+    write721_to_byte_array (doshdr->e_cparhdr, ALIGN_UP (sizeof (*doshdr), 16) / 16);
+    
+    write721_to_byte_array (doshdr->e_maxalloc, 0xFFFF);
+    write721_to_byte_array (doshdr->e_sp, 0x00B8);
+    
+    write721_to_byte_array (doshdr->e_lfarlc, sizeof (*doshdr));
+    write741_to_byte_array (doshdr->e_lfanew, sizeof (*doshdr) + sizeof (dos_stub));
+    
+    memcpy ((char *)  output + GET_UINT16 (doshdr->e_lfarlc), dos_stub, sizeof (dos_stub));
+    
+    
+    pehdr->Signature[0] = 'P';
+    pehdr->Signature[1] = 'E';
+    
+    write721_to_byte_array (pehdr->Machine, IMAGE_FILE_MACHINE_I386);
+    write721_to_byte_array (pehdr->NumberOfSections, no_sections);
+    write741_to_byte_array (pehdr->TimeDateStamp, time (0));
+    write721_to_byte_array (pehdr->SizeOfOptionalHeader, sizeof (*opthdr));
+    
+    {
+    
+        unsigned short characteristics = 0;
+        
+        characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
+        characteristics |= IMAGE_FILE_EXECUTABLE_IMAGE;
+        characteristics |= IMAGE_FILE_LINE_NUMS_STRIPPED;
+        characteristics |= IMAGE_FILE_LOCAL_SYMS_STRIPPED;
+        characteristics |= IMAGE_FILE_32BIT_MACHINE;
+        characteristics |= IMAGE_FILE_DEBUG_STRIPPED;
+        
+        write721_to_byte_array (pehdr->Characteristics, characteristics);
+    
+    }
+    
+    
+    write721_to_byte_array (opthdr->Magic, IMAGE_FILE_MAGIC_I386);
+    
+    opthdr->MajorLinkerVersion = 2;
+    opthdr->MinorLinkerVersion = 1;
+    
+    write741_to_byte_array (opthdr->SizeOfCode, ALIGN_UP (state->text_size, SECTION_ALIGNMENT));
+    write741_to_byte_array (opthdr->SizeOfInitializedData, ALIGN_UP (state->data_size, SECTION_ALIGNMENT));
+    write741_to_byte_array (opthdr->SizeOfUninitializedData,  ALIGN_UP (state->bss_size, SECTION_ALIGNMENT));
+    write741_to_byte_array (opthdr->AddressOfEntryPoint, ALIGN_UP ((char *) text - (char *) output, SECTION_ALIGNMENT) + entry);
+    write741_to_byte_array (opthdr->BaseOfCode, ALIGN_UP ((char *) text - (char *) output, SECTION_ALIGNMENT));
+    write741_to_byte_array (opthdr->BaseOfData, ALIGN_UP ((char *) data - (char *) output, SECTION_ALIGNMENT));
+    
+    write741_to_byte_array (opthdr->ImageBase, state->psp);
+    write741_to_byte_array (opthdr->SectionAlignment, SECTION_ALIGNMENT);
+    write741_to_byte_array (opthdr->FileAlignment, SECTION_ALIGNMENT);
+    
+    write721_to_byte_array (opthdr->MajorOperatingSystemVersion, 4);
+    write721_to_byte_array (opthdr->MajorImageVersion, 1);
+    write721_to_byte_array (opthdr->MajorSubsystemVersion, 4);
+    
+    write741_to_byte_array (opthdr->SizeOfImage, GET_UINT32 (opthdr->BaseOfData) + ALIGN_UP (GET_UINT32 (opthdr->SizeOfInitializedData), SECTION_ALIGNMENT));
+    write741_to_byte_array (opthdr->SizeOfHeaders, ALIGN_UP (header_size, SECTION_ALIGNMENT));
+    write741_to_byte_array (opthdr->Checksum, pe_chksum (output, output_size));
+    
+    write721_to_byte_array (opthdr->Subsystem, state->subsystem);
+    
+    {
+    
+        unsigned long ibss_addr = ((char *) data - (char *) output) + state->data_size;
+        unsigned long ibss_size = state->bss_size;
+        
+        unsigned long stack_addr = ibss_addr + ibss_size;
+        unsigned long stack_size = ALIGN_UP (stack_addr, SECTION_ALIGNMENT);
+        
+        write741_to_byte_array (opthdr->SizeOfStackReserved, SECTION_ALIGNMENT << 9);
+        write741_to_byte_array (opthdr->SizeOfStackCommit, ALIGN_UP (stack_addr % 16 + stack_size, SECTION_ALIGNMENT));
+        write741_to_byte_array (opthdr->SizeOfHeapReserved, SECTION_ALIGNMENT << 8);
+        write741_to_byte_array (opthdr->SizeOfHeapCommit, ALIGN_UP (stack_addr % 16 + stack_size, SECTION_ALIGNMENT));
+    
+    }
+    
+    write741_to_byte_array (opthdr->NumberOfRvaAndSizes, 16);
+    
+    
+    if (state->raw_text_size > 0) {
+    
+        unsigned long characteristics = 0;
+        memcpy (section_text->Name, ".text", 5);
+        
+        write741_to_byte_array (section_text->VirtualSize, state->text_size);
+        write741_to_byte_array (section_text->VirtualAddress, GET_UINT32 (opthdr->BaseOfCode));
+        write741_to_byte_array (section_text->SizeOfRawData, state->raw_text_size);
+        write741_to_byte_array (section_text->PointerToRawData, ((char *) text - (char *) output));
+        
+        characteristics |= IMAGE_SCN_CNT_CODE;
+        characteristics |= IMAGE_SCN_ALIGN_4BYTES;
+        characteristics |= IMAGE_SCN_MEM_EXECUTE;
+        characteristics |= IMAGE_SCN_MEM_READ;
+        
+        write741_to_byte_array (section_text->Characteristics, characteristics);
+    
+    }
+    
+    if (state->raw_data_size > 0) {
+    
+        unsigned long characteristics = 0;
+        memcpy (section_text->Name, ".data", 5);
+        
+        write741_to_byte_array (section_data->VirtualSize, state->data_size);
+        write741_to_byte_array (section_data->VirtualAddress, GET_UINT32 (opthdr->BaseOfData));
+        write741_to_byte_array (section_data->SizeOfRawData, state->raw_data_size);
+        write741_to_byte_array (section_data->PointerToRawData, ((char *) data - (char *) output));
+        
+        characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
+        characteristics |= IMAGE_SCN_ALIGN_4BYTES;
+        characteristics |= IMAGE_SCN_MEM_READ;
+        characteristics |= IMAGE_SCN_MEM_WRITE;
+        
+        write741_to_byte_array (section_data->Characteristics, characteristics);
+    
+    }
+    
+    
+    /* write the file */
+    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;
+    
+    }
+    
+    return 0;
+
+}
+
+
 int create_executable_from_elks_objects (void) {
 
     struct elks_object *object;
@@ -657,6 +914,15 @@ int create_executable_from_elks_objects (void) {
         
         }
     
+    } else if (state->format == LD_FORMAT_I386_PE) {
+    
+        if (init_pe_object ()) {
+        
+            report_at (program_name, 0, REPORT_ERROR, "failed to initialize pe object");
+            return EXIT_FAILURE;
+        
+        }
+    
     }
     
     for (i = 0; i < state->nb_elks_objs; ++i) {
@@ -687,7 +953,7 @@ int create_executable_from_elks_objects (void) {
         return EXIT_FAILURE;
     }
     
-    if (state->format == LD_FORMAT_IA16_ELKS || state->format == LD_FORMAT_I386_ELKS || state->format == LD_FORMAT_I386_AOUT) {
+    if (state->format == LD_FORMAT_IA16_ELKS || state->format == LD_FORMAT_I386_ELKS || state->format == LD_FORMAT_I386_AOUT || state->format == LD_FORMAT_I386_PE) {
         entry = get_entry ();
     }
     
@@ -742,6 +1008,14 @@ int create_executable_from_elks_objects (void) {
         
         }
     
+    } else if (state->format == LD_FORMAT_I386_PE) {
+    
+        if (write_pe_object (entry)) {
+        
+            report_at (program_name, 0, REPORT_ERROR, "failed to write pe object");
+            return EXIT_FAILURE;
+        
+        }
     }
     
     return EXIT_SUCCESS;
diff --git a/ld.c b/ld.c
index cdb7af52a6e86bfc3b18ac305a20605f32e23194..553a87a45a04b017e3d97b47f552f583a1a96e87 100644 (file)
--- a/ld.c
+++ b/ld.c
@@ -108,6 +108,10 @@ static int process_elks (void *obj, unsigned long sz, const char *fname, int qui
     
     }*/
     
+    state->raw_text_size    += GET_UINT32 (hdr->a_text);
+    state->raw_data_size    += GET_UINT32 (hdr->a_data);
+    state->raw_bss_size     += GET_UINT32 (hdr->a_bss);
+    
     if (state->impure) {
     
         state->text_size    += GET_UINT32 (hdr->a_text);
@@ -667,6 +671,8 @@ int main (int argc, char **argv) {
         
         state->impure = 1;
     
+    } else if (state->format == LD_FORMAT_I386_PE) {
+        state->psp = 0x00400000;
     }
     
     for (i = 0; i < state->nb_files; i++) {
diff --git a/ld.h b/ld.h
index 6f5e28924f540b2336e59c84e7b1547cc38c5543..6fccd1b020c70a727c1cfd3d7af99a44e6880b5b 100644 (file)
--- a/ld.h
+++ b/ld.h
@@ -24,6 +24,8 @@ struct elks_object {
 
 };
 
+#define     GET_UINT16(arr)             ((unsigned long) arr[0] | (((unsigned long) arr[1]) << 8))
+
 #define     GET_INT32(arr)              ((long) arr[0] | (((long) arr[1]) << 8) | (((long) arr[2]) << 16) | (((long) arr[3]) << 24))
 #define     GET_UINT32(arr)             ((unsigned long) arr[0] | (((unsigned long) arr[1]) << 8) | (((unsigned long) arr[2]) << 16) | (((unsigned long) arr[3]) << 24))
 
@@ -43,7 +45,10 @@ struct ld_state {
     struct elks_object **elks_objs;
     long nb_elks_objs;
     
+    unsigned long raw_text_size, raw_data_size, raw_bss_size;
     unsigned long text_size, data_size, bss_size;
+    
+    unsigned long subsystem;
     char *entry;
 
 };
@@ -55,11 +60,11 @@ struct ld_state {
 #define     LD_FORMAT_I386_ELKS         0x04
 
 #define     LD_FORMAT_I386_AOUT         0x08
+#define     LD_FORMAT_I386_PE           0x10
 
 extern struct ld_state *state;
 extern const char *program_name;
 
-#define     FILE_ALIGNMENT              512
 #define     SECTION_ALIGNMENT           4096
 
 #define     DIV_ROUNDUP(a, b)           (((a) + ((b) - 1)) / (b))
diff --git a/lib.c b/lib.c
index eb87b241cfab23b636cfbab1caa5c1bda587623a..7aeac3610fe7ffe8923f342ee58020223fbb2016 100644 (file)
--- a/lib.c
+++ b/lib.c
@@ -36,19 +36,21 @@ struct ld_option {
 #define     LD_OPTION_MAP               5
 #define     LD_OPTION_OUTFILE           6
 #define     LD_OPTION_PSP               7
+#define     LD_OPTION_SUBSYSTEM         8
 
 static struct ld_option opts[] = {
 
-    {   "-N",           LD_OPTION_IMPURE,       LD_OPTION_NO_ARG    },
-    {   "-T",           LD_OPTION_PSP,          LD_OPTION_HAS_ARG   },
+    {   "-N",               LD_OPTION_IMPURE,       LD_OPTION_NO_ARG    },
+    {   "-T",               LD_OPTION_PSP,          LD_OPTION_HAS_ARG   },
     
-    {   "-e",           LD_OPTION_ENTRY,        LD_OPTION_HAS_ARG   },
-    {   "-o",           LD_OPTION_OUTFILE,      LD_OPTION_HAS_ARG   },
+    {   "-e",               LD_OPTION_ENTRY,        LD_OPTION_HAS_ARG   },
+    {   "-o",               LD_OPTION_OUTFILE,      LD_OPTION_HAS_ARG   },
     
-    {   "--oformat",    LD_OPTION_FORMAT,       LD_OPTION_HAS_ARG   },
-    {   "--help",       LD_OPTION_HELP,         LD_OPTION_NO_ARG    },
+    {   "--oformat",        LD_OPTION_FORMAT,       LD_OPTION_HAS_ARG   },
+    {   "--help",           LD_OPTION_HELP,         LD_OPTION_NO_ARG    },
+    {   "--subsystem",      LD_OPTION_SUBSYSTEM,    LD_OPTION_HAS_ARG   },
     
-    {   0,              0,                      0                   }
+    {   0,                  0,                      0                   }
 
 };
 
@@ -174,6 +176,8 @@ void parse_args (int argc, char **argv, int optind) {
     
     }
     
+    state->subsystem = 3;
+    
     while (optind < argc) {
     
         r = argv[optind++];
@@ -276,6 +280,13 @@ void parse_args (int argc, char **argv, int optind) {
                 
                 }
                 
+                if (xstrcasecmp (optarg, "pe-i386") == 0) {
+                
+                    state->format = LD_FORMAT_I386_PE;
+                    break;
+                
+                }
+                
                 report_at (program_name, 0, REPORT_ERROR, "unrecognised output format '%s'", optarg);
                 exit (EXIT_FAILURE);
             
@@ -336,6 +347,26 @@ void parse_args (int argc, char **argv, int optind) {
             
             }
             
+            case LD_OPTION_SUBSYSTEM: {
+            
+                long conversion;
+                char *temp;
+                
+                errno = 0;
+                conversion = strtol (optarg, &temp, 0);
+                
+                if (!*optarg || isspace ((int) *optarg) || errno || *temp) {
+                
+                    report_at (program_name, 0, REPORT_ERROR, "bad number for subsystem");
+                    exit (EXIT_FAILURE);
+                
+                }
+                
+                state->subsystem = (unsigned long) conversion;
+                break;
+            
+            }
+            
             default: {
             
                 report_at (program_name, 0, REPORT_ERROR, "unsupported option '%s'", r);
diff --git a/pe.h b/pe.h
new file mode 100644 (file)
index 0000000..59a7724
--- /dev/null
+++ b/pe.h
@@ -0,0 +1,177 @@
+/******************************************************************************
+ * @file            pe.h
+ *****************************************************************************/
+#ifndef     _PE_H
+#define     _PE_H
+
+struct msdos_header {
+
+    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                       */
+    unsigned char e_res[8];             /* Reserved words                       */
+    unsigned char e_oemid[2];           /* OEM identifier (for e_oeminfo)       */
+    unsigned char e_oeminfo[2];         /* OEM information; e_oemid specific    */
+    unsigned char e_res2[20];           /* Reserved words                       */
+    unsigned char e_lfanew[4];          /* File address of new exe header       */
+
+};
+
+struct pe_header {
+
+    unsigned char Signature[4];
+    
+    unsigned char Machine[2];
+    unsigned char NumberOfSections[2];
+    
+    unsigned char TimeDateStamp[4];
+    unsigned char PointerToSymbolTable[4];
+    unsigned char NumberOfSymbols[4];
+    
+    unsigned char SizeOfOptionalHeader[2];
+    unsigned char Characteristics[2];
+
+};
+
+#define     IMAGE_FILE_MACHINE_I386                         0x014C
+
+#define     IMAGE_FILE_RELOCS_STRIPPED                      0x0001
+#define     IMAGE_FILE_EXECUTABLE_IMAGE                     0x0002
+#define     IMAGE_FILE_LINE_NUMS_STRIPPED                   0x0004
+#define     IMAGE_FILE_LOCAL_SYMS_STRIPPED                  0x0008
+#define     IMAGE_FILE_32BIT_MACHINE                        0x0100
+#define     IMAGE_FILE_DEBUG_STRIPPED                       0x0200
+
+struct pe_optional_header {
+
+    unsigned char Magic[2];
+    
+    unsigned char MajorLinkerVersion;
+    unsigned char MinorLinkerVersion;
+    
+    unsigned char SizeOfCode[4];
+    unsigned char SizeOfInitializedData[4];
+    unsigned char SizeOfUninitializedData[4];
+    
+    unsigned char AddressOfEntryPoint[4];
+    
+    unsigned char BaseOfCode[4];
+    unsigned char BaseOfData[4];
+    
+    
+    unsigned char ImageBase[4];
+    unsigned char SectionAlignment[4];
+    unsigned char FileAlignment[4];
+    
+    unsigned char MajorOperatingSystemVersion[2];
+    unsigned char MinorOperatingSystemVersion[2];
+    unsigned char MajorImageVersion[2];
+    unsigned char MinorImageVersion[2];
+    unsigned char MajorSubsystemVersion[2];
+    unsigned char MinorSubsystemVersion[2];
+    
+    unsigned char Win32VersionValue[4];
+    unsigned char SizeOfImage[4];
+    unsigned char SizeOfHeaders[4];
+    unsigned char Checksum[4];
+    
+    unsigned char Subsystem[2];
+    unsigned char DllCharacteristics[2];
+    
+    unsigned char SizeOfStackReserved[4];
+    unsigned char SizeOfStackCommit[4];
+    unsigned char SizeOfHeapReserved[4];
+    unsigned char SizeOfHeapCommit[4];
+    
+    unsigned char LoaderFlags[4];
+    unsigned char NumberOfRvaAndSizes[4];
+    
+    
+    /*unsigned char Reserved[128];*/
+    unsigned char Reserved[32 * 4];
+
+};
+
+#define     IMAGE_FILE_MAGIC_I386                           0x010B
+
+struct section_table_entry {
+
+    char Name[8];
+    
+    unsigned char VirtualSize[4];
+    unsigned char VirtualAddress[4];
+    
+    unsigned char SizeOfRawData[4];
+    unsigned char PointerToRawData[4];
+    unsigned char PointerToRelocations[4];
+    unsigned char PointerToLinenumbers[4];
+    
+    unsigned char NumberOfRelocations[2];
+    unsigned char NumberOfLinenumbers[2];
+    
+    unsigned char Characteristics[4];
+
+};
+
+#define     IMAGE_SCN_CNT_CODE                              0x00000020
+#define     IMAGE_SCN_CNT_INITIALIZED_DATA                  0x00000040
+#define     IMAGE_SCN_CNT_UNINITIALIZED_DATA                0x00000080
+#define     IMAGE_SCN_ALIGN_4BYTES                          0x00300000
+#define     IMAGE_SCN_MEM_EXECUTE                           0x20000000
+#define     IMAGE_SCN_MEM_READ                              0x40000000
+#define     IMAGE_SCN_MEM_WRITE                             0x80000000
+
+struct relocation_entry {
+
+    unsigned int VirtualAddress;
+    unsigned int SymbolTableIndex;
+    
+    unsigned short Type;
+
+};
+
+#define     RELOCATION_ENTRY_SIZE                           10
+
+#define     IMAGE_REL_I386_ABSOLUTE                         0x0000
+#define     IMAGE_REL_I386_DIR32                            0x0006
+#define     IMAGE_REL_I386_DIR32NB                          0x0007
+#define     IMAGE_REL_I386_REL32                            0x0014
+
+struct symbol_table_entry {
+
+    char Name[8];
+    unsigned int Value;
+    
+    signed short SectionNumber;
+    unsigned short Type;
+    
+    unsigned char StorageClass;
+    unsigned char NumberOfAuxSymbols;
+
+};
+
+#define     SYMBOL_TABLE_ENTRY_SIZE                         18
+#define     IMAGE_SYM_UNDEFINED                             0
+
+#define     IMAGE_SYM_ABSOLUTE                              -1
+#define     IMAGE_SYM_DEBUG                                 -2
+
+#define     IMAGE_SYM_TYPE_NULL                             0
+#define     IMAGE_SYM_DTYPE_NULL                            0
+
+#define     IMAGE_SYM_CLASS_EXTERNAL                        2
+#define     IMAGE_SYM_CLASS_STATIC                          3
+#define     IMAGE_SYM_CLASS_FILE                            103
+
+#endif      /* _PE_H */