Initial re-write
authorRobert Pengelly <robertapengelly@hotmail.com>
Mon, 25 Nov 2024 20:27:17 +0000 (20:27 +0000)
committerRobert Pengelly <robertapengelly@hotmail.com>
Mon, 25 Nov 2024 20:27:17 +0000 (20:27 +0000)
21 files changed:
Makefile.p32
Makefile.pdw
Makefile.unix
Makefile.w32
elks.c
elks.h
ld.c
ld.h
lib.c
lib.h
link.c [new file with mode: 0644]
map.c [new file with mode: 0644]
pe.c [new file with mode: 0644]
pe.h
reloc.h [new file with mode: 0644]
report.c
report.h
section.c [new file with mode: 0644]
section.h [new file with mode: 0644]
symbol.c [new file with mode: 0644]
symbol.h [new file with mode: 0644]

index 40bbfc49cd2318b9ae3a6587529fbb42819525ef..2fc36a51777c8a6b2cd50b7fa2a29a7a1ee329fa 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=elks.c hashtab.o ld.o lib.o report.o vector.o write7x.o
+COBJ=elks.c hashtab.o ld.o lib.o link.o map.o pe.o report.o section.o symbol.o vector.o write7x.o
 
 all: clean slink.exe
 
index a1bee134a8f9f787768e85daea76d38e60552982..017e3f739624bbcbaed8a665a84ea27ad61bb78a 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=elks.c hashtab.o ld.o lib.o report.o vector.o write7x.o
+COBJ=elks.c hashtab.o ld.o lib.o link.o map.o pe.o report.o section.o symbol.o vector.o write7x.o
 
 all: clean slink.exe
 
index e9625c6904c318ce7315e11ba85386c5f571f87e..e49bb9aca91cc6b167d1a1bcef58d8689f10769c 100644 (file)
@@ -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                :=  elks.c hashtab.c ld.c lib.c report.c vector.c write7x.c
+CSRC                :=  elks.c hashtab.c ld.c lib.c link.c map.c pe.c report.c section.c symbol.c vector.c write7x.c
 
 ifeq ($(OS), Windows_NT)
 all: slink.exe
index f3aaa1c6229d6d804c368099ad0524a9d604280c..c9c024147e52d2560c3f14249d84e05c84b66a4e 100644 (file)
@@ -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                :=  elks.c hashtab.c ld.c lib.c report.c vector.c write7x.c
+CSRC                :=  elks.c hashtab.c ld.c lib.c link.c map.c pe.c report.c section.c symbol.c vector.c write7x.c
 
 all: slink.exe
 
diff --git a/elks.c b/elks.c
index dd181956ec8e53b25350eaaed760aabb68a255fc..2c17f534791802980265c2580850d52f745f8e4f 100644 (file)
--- a/elks.c
+++ b/elks.c
 /******************************************************************************
  * @file            elks.c
  *****************************************************************************/
-#include    <limits.h>
-#include    <stddef.h>
-#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    "reloc.h"
 #include    "report.h"
-#include    "write7x.h"
+#include    "section.h"
+#include    "symbol.h"
 
-typedef     signed char                 int8_t;
-typedef     signed short                int16_t;
+static void translate_relocation (const char *filename, struct reloc_entry *reloc, struct elks_relocation_info *input_reloc, struct section_part *part, struct elks_exec *exec_p) {
 
-#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;
-            
-            }
-        
-        }
+    unsigned long r_symbolnum = array_to_integer (input_reloc->r_symbolnum, 4);
     
-    }
-    
-    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 r_address = array_to_integer (input_reloc->r_address, 4);
+    long symbolnum = (r_symbolnum & 0x7ffffff);
     
-    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++) {
+    if ((r_symbolnum >> 31) & 1) {      /* ext */
+        reloc->symbol = part->of->symbol_arr + symbolnum;
+    } else {
     
-        struct elks_nlist *symbol = &object->symtab[i];
-        unsigned long final_slide = 0, n_value = GET_UINT32 (symbol->n_value);
+        if (state->format == LD_FORMAT_BIN || state->format == LD_FORMAT_COM) {
         
-        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;
+            if ((((r_symbolnum & (3 << 29)) >> 28) & 0xff) != N_ABS) {
+                report_at (program_name, 0, REPORT_ERROR, "%s: segment relocation at %04x:%04x", filename, r_address / 0xffff, r_address % 0xffff);
+            }
         
         }
         
-        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];
+        if (symbolnum == N_TEXT) {
+            reloc->symbol = part->of->symbol_arr + part->of->symbol_cnt - 3;
+        } else if (symbolnum == N_DATA) {
         
-        long r_address = GET_INT32 (rel->r_address);
-        r_address += object->text_slide;
+            reloc->symbol = part->of->symbol_arr + part->of->symbol_cnt - 2;
+            reloc->addend -= array_to_integer (exec_p->a_text, 4);
         
-        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];
+        } else if (symbolnum == N_BSS) {
         
-        long r_address = GET_INT32 (rel->r_address);
-        r_address += state->text_size + object->data_slide;
+            reloc->symbol = part->of->symbol_arr + part->of->symbol_cnt - 1;
+            reloc->addend -= (array_to_integer (exec_p->a_text, 4) + array_to_integer (exec_p->a_data, 4));
         
-        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 {
-    
-        if (state->format == LD_FORMAT_I386_PE) {
-            obj_text_size = ALIGN_UP (GET_UINT32 (header->a_text), FILE_ALIGNMENT);
-        } 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 {
-    
-        if (state->format == LD_FORMAT_I386_PE) {
-            obj_data_size = ALIGN_UP (GET_UINT32 (header->a_data), FILE_ALIGNMENT);
         } 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 {
-    
-        if (state->format == LD_FORMAT_I386_PE) {
-            obj_bss_size = ALIGN_UP (GET_UINT32 (header->a_bss), FILE_ALIGNMENT);
-        } 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;
+            report_at (program_name, 0, REPORT_INTERNAL_ERROR, "local input_reloc->r_symbolnum %#lx is not yet supported", symbolnum);
+            return;
         
-        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;
+    reloc->offset = r_address;
     
-    int far_call = 0, pcrel = 0, ext = 0, length = 0;
-    /*int need_relocate = 1;*/
+    switch (1U << ((r_symbolnum >> 29) & 3)) {
     
-    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 8:
         
-        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 (strcmp (symname, "__edata") == 0) {
-        
-            int32_t data_addr = ((char *) text - (char *) output) - header_size;
-            data_addr += state->text_size;
+            if ((r_symbolnum >> 28) & 1) {
             
-            write741_to_byte_array (symbol->n_value, data_addr / 16);
-            /*need_relocate = 0;*/
-        
-        } else if (strcmp (symname, "__end") == 0) {
-        
-            int32_t data_addr = ((char *) data - (char *) output) - header_size;
+                reloc->howto = &reloc_howtos[RELOC_TYPE_PC64];
+                reloc->addend += reloc->offset + 8;
             
-            data_addr += state->data_size;
-            data_addr += state->bss_size;
+            } else {
+                reloc->howto = &reloc_howtos[RELOC_TYPE_64];
+            }
             
-            write741_to_byte_array (symbol->n_value, data_addr % 16);
-            /*need_relocate = 0;*/
+            break;
         
-        } else if (!get_symbol (&symobj, &symidx, symname, 0)) {
-            symbol = &symobj->symtab[symidx];
-        } else {
-            return 1;
-        }
-    
-    }
-    
-    if (pcrel) {
-    
-        if (result == 0) {
-            result = (long) GET_UINT32 (symbol->n_value) - (GET_INT32 (r->r_address) + length);
-        }
-    
-    } else {
-    
-        if (!ext || (symbol->n_type & N_TYPE) == N_BSS || (symbol->n_type & N_TYPE) == N_DATA || (symbol->n_type & N_TYPE) == N_TEXT) {
+        case 4:
         
-            struct elks_relocation_info new_relocation;
+            if ((r_symbolnum >> 28) & 1) {
             
-            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_ELKS || state->format == LD_FORMAT_I386_ELKS || 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);
+                reloc->howto = &reloc_howtos[RELOC_TYPE_PC32];
+                reloc->addend += reloc->offset + 4;
             
+            } else {
+                reloc->howto = &reloc_howtos[RELOC_TYPE_32];
             }
             
-        }
+            break;
         
-        if (result == 0) {
+        case 2:
         
-            int32_t r_address = GET_INT32 (r->r_address);
+            if ((r_symbolnum >> 28) & 1) {
             
-            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);
+                reloc->howto = &reloc_howtos[RELOC_TYPE_PC16];
+                reloc->addend += reloc->offset + 2;
+            
+            } else {
+                reloc->howto = &reloc_howtos[RELOC_TYPE_16];
             }
-        
-        }
-        
-        if (ext) {
-        
-            symbolnum = (symbol->n_type & N_TYPE);
             
-            result += GET_UINT32 (symbol->n_value);
-            result += state->psp;
+            break;
         
-        } else {
+        case 1:
         
-            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) {
+            if ((r_symbolnum >> 28) & 1) {
             
-                result -= GET_UINT32 (object->header->a_data);
-                result += state->data_size;
-                result += objbsssize;
+                reloc->howto = &reloc_howtos[RELOC_TYPE_PC8];
+                reloc->addend += reloc->offset + 4;
             
+            } else {
+                reloc->howto = &reloc_howtos[RELOC_TYPE_8];
             }
             
-            result += state->psp;
-        
-        }
+            break;
     
     }
-    
-    number_to_chars (p, result, length);
-    return 0;
 
 }
 
-static int glue (struct elks_object *object) {
+void read_elks_object (const char *filename, unsigned char *data, unsigned long data_size) {
 
-    long i, err = 0;
-    
-    for (i = 0; i < object->trelocs_count; i++) {
-    
-        if (relocate (object, &object->trelocs[i], 0)) {
-            err = 1;
-        }
+    struct elks_exec *elks_exec;
+    struct elks_nlist *elks_nlist;
     
-    }
+    const char *strtab;
+    unsigned long strtab_size;
     
-    for (i = 0; i < object->drelocs_count; i++) {
+    unsigned long num_symbols;
+    unsigned long i;
     
-        if (relocate (object, &object->drelocs[i], 1)) {
-            err = 1;
-        }
+    struct section_part *part, *part_p_array[4] = { 0 };
+    struct section *section, *bss_section;
     
-    }
+    struct symbol *symbol, *old_symbol;
+    struct section_part *bss_part;
     
-    objtextsize += GET_UINT32 (object->header->a_text);
-    objdatasize += GET_UINT32 (object->header->a_data);
-    objbsssize  += GET_UINT32 (object->header->a_bss);
+    struct elks_relocation_info *reloc_info;
+    struct object_file *of;
     
-    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_ELKS || state->format == LD_FORMAT_I386_ELKS) {
-        header_size = sizeof (struct elks_exec);
-    }
+    unsigned char *pos = data;
     
-    if (!state->impure) {
-        header_size = ALIGN_UP (header_size, SECTION_ALIGNMENT);
-    }
+    if ((pos - data + sizeof (*elks_exec) > data_size) || pos < data) {
     
-    output_size = header_size + state->text_size + state->data_size;
+        report_at (program_name, 0, REPORT_FATAL_ERROR, "corrupted input file");
+        return;
     
-    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) {
+    elks_exec = (struct elks_exec *) pos;
+    pos += sizeof (*elks_exec);
     
-        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));
+    num_symbols = array_to_integer (elks_exec->a_syms, 4) / sizeof (*elks_nlist);
+    of = object_file_make (filename, num_symbols + 4);
     
-    } else if (state->format == LD_FORMAT_IA16_ELKS || state->format == LD_FORMAT_I386_ELKS) {
+    section = section_find_or_make (".text");
+    section->flags = SECTION_FLAG_ALLOC | SECTION_FLAG_LOAD | SECTION_FLAG_READONLY | SECTION_FLAG_CODE;
     
-        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 = (state->format == LD_FORMAT_I386_ELKS) ? 0x10 : 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)); 
+    part = section_part_new (section, of);
     
-    }
+    part->content_size = array_to_integer (elks_exec->a_text, 4);
+    part->content = xmalloc (part->content_size);
     
-    if (fwrite ((char *) output, output_size, 1, state->ofp) != 1) {
+    if ((pos - data + part->content_size > data_size) || pos < data) {
     
-        report_at (program_name, 0, REPORT_ERROR, "failed to write data to '%s'", state->ofile);
-        return 1;
+        report_at (program_name, 0, REPORT_FATAL_ERROR, "corrupted input file");
+        return;
     
     }
     
-    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_ELKS || state->format == LD_FORMAT_I386_ELKS) {
+    memcpy (part->content, pos, part->content_size);
+    pos += part->content_size;
     
-        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;
-            
-            }
-        
-        }
+    section_append_section_part (section, part);
+    part_p_array[1] = part;
     
-    }
+    section = section_find_or_make (".data");
+    section->flags = SECTION_FLAG_ALLOC | SECTION_FLAG_LOAD | SECTION_FLAG_DATA;
     
-    return 0;
-
-}
-
-
-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,
+    part = section_part_new (section, of);
     
-    0x69,   0x73,   0x20,   0x70,   0x72,   0x6F,   0x67,   0x72,
-    0x61,   0x6D,   0x20,   0x63,   0x61,   0x6E,   0x6E,   0x6F,
+    part->content_size = array_to_integer (elks_exec->a_data, 4);
+    part->content = xmalloc (part->content_size);
     
-    0x74,   0x20,   0x62,   0x65,   0x20,   0x72,   0x75,   0x6E,
-    0x20,   0x69,   0x6E,   0x20,   0x44,   0x4F,   0x53,   0x20,
+    if ((pos - data + part->content_size > data_size) || pos < data) {
     
-    0x6D,   0x6F,   0x64,   0x65,   0x2E,   0x0D,   0x0D,   0x0A,
-    0x24,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00,   0x00
-
-};
-
-static int no_sections = 0;
-
-static unsigned long bytearray_read_4_bytes (unsigned char *src) {
-
-    unsigned long value = 0;
-    int i;
+        report_at (program_name, 0, REPORT_FATAL_ERROR, "corrupted input file");
+        return;
     
-    for (i = 0; i < 4; i++) {
-        value |= (unsigned long) src[i] << (CHAR_BIT * i);
     }
     
-    return value;
-
-}
-
-static unsigned long pe_chksum (unsigned char *base, unsigned long chksum_off, unsigned long size) {
-
-    unsigned long checksum = 0, data, i;
-    int carry;
-    
-    for (i = 0; i < size / 4; i++) {
+    memcpy (part->content, pos, part->content_size);
+    pos += part->content_size;
     
-        if (i == chksum_off / 4) {
-            continue;
-        }
-        
-        data  = bytearray_read_4_bytes (base + i * 4);
-        
-        carry = checksum > 0xFFFFFFFFLU - data;
-        
-        checksum += data;
-        checksum += carry;
-        
-        checksum &= 0xFFFFFFFFLU;
+    section_append_section_part (section, part);
+    part_p_array[2] = part;
     
-    }
+    bss_section = section = section_find_or_make (".bss");
     
-    checksum = (checksum >> 16) + (checksum & 0xFFFF);
-    
-    checksum += checksum >> 16;
-    checksum &= 0xFFFF;
-    checksum += size;
-    
-    return checksum & 0xFFFFFFFFLU;
-
-}
-
-static int init_pe_object (void) {
-
-    header_size = sizeof (*doshdr) + sizeof (dos_stub) + sizeof (*pehdr) + sizeof (*opthdr);
+    section->flags = SECTION_FLAG_ALLOC;
+    section->is_bss = 1;
     
-    header_size += sizeof (*section_data);
-    header_size += sizeof (*section_text);
+    part = section_part_new (section, of);
+    part->content_size = array_to_integer (elks_exec->a_bss, 4);
     
-    no_sections = 0;
+    section_append_section_part (section, part);
+    part_p_array[3] = part;
     
-    if (state->raw_text_size > 0) {
-        no_sections++;
-    }
+    pos += array_to_integer (elks_exec->a_syms, 4) + array_to_integer (elks_exec->a_trsize, 4) + array_to_integer (elks_exec->a_drsize, 4);
     
-    if (state->raw_data_size > 0) {
-        no_sections++;
-    }
+    if ((unsigned long) (pos - data + 4) > data_size || pos < data) {
     
-    header_size = ALIGN_UP (header_size, FILE_ALIGNMENT);
-    output_size = header_size + state->text_size + state->data_size;
+        report_at (program_name, 0, REPORT_FATAL_ERROR, "corrupted input file");
+        return;
     
-    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, FILE_ALIGNMENT));
-    
-    return 0;
-
-}
-
-static int write_pe_object (unsigned long entry) {
-
-    unsigned long checksum_pos, size;
-    
-    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);
+    strtab_size = array_to_integer (pos, 4);
     
-    write721_to_byte_array (doshdr->e_maxalloc, 0xFFFF);
-    write721_to_byte_array (doshdr->e_sp, 0x00B8);
+    if (strtab_size < 4) {
     
-    write721_to_byte_array (doshdr->e_lfarlc, sizeof (*doshdr));
-    write741_to_byte_array (doshdr->e_lfanew, sizeof (*doshdr) + sizeof (dos_stub));
+        report_at (program_name, 0, REPORT_ERROR, "%s: invalid string table size %lu", filename, strtab_size);
+        return;
     
-    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));
-    
-    {
+    } else {
     
-        unsigned short characteristics = 0;
+        if ((pos - data + strtab_size > data_size) || pos < data) {
         
-        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;
+            report_at (program_name, 0, REPORT_FATAL_ERROR, "corrupted input file");
+            return;
         
-        write721_to_byte_array (pehdr->Characteristics, characteristics);
-    
-    }
-    
-    
-    write721_to_byte_array (opthdr->Magic, IMAGE_FILE_MAGIC_I386);
-    
-    opthdr->MajorLinkerVersion = 0;
-    opthdr->MinorLinkerVersion = 10;
-    
-    write741_to_byte_array (opthdr->SizeOfCode, state->text_size);
-    write741_to_byte_array (opthdr->SizeOfInitializedData, state->data_size);
-    write741_to_byte_array (opthdr->SizeOfUninitializedData, state->bss_size);
-    write741_to_byte_array (opthdr->AddressOfEntryPoint, ALIGN_UP ((char *) text - (char *) output, SECTION_ALIGNMENT) + entry);
-    
-    if (state->raw_text_size > 0) {
-        write741_to_byte_array (opthdr->BaseOfCode, ALIGN_UP (state->text_size, SECTION_ALIGNMENT));
-    }
+        }
+        
+        strtab = (char *) pos;
     
-    if (state->raw_data_size > 0) {
-        write741_to_byte_array (opthdr->BaseOfData, ALIGN_UP (state->data_size, SECTION_ALIGNMENT));
     }
     
-    write741_to_byte_array (opthdr->ImageBase, state->psp);
-    
-    write741_to_byte_array (opthdr->SectionAlignment, SECTION_ALIGNMENT);
-    write741_to_byte_array (opthdr->FileAlignment, FILE_ALIGNMENT);
-    
-    write721_to_byte_array (opthdr->MajorOperatingSystemVersion, 4);
-    write721_to_byte_array (opthdr->MajorImageVersion, 1);
-    write721_to_byte_array (opthdr->MajorSubsystemVersion, 4);
+    pos -= array_to_integer (elks_exec->a_syms, 4);
     
-    size = GET_UINT32 (opthdr->BaseOfCode) + GET_UINT32 (opthdr->SizeOfCode) + GET_UINT32 (opthdr->BaseOfData) + GET_UINT32 (opthdr->SizeOfInitializedData);
-    write741_to_byte_array (opthdr->SizeOfImage, ALIGN_UP (size, SECTION_ALIGNMENT));
+    for (i = 0; i < num_symbols; i++) {
     
-    write741_to_byte_array (opthdr->SizeOfHeaders, header_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;
+        elks_nlist = (struct elks_nlist *) (pos + (i * sizeof (*elks_nlist)));
+        symbol = of->symbol_arr + i;
         
-        unsigned long stack_addr = ibss_addr + ibss_size;
-        unsigned long stack_size = ALIGN_UP (stack_addr, SECTION_ALIGNMENT);
+        if (array_to_integer (elks_nlist->n_strx, 4) < strtab_size) {
+            symbol->name = xstrdup (strtab + array_to_integer (elks_nlist->n_strx, 4));
+        } else {
         
-        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);
+            report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid offset into string table", filename);
+            return;
         
-        write741_to_byte_array (section_text->VirtualSize, state->raw_text_size);
-        write741_to_byte_array (section_text->VirtualAddress, GET_UINT32 (opthdr->BaseOfCode));
-        write741_to_byte_array (section_text->SizeOfRawData, state->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;
+        symbol->value = array_to_integer (elks_nlist->n_value, 4);
+        symbol->size = 0;
         
-        write741_to_byte_array (section_text->Characteristics, characteristics);
-    
-    }
-    
-    if (state->raw_data_size > 0) {
-    
-        unsigned long characteristics = 0;
-        memcpy (section_text->Name, ".data", 5);
+        if ((elks_nlist->n_type & N_TYPE) == N_UNDF || (elks_nlist->n_type & N_TYPE) == N_COMM) {
         
-        write741_to_byte_array (section_data->VirtualSize, state->raw_data_size);
-        write741_to_byte_array (section_data->VirtualAddress, GET_UINT32 (opthdr->BaseOfData));
-        write741_to_byte_array (section_data->SizeOfRawData, state->data_size);
-        write741_to_byte_array (section_data->PointerToRawData, ((char *) data - (char *) output));
+            if (symbol->value) {
+            
+                old_symbol = symbol_find (symbol->name);
+                
+                if (!old_symbol || symbol_is_undefined (old_symbol)) {
+                
+                    bss_part = section_part_new (bss_section, of);
+                    section_append_section_part (bss_section, bss_part);
+                    
+                    bss_part->content_size = symbol->size = symbol->value;
+                    
+                    symbol->part = bss_part;
+                    symbol->value = 0;
+                    symbol->section_number = 3;
+                
+                } else {
+                
+                    if (symbol->value > old_symbol->size) {
+                        old_symbol->part->content_size = old_symbol->size = symbol->value;
+                    }
+                    
+                    symbol->part = 0;
+                    symbol->value = 0;
+                    symbol->section_number = UNDEFINED_SECTION_NUMBER;
+                
+                }
+            
+            } else {
+            
+                symbol->section_number = UNDEFINED_SECTION_NUMBER;
+                symbol->part = 0;
+            
+            }
         
-        characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
-        characteristics |= IMAGE_SCN_ALIGN_4BYTES;
-        characteristics |= IMAGE_SCN_MEM_READ;
-        characteristics |= IMAGE_SCN_MEM_WRITE;
+        } else if ((elks_nlist->n_type & N_TYPE) == N_ABS) {
         
-        write741_to_byte_array (section_data->Characteristics, characteristics);
-    
-    }
-    
-    checksum_pos = sizeof (*doshdr) + sizeof (dos_stub) + sizeof (*pehdr) + offsetof (struct pe_optional_header, Checksum);
-    write741_to_byte_array (opthdr->Checksum, pe_chksum (output, checksum_pos, output_size));
-    
-    
-    /* 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;
-    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;
+            symbol->section_number = ABSOLUTE_SECTION_NUMBER;
+            symbol->part = 0;
         
-        if ((output = malloc (output_size)) == NULL) {
-            return EXIT_FAILURE;
-        }
+        } else if ((elks_nlist->n_type & N_TYPE) == N_TEXT) {
         
-        memset (output, 0, output_size);
+            symbol->section_number = 1;
+            symbol->part = part_p_array[1];
         
-        text = (void *) (char *) output;
-        data = (void *) ((char *) text + state->text_size);
-    
-    } else if (state->format == LD_FORMAT_IA16_ELKS || state->format == LD_FORMAT_I386_ELKS || state->format == LD_FORMAT_I386_AOUT) {
-    
-        if (init_elks_object ()) {
+        } else if ((elks_nlist->n_type & N_TYPE) == N_DATA) {
         
-            report_at (program_name, 0, REPORT_ERROR, "failed to initialize a.out object");
-            return EXIT_FAILURE;
+            symbol->section_number = 2;
+            symbol->part = part_p_array[2];
+            symbol->value -= array_to_integer (elks_exec->a_text, 4);
         
-        }
-    
-    } else if (state->format == LD_FORMAT_I386_PE) {
-    
-        if (init_pe_object ()) {
+        } else if ((elks_nlist->n_type & N_TYPE) == N_BSS) {
         
-            report_at (program_name, 0, REPORT_ERROR, "failed to initialize pe object");
-            return EXIT_FAILURE;
+            symbol->section_number = 3;
+            symbol->part = part_p_array[3];
+            symbol->value -= (array_to_integer (elks_exec->a_text, 4) + array_to_integer (elks_exec->a_data, 4));
         
-        }
-    
-    }
-    
-    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) {
-    
-        if (state->format == LD_FORMAT_I386_PE) {
-            state->bss_size = ALIGN_UP (state->bss_size, FILE_ALIGNMENT);
         } else {
-            state->bss_size = ALIGN_UP (state->bss_size, SECTION_ALIGNMENT);
+        
+            report_at (program_name, 0, REPORT_INTERNAL_ERROR, "unsupported nlist.n_type: %#x", elks_nlist->n_type);
+            return;
+        
         }
-    
-    }
-    
-    for (i = 0; i < state->nb_elks_objs; ++i) {
-    
-        if (glue (state->elks_objs[i])) {
-            err = 1;
+        
+        if ((elks_nlist->n_type & N_EXT) || (elks_nlist->n_type & N_TYPE) == N_UNDF || (elks_nlist->n_type & N_TYPE) == N_COMM) {
+            symbol_record_external_symbol (symbol);
         }
     
     }
     
-    if (err) {
-        return EXIT_FAILURE;
-    }
+    for (i = 1; i < 4; i++) {
     
-    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 ();
-    }
-    
-    for (i = 0; i < state->nb_elks_objs; i++) {
-    
-        if ((object = state->elks_objs[i]) == NULL) {
-            return EXIT_FAILURE;
-        }
+        symbol = of->symbol_arr + num_symbols + i;
+        part = part_p_array[i];
         
-        /*if (state->mapfile) {
-            init_map (object);
-        }*/
-        
-        free (object->raw);
-        free (object);
+        symbol->name = xstrdup (part->section->name);
+        symbol->value = 0;
+        symbol->size = 0;
+        symbol->part = part;
+        symbol->section_number = i;
     
     }
     
-    state->nb_elks_objs = 0;
-    
-    /*if (state->mapfile) {
+    pos -= (array_to_integer (elks_exec->a_trsize, 4) + array_to_integer (elks_exec->a_drsize, 4));
+    part = part_p_array[1];
     
-        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 ();
+    part->reloc_cnt = array_to_integer (elks_exec->a_trsize, 4) / sizeof (*reloc_info);
+    part->reloc_arr = xmalloc (sizeof (*part->reloc_arr) * part->reloc_cnt);
     
-    }*/
+    for (i = 0; i < part->reloc_cnt; i++) {
     
-    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;
+        reloc_info = (struct elks_relocation_info *) (pos + (sizeof (*reloc_info) * i));
+        translate_relocation (filename, part->reloc_arr + i, reloc_info, part, elks_exec);
     
     }
     
-    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;
-        
-        }
+    pos += array_to_integer (elks_exec->a_trsize, 4);
+    part = part_p_array[2];
     
-    } else if (state->format == LD_FORMAT_IA16_ELKS || state->format == LD_FORMAT_I386_ELKS || state->format == LD_FORMAT_I386_AOUT) {
+    part->reloc_cnt = array_to_integer (elks_exec->a_drsize, 4) / sizeof (*reloc_info);
+    part->reloc_arr = xmalloc (sizeof (*part->reloc_arr) * part->reloc_cnt);
     
-        if (write_elks_object (entry)) {
-        
-            report_at (program_name, 0, REPORT_ERROR, "failed to write a.out object");
-            return EXIT_FAILURE;
-        
-        }
+    for (i = 0; i < part->reloc_cnt; i++) {
     
-    } else if (state->format == LD_FORMAT_I386_PE) {
+        reloc_info = (struct elks_relocation_info *) (pos + (sizeof (*reloc_info) * i));
+        translate_relocation (filename, part->reloc_arr + i, reloc_info, part, elks_exec);
     
-        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/elks.h b/elks.h
index dfbe08f749a0931b395d9f8d41107ebf5aa756c9..2a592d3e6b184223df9ee35fb24d6a517b45b736 100644 (file)
--- a/elks.h
+++ b/elks.h
@@ -32,6 +32,7 @@ struct elks_exec {
 #define     N_TEXT                      0x04
 #define     N_DATA                      0x06
 #define     N_BSS                       0x08
+#define     N_COMM                      0x12
 
 struct elks_relocation_info {
 
@@ -55,8 +56,8 @@ struct elks_nlist {
 };
 
 #define     N_TYPE                      0x1e
-int create_executable_from_elks_objects (void);
-
 #define     ELKS_MAGIC                  0403
 
+void read_elks_object (const char *filename, unsigned char *data, unsigned long data_size);
+
 #endif      /* _ELKS_H */
diff --git a/ld.c b/ld.c
index 27d2886922cf14950c62079aa58778556e148af5..19c6c23944f7c507d97be7fc0d057212ec7ffc9f 100644 (file)
--- a/ld.c
+++ b/ld.c
 #include    <string.h>
 
 #include    "elks.h"
-#include    "hashtab.h"
 #include    "ld.h"
 #include    "lib.h"
+#include    "pe.h"
 #include    "report.h"
-#include    "vector.h"
+#include    "section.h"
 
 struct ld_state *state = 0;
 const char *program_name = 0;
 
 static void cleanup (void) {
 
-    long i;
-    
-    if (state->ofp) {
-        fclose (state->ofp);
-    }
-    
     if (get_error_count () > 0) {
     
-        if (state->ofile) {
-            remove (state->ofile);
-        }
-    
-    }
-    
-    for (i = 0; i < state->nb_elks_objs; ++i) {
-    
-        struct elks_object *obj = state->elks_objs[i];
-        
-        if (obj == NULL) {
-            continue;
+        if (state->output_filename) {
+            remove (state->output_filename);
         }
-        
-        if (obj->raw != NULL) {
-            free (obj->raw);
-        }
-        
-        free (obj);
-    
-    }
-
-}
-
-
-static unsigned long conv_dec (char *str, long max) {
-
-    unsigned long value = 0;
-    
-    while (*str != ' ' && max-- > 0) {
-    
-        value *= 10;
-        value += *str++ - '0';
     
     }
-    
-    return value;
 
 }
 
-static struct hashtab hashtab_globals = { 0 };
-static struct vector vec_undef = { 0 };
-
-static int process_elks (void *obj, unsigned long sz, const char *fname, int quiet) {
+static int read_file_into_memory (const char *filename, unsigned char **memory_p, unsigned long *size_p) {
 
-    struct elks_exec *hdr = obj;
-    
-    struct elks_object *data_obj;
-    struct elks_nlist *symtab;
-    
-    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;
-    
-    char *strtab;
-    long i;
+    unsigned char *memory;
+    FILE *fp;
     
-    if (!(hdr->a_magic[0] == ((ELKS_MAGIC >> 8) & 0xff) && hdr->a_magic[1] == (ELKS_MAGIC & 0xff))) {
+    unsigned long mem_size;
     
-        if (!quiet) {
-            report_at (program_name, 0, REPORT_ERROR, "'%s' is not a valid object", fname);
-        }
-        
+    if (!(fp = fopen (filename, "rb"))) {
         return 1;
-    
     }
     
-    /*for (i = 0; i < state->nb_elks_objs; ++i) {
-    
-        struct elks_object *obj_to_compare = state->elks_objs[i];
-        
-        if (obj_to_compare->size != sz) {
-            continue;
-        }
-        
-        if (memcmp (obj_to_compare->raw, obj, sz) == 0) {
-            return 0;
-        }
-    
-    }*/
+    fseek (fp, 0, SEEK_END);
+    mem_size = ftell (fp);
     
-    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);
+    fseek (fp, 0, SEEK_SET);
+    memory = xmalloc (mem_size);
     
-    if (state->impure) {
+    if (fread (memory, mem_size, 1, fp) != 1) {
     
-        state->text_size    += GET_UINT32 (hdr->a_text);
-        state->data_size    += GET_UINT32 (hdr->a_data);
-        state->bss_size     += GET_UINT32 (hdr->a_bss);
-    
-    } else {
-    
-        if (state->format == LD_FORMAT_I386_PE) {
-        
-            state->text_size    += ALIGN_UP (GET_UINT32 (hdr->a_text),  FILE_ALIGNMENT);
-            state->data_size    += ALIGN_UP (GET_UINT32 (hdr->a_data),  FILE_ALIGNMENT);
-            state->bss_size     += ALIGN_UP (GET_UINT32 (hdr->a_bss),   FILE_ALIGNMENT);
-        
-        } else {
+        fclose (fp);
         
-            state->text_size    += ALIGN_UP (GET_UINT32 (hdr->a_text),  SECTION_ALIGNMENT);
-            state->data_size    += ALIGN_UP (GET_UINT32 (hdr->a_data),  SECTION_ALIGNMENT);
-            state->bss_size     += ALIGN_UP (GET_UINT32 (hdr->a_bss),   SECTION_ALIGNMENT);
-        
-        }
-    
-    }
-    
-    trelocs_off     = sizeof (*hdr) + GET_UINT32 (hdr->a_text) + GET_UINT32 (hdr->a_data);
-    drelocs_off     = trelocs_off + GET_UINT32 (hdr->a_trsize);
-    symtab_off      = drelocs_off + GET_UINT32 (hdr->a_drsize);
-    strtab_off      = symtab_off + GET_UINT32 (hdr->a_syms);
-    
-    trelocs_count   = GET_UINT32 (hdr->a_trsize) / sizeof (*trelocs);
-    drelocs_count   = GET_UINT32 (hdr->a_drsize) / sizeof (*drelocs);
-    symtab_count    = GET_UINT32 (hdr->a_syms) / sizeof (*symtab);
-    
-    trelocs = (void *) ((char *) obj + trelocs_off);
-    drelocs = (void *) ((char *) obj + drelocs_off);
-    symtab  = (void *) ((char *) obj + symtab_off);
-    strtab  = (char *) obj + strtab_off;
-    
-    if (!(data_obj = malloc (sizeof (*data_obj)))) {
+        free (memory);
         return 1;
-    }
-    
-    memset (data_obj, 0, sizeof (*data_obj));
     
-    data_obj->filename = fname;
-    data_obj->header = hdr;
-    data_obj->raw = obj;
-    data_obj->size = sz;
-    
-    data_obj->trelocs = trelocs;
-    data_obj->drelocs = drelocs;
-    data_obj->symtab = symtab;
-    data_obj->strtab = strtab;
-    data_obj->trelocs_count = trelocs_count;
-    data_obj->drelocs_count = drelocs_count;
-    data_obj->symtab_count = symtab_count;
-    
-    dynarray_add (&state->elks_objs, &state->nb_elks_objs, data_obj);
-    
-    for (i = 0; i < symtab_count; ++i) {
+    }
     
-        struct elks_nlist *sym = &symtab[i];
-        char *symname = strtab + GET_INT32 (sym->n_strx);
-        
-        if ((sym->n_type & N_TYPE) == N_UNDF) {
-            vec_push (&vec_undef, (void *) symname);
-        } else if (sym->n_type == 5 || sym->n_type == 7 || sym->n_type == 9) {
-        
-            struct hashtab_name *key;
-            
-            if ((key = hashtab_alloc_name (symname)) == NULL) {
-            
-                free (key);
-                
-                report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory (memory full)");
-                return 1;
-            
-            }
-            
-            if (hashtab_get (&hashtab_globals, key) != NULL) {
-            
-                free (key);
-                continue;
-            
-            }
-            
-            hashtab_put (&hashtab_globals, key, symname);
-        
-        }
+    fclose (fp);
     
-    }
+    *memory_p = memory;
+    *size_p = mem_size;
     
     return 0;
 
 }
 
-struct ar_header {
+static void read_input_file (const char *filename) {
 
-    char name[16];
-    char mtime[12];
-    char owner[6];
-    char group[6];
-    char mode[8];
-    char size[10];
-    char endsig[2];
-
-};
-
-static int read_ar_obj (FILE *ar_file, const char *root_fname, unsigned long index) {
-
-    struct ar_header hdr;
-    unsigned long sz, sz_aligned;
-    
-    int i;
+    unsigned char *data;
+    unsigned long data_size;
     
-    char *fname, *path;
-    void *obj;
+    if (read_file_into_memory (filename, &data, &data_size)) {
     
-    if ((fname = malloc (17)) == NULL) {
+        report_at (program_name, 0, REPORT_ERROR, "failed to read file '%s' into memory", filename);
+        return;
     
-        report_at (program_name, 0, REPORT_ERROR, "failed to allocation memory (memory full)");
-        return 1;
+    }
     
+    if (data[0] == ((ELKS_MAGIC >> 8) & 0xff) && data[1] == (ELKS_MAGIC & 0xff)) {
+        read_elks_object (filename, data, data_size);
+    } else {
+        report_at (program_name, 0, REPORT_ERROR, "'%s' is not a valid object", filename);
     }
     
-    fseek (ar_file, index, SEEK_SET);
+    free (data);
+
+}
+
+int main (int argc, char **argv) {
+
+    long i;
     
-    if (fread (&hdr, sizeof (hdr), 1, ar_file) != 1) {
+    if (argc && *argv) {
     
-        if (feof (ar_file)) {
-            return 0;
-        }
+        char *p;
+        program_name = *argv;
         
-        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", root_fname);
-        return 1;
+        if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) {
+            program_name = (p + 1);
+        }
     
     }
     
-    sz = conv_dec (hdr.size, 10);
-    sz_aligned = (sz % 2) ? (sz + 1) : sz;
+    atexit (cleanup);
     
-    memcpy (fname, hdr.name, 16);
+    state = xmalloc (sizeof (*state));
+    parse_args (argc, argv, 1);
     
-    for (i = 0; i < 16; ++i) {
+    if (state->nb_input_files == 0) {
     
-        if (fname[i] == 0x20 || fname[i] == '/') {
-        
-            fname[i] = '\0';
-            break;
-        
-        }
+        report_at (program_name, 0, REPORT_ERROR, "no input files provided");
+        exit (EXIT_FAILURE);
     
     }
     
-    if ((obj = malloc (sz_aligned)) == NULL) {
+    if (state->format == LD_FORMAT_I386_AOUT || state->format == LD_FORMAT_I386_ELKS || state->format == LD_FORMAT_IA16_ELKS) {
     
-        report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory (memory full)");
-        return 1;
+        section_find_or_make (".text");
+        section_find_or_make (".data");
+        section_find_or_make (".bss");
     
     }
     
-    if (fread (obj, sz_aligned, 1, ar_file) != 1) {
-    
-        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", root_fname);
-        free (obj);
-        
-        return 1;
+    if (!state->output_filename) {
+        state->output_filename = "a.out";
+    }
     
+    for (i = 0; i < state->nb_input_files; i++) {
+        read_input_file (state->input_files[i]);
     }
     
-    if (fname) {
+    if (get_error_count () > 0) { return EXIT_FAILURE; }
+    sections_destroy_empty_before_collapse ();
     
-        unsigned long len = strlen (root_fname) + 1 + strlen (fname) + 2;
-        
-        if ((path = malloc (len)) == NULL) {
-        
-            report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory (memory full)");
-            free (obj);
-            
-            return 1;
-        
-        }
-        
-        memset (path, 0, len);
-        sprintf (path, "%s(%s)", root_fname, fname);
-        
-        if (process_elks (obj, sz, path, 1)) {
-        
-            free (obj);
-            return 1;
-        
-        }
+    if (!state->use_custom_base_address) {
     
-    } else {
-    
-        if (process_elks (obj, sz, "", 1)) {
-        
-            free (obj);
-            return 1;
-        
+        if (state->format == LD_FORMAT_COM) {
+            state->base_address = 0x00000100;
+        } else if (state->format == LD_FORMAT_I386_PE) {
+            state->base_address = 0x00400000;
         }
     
     }
     
-    free (fname);
-    return 0;
-
-}
-
-static int process_archive (FILE *ar_file, const char *root_fname) {
-
-    struct vector vec_undef2 = { 0 };
-    char *fname, *path;
-    
-    void *obj;
-    
-    if ((fname = malloc (17)) == NULL) {
-    
-        report_at (program_name, 0, REPORT_ERROR, "failed to allocation memory (memory full)");
-        return 1;
-    
+    if (state->format == LD_FORMAT_I386_PE) {
+        pe_before_link ();
     }
     
-    if (fseek (ar_file, 8, SEEK_SET) != 0) {
-    
-        report_at (program_name, 0, REPORT_ERROR, "failed whilst seeking '%s'", root_fname);
-        return 1;
+    link ();
     
+    if (get_error_count () > 0) {
+        return EXIT_FAILURE;
     }
     
-    for (;;) {
+    if (state->format == LD_FORMAT_BIN || state->format == LD_FORMAT_COM) {
     
-        struct ar_header hdr;
+        FILE *fp;
         
-        int err, i;
-        unsigned long sz, sz_aligned;
+        unsigned char *data;
+        unsigned long data_size = 0;
         
-        if (fread (&hdr, sizeof (hdr), 1, ar_file) != 1) {
+        struct section *section;
         
-            if (feof (ar_file)) {
-                break;
-            }
-            
-            report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", root_fname);
-            return 1;
+        if (!(fp = fopen (state->output_filename, "wb"))) {
         
-        }
-            
-        sz = conv_dec (hdr.size, 10);
-        sz_aligned = (sz % 2) ? (sz + 1) : sz;
-        
-        if (memcmp (hdr.name, "__.SYMDEF", 9) == 0 || memcmp (hdr.name, "/", 1) == 0) {
-        
-            unsigned char temp[4], *temp3;
-            unsigned long cnt, j, k, *temp2;
-            
-            if (fread (temp, 4, 1, ar_file) != 1) {
-            
-                report_at (program_name, 0, REPORT_ERROR, "failed to read symdef count");
-                return 1;
-            
-            }
-            
-            cnt = (unsigned long) temp[3] | (((unsigned long) temp[2]) << 8) | (((unsigned long) temp[1]) << 16) | (((unsigned long) temp[0]) << 24);
-            sz -= 4;
-            
-            if ((temp2 = (unsigned long *) malloc (cnt * sizeof (unsigned long))) == NULL) {
-            
-                report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory (memory full)");
-                return 1;
-            
-            }
-            
-            for (j = 0; j < cnt; ++j) {
-            
-                if (fread (temp, 4, 1, ar_file) != 1) {
-                
-                    report_at (program_name, 0, REPORT_ERROR, "failed to read symdef index");
-                    return 1;
-                
-                }
-                
-                temp2[j] = (unsigned long) temp[3] | (((unsigned long) temp[2]) << 8) | (((unsigned long) temp[1]) << 16) | (((unsigned long) temp[0]) << 24);
-            
-            }
-            
-            sz -= cnt * 4;
-            
-            if ((temp3 = (unsigned char *) malloc (sz)) == NULL) {
-            
-                report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory (memory full)");
-                return 1;
-            
-            }
-            
-            if (fread (temp3, sz, 1, ar_file) != 1) {
-            
-                report_at (program_name, 0, REPORT_ERROR, "failed to read symdef symbols");
-                return 1;
-            
-            }
-            
-            while (vec_undef.length > 0) {
-            
-                char *symname = (char *) vec_pop (&vec_undef);
-                
-                struct hashtab_name *key;
-                char *temp;
-                
-                if ((key = hashtab_alloc_name (symname)) == NULL) {
-                
-                    report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory (memory full)");
-                    return 1;
-                
-                }
-                
-                if ((temp = hashtab_get (&hashtab_globals, key)) != NULL) {
-                
-                    if (strcmp (temp, symname) != 0) {
-                    
-                        free (key);
-                        
-                        report_at (program_name, 0, REPORT_ERROR, "hashtab collison");
-                        return 1;
-                    
-                    }
-                    
-                    continue;
-                
-                }
-                
-                free (key);
-                
-                for (j = 0, k = 0; k < sz; ) {
-                
-                    unsigned long len = strlen ((char *) temp3 + k) + 1;
-                    
-                    if (strcmp ((char *) temp3 + k, symname) == 0) {
-                        break;
-                    }
-                    
-                    k += len;
-                    j++;
-                
-                }
-                
-                if (j >= cnt) {
-                
-                    vec_push (&vec_undef2, symname);
-                    continue;
-                
-                }
-                
-                if (read_ar_obj (ar_file, root_fname, temp2[j])) {
-                
-                    report_at (program_name, 0, REPORT_ERROR, "failed whilst reading ar object");
-                    return 1;
-                
-                }
-            
-            }
-            
-            memcpy (&vec_undef, &vec_undef2, sizeof (vec_undef));
-            return 0;
+            report_at (program_name, 0, REPORT_ERROR, "cannot open '%s' for writing", state->output_filename);
+            return EXIT_FAILURE;
         
         }
         
-        memcpy (fname, hdr.name, 16);
+        for (section = all_sections; section; section = section->next) {
         
-        for (i = 0; i < 16; ++i) {
-        
-            if (fname[i] == 0x20 || fname[i] == '/') {
-            
-                fname[i] = '\0';
-                break;
-            
+            if (data_size < section->rva + section->total_size) {
+                data_size = section->rva + section->total_size;
             }
         
         }
         
-        if ((obj = malloc (sz_aligned)) == NULL) {
-        
-            report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory (memory full)");
-            return 1;
-        
-        }
-        
-        if (fread (obj, sz_aligned, 1, ar_file) != 1) {
+        data = xmalloc (data_size);
         
-            report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", root_fname);
-            free (obj);
-            
-            return 1;
-        
-        }
+        for (section = all_sections; section; section = section->next) {
         
-        if (fname) {
-        
-            unsigned long len = strlen (root_fname) + 1 + strlen (fname) + 2;
-            
-            if ((path = malloc (len)) == NULL) {
-            
-                report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory (memory full)");
-                free (obj);
-                
-                return 1;
-            
+            if (section->is_bss) {
+                continue;
             }
             
-            memset (path, 0, len);
-            sprintf (path, "%s(%s)", root_fname, fname);
-            
-            if ((err = process_elks (obj, sz, path, 1))) {
-                free (obj);
-            }
-        
-        } else {
-        
-            if ((err = process_elks (obj, sz, "", 1))) {
-                free (obj);
-            }
+            section_write (section, data + section->rva);
         
         }
         
-        obj = NULL;
-    
-    }
-    
-    free (fname);
-    return 0;
-
-}
-
-static int process_file (const char *fname) {
-
-    FILE *ifp;
-    void *obj;
-    
-    char *ar_magic[8];
-    long obj_sz;
-    
-    int err;
-    
-    if ((ifp = fopen (fname, "rb")) == NULL) {
-    
-        report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for reading", fname);
-        return 1;
-    
-    }
-    
-    if (fread (ar_magic, 8, 1, ifp) != 1) {
-    
-        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", fname);
-        fclose (ifp);
-        
-        return 1;
-    
-    }
-    
-    if (memcmp (ar_magic, "!<arch>\n", 8) == 0) {
-    
-        int err = process_archive (ifp, fname);
-        fclose (ifp);
-        
-        if (err) {
-            return EXIT_FAILURE;
-        }
-        
-        return EXIT_SUCCESS;
-    
-    }
-    
-    if (fseek (ifp, 0, SEEK_END) != 0) {
-    
-        report_at (program_name, 0, REPORT_ERROR, "failed whist seeking '%s'", fname);
-        fclose (ifp);
-        
-        return 1;
-    
-    }
-    
-    if ((obj_sz = ftell (ifp)) == -1) {
-    
-        report_at (program_name, 0, REPORT_ERROR, "size of '%s' is -1", fname);
-        fclose (ifp);
-        
-        return 1;
-    
-    }
-    
-    rewind (ifp);
-    
-    if ((obj = malloc (obj_sz)) == NULL) {
-    
-        report_at (program_name, 0, REPORT_ERROR, "failed to allocation memory (memory full)");
-        fclose (ifp);
-        
-        return 1;
-    
-    }
-    
-    if (fread (obj, obj_sz, 1, ifp) != 1) {
-    
-        report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", fname);
-        free (obj);
-        
-        fclose (ifp);
-        return 1;
-    
-    }
-    
-    if ((err = process_elks (obj, obj_sz, fname, 1))) {
-    
-        report_at (fname, 0, REPORT_ERROR, "file format not recognized");
-        free (obj);
-        
-        fclose (ifp);
-        return 1;
-    
-    }
-    
-    fclose (ifp);
-    return 0;
-
-}
-
-int main (int argc, char **argv) {
-
-    long i;
-    
-    if (argc && *argv) {
-    
-        char *p;
-        program_name = *argv;
-        
-        if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) {
-            program_name = (p + 1);
-        }
-    
-    }
-    
-    atexit (cleanup);
-    
-    state = xmalloc (sizeof (*state));
-    parse_args (argc, argv, 1);
-    
-    if (state->nb_files == 0) {
-    
-        report_at (program_name, 0, REPORT_ERROR, "no input files provided");
-        exit (EXIT_FAILURE);
-    
-    }
-    
-    if (!state->entry || strcmp (state->entry, "") == 0) {
-        state->entry = "_start";
-    }
-    
-    if (!state->ofile) {
-        state->ofile = xstrdup ("a.out");
-    }
-    
-    if (state->format == LD_FORMAT_BIN || state->format == LD_FORMAT_COM || state->format == LD_FORMAT_IA16_ELKS || state->format == LD_FORMAT_I386_ELKS) {
-    
-        if (state->format == LD_FORMAT_COM) {
-            state->psp = 0x100;
+        if (fwrite (data, data_size, 1, fp) != 1) {
+            report_at (program_name, 0, REPORT_ERROR, "failed to write data to '%s'", state->output_filename);
         }
         
-        state->impure = 1;
-    
-    } else if (state->format == LD_FORMAT_I386_PE) {
-        state->psp = 0x00400000;
-    }
-    
-    for (i = 0; i < state->nb_files; i++) {
-    
-        if (process_file (state->files[i])) {
-            return EXIT_FAILURE;
-        }
-    
-    }
+        free (data);
+        fclose (fp);
     
-    if (state->format == LD_FORMAT_IA16_ELKS) {
+    }/* 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) {
+        elks_write (state->output_filename);
+    }*/ else if (state->format == LD_FORMAT_I386_PE) {
     
-        if (state->text_size > 65536L || state->data_size > 65536L || (state->text_size + state->data_size) > 65536L) {
-        
-            report_at (program_name, 0, REPORT_ERROR, "binary to large for elks-ia16");
-            return EXIT_FAILURE;
-        
-        }
+        pe_after_link ();
+        pe_write (state->output_filename);
     
     }
     
-    if (state->nb_elks_objs > 0) {
-    
-        if (create_executable_from_elks_objects ()) {
-            return EXIT_FAILURE;
-        }
-    
+    if (state->output_map_filename) {
+        map_write (state->output_map_filename);
     }
     
-    return EXIT_SUCCESS;
+    return (get_error_count () > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
 
 }
diff --git a/ld.h b/ld.h
index cf5710fd1697b2e91d076ab8381f6a4753622c24..ddfdf9e36da2a9d9629b1d3ad8eb09091d23d8a8 100644 (file)
--- a/ld.h
+++ b/ld.h
@@ -4,52 +4,24 @@
 #ifndef     _LD_H
 #define     _LD_H
 
-#include    "aout.h"
-
-struct elks_object {
-
-    const char *filename;
-    void *raw;
-    
-    unsigned long size;
-    
-    struct elks_exec *header;
-    struct elks_relocation_info *trelocs, *drelocs;
-    
-    struct elks_nlist *symtab;
-    char *strtab;
-    
-    long symtab_count, trelocs_count, drelocs_count;
-    unsigned long text_slide, data_slide, bss_slide;
-
-};
-
-#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))
-
-#include    <stdio.h>
+#define     FAKE_LD_FILENAME            "autogenerated"
 
 struct ld_state {
 
-    const char **files;
-    long nb_files;
-    
-    const char *ofile;
-    FILE *ofp;
+    const char **input_files;
+    long nb_input_files;
     
-    int format, impure;
-    int psp;
+    const char *entry_symbol_name;
+    unsigned long entry_point;
     
-    struct elks_object **elks_objs;
-    long nb_elks_objs;
+    const char *output_map_filename;
+    unsigned long base_address;
     
-    unsigned long raw_text_size, raw_data_size, raw_bss_size;
-    unsigned long text_size, data_size, bss_size;
+    const char *output_filename;
+    int create_shared_library, format;
     
-    unsigned long subsystem;
-    char *entry;
+    int emit_relocs, use_custom_base_address;
+    unsigned long size_of_headers;
 
 };
 
@@ -57,18 +29,15 @@ struct ld_state {
 #define     LD_FORMAT_BIN               0x01
 
 #define     LD_FORMAT_IA16_ELKS         0x02
-#define     LD_FORMAT_I386_ELKS         0x04
+#define     LD_FORMAT_I386_ELKS         0x03
 
-#define     LD_FORMAT_I386_AOUT         0x08
-#define     LD_FORMAT_I386_PE           0x10
+#define     LD_FORMAT_I386_AOUT         0x04
+#define     LD_FORMAT_I386_PE           0x05
 
 extern struct ld_state *state;
 extern const char *program_name;
 
-#define     SECTION_ALIGNMENT           4096
-#define     FILE_ALIGNMENT              512
-
-#define     DIV_ROUNDUP(a, b)           (((a) + ((b) - 1)) / (b))
-#define     ALIGN_UP(x, a)              (DIV_ROUNDUP ((x), (a)) * (a))
+void map_write (const char *filename);
+void link (void);
 
 #endif      /* _LD_H */
diff --git a/lib.c b/lib.c
index 7aeac3610fe7ffe8923f342ee58020223fbb2016..1da8663ca99c4fc83084cd24c32829a21f39f383 100644 (file)
--- a/lib.c
+++ b/lib.c
 
 #include    "ld.h"
 #include    "lib.h"
+#include    "pe.h"
 #include    "report.h"
 
-#if     defined (_WIN32)
-# define    PATHSEP                     ';'
-#else
-# define    PATHSEP                     ':'
-#endif
+struct options_with_use {
 
-struct ld_option {
-
-    const char *name;
-    int idx, flgs;
+    int (*check_option) (const char *cmd_arg, int argc, char **argv, int *optind, const char **optarg);
+    void (*use_option) (const char *cmd_arg, int idx, const char *optarg);
 
 };
 
-#define     LD_OPTION_NO_ARG            0
-#define     LD_OPTION_HAS_ARG           1
+static struct options_with_use fmt_tbl[] = {
+
+    {   0,                      0               },
+    {   0,                      0               },
+    {   0,                      0               },
+    {   0,                      0               },
+    {   0,                      0               },
+    {   &pe_check_option,       &pe_use_option  }
+
+};
 
-#define     LD_OPTION_NONE              0
-#define     LD_OPTION_ENTRY             1
-#define     LD_OPTION_FORMAT            2
-#define     LD_OPTION_HELP              3
-#define     LD_OPTION_IMPURE            4
-#define     LD_OPTION_MAP               5
-#define     LD_OPTION_OUTFILE           6
-#define     LD_OPTION_PSP               7
-#define     LD_OPTION_SUBSYSTEM         8
+#define     LD_OPTION_IGNORED           0
+#define     LD_OPTION_EMIT_RELOCS       1
+#define     LD_OPTION_ENTRY             2
+#define     LD_OPTION_FORMAT            3
+#define     LD_OPTION_HELP              4
+#define     LD_OPTION_IMAGE_BASE        5
+#define     LD_OPTION_MAP               6
+#define     LD_OPTION_MAP_FILE          7
+#define     LD_OPTION_OUTFILE           8
 
 static struct ld_option opts[] = {
 
-    {   "-N",               LD_OPTION_IMPURE,       LD_OPTION_NO_ARG    },
-    {   "-T",               LD_OPTION_PSP,          LD_OPTION_HAS_ARG   },
+    {   "-M",                   LD_OPTION_MAP,              LD_OPTION_NO_ARG    },
+    {   "-Map",                 LD_OPTION_MAP_FILE,         LD_OPTION_HAS_ARG   },
+    {   "-N",                   LD_OPTION_IGNORED,          LD_OPTION_NO_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   },
+    {   "-s",                   LD_OPTION_IGNORED,          LD_OPTION_NO_ARG    },
+    {   "-q",                   LD_OPTION_EMIT_RELOCS,      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                   }
+    {   "--emit_relocs",        LD_OPTION_EMIT_RELOCS,      LD_OPTION_NO_ARG    },
+    {   "--entry",              LD_OPTION_ENTRY,            LD_OPTION_HAS_ARG   },
+    {   "--help",               LD_OPTION_HELP,             LD_OPTION_NO_ARG    },
+    {   "--image_base",         LD_OPTION_IMAGE_BASE,       LD_OPTION_HAS_ARG   },
+    {   "--oformat",            LD_OPTION_FORMAT,           LD_OPTION_HAS_ARG   },
+    {   "--omagic",             LD_OPTION_IGNORED,          LD_OPTION_NO_ARG    },
+    {   "--output",             LD_OPTION_OUTFILE,          LD_OPTION_HAS_ARG   },
+    {   "--print-map",          LD_OPTION_MAP,              LD_OPTION_NO_ARG    },
+    {   "--strip-all",          LD_OPTION_IGNORED,          LD_OPTION_NO_ARG    },
+    
+    
+    {   0,                      0,                          0                   }
 
 };
 
@@ -62,22 +76,206 @@ static void print_usage (void) {
         fprintf (stderr, "Usage: %s [options] file...\n\n", program_name);
         fprintf (stderr, "Options:\n\n");
         
-        fprintf (stderr, "    -N                    Do not page align data.\n");
-        fprintf (stderr, "    -T OFFSET             Offset addresses by the specified offset.\n");
+        fprintf (stderr, "    -e ADDRESS, --entry ADDRESS       Set start address.\n");
+        fprintf (stderr, "    -q, --emit-relocs                 Generate relocations in final output.\n");
+        fprintf (stderr, "    -s, --strip-all                   Ignored.\n");
+        
+        fprintf (stderr, "\n");
+        
+        fprintf (stderr, "    -M, --print-map                   Print map file on standard output.\n");
+        fprintf (stderr, "    -N, --omagic                      Ignored.\n");
         
-        fprintf (stderr, "    --oformat FORMAT      Specify the format of output file (default msdos)\n");
-        fprintf (stderr, "                              Supported formats are:\n");
-        fprintf (stderr, "                                  a.out-i386, elks-ia16, elks-i386,\n");
-        fprintf (stderr, "                                  binary, msdos\n");
+        fprintf (stderr, "\n");
+        fprintf (stderr, "    -Map FILE                         Write a linker map to FILE.\n");
         
-        fprintf (stderr, "    -e ADDRESS            Set start address.\n");
-        fprintf (stderr, "    -s                    Ignored.\n");
+        fprintf (stderr, "\n");
         
-        fprintf (stderr, "    -o FILE               Set output file name (default a.out).\n");
-        fprintf (stderr, "    --help                Print this help information.\n");
+        fprintf (stderr, "    --help                            Print option help.\n");
+        fprintf (stderr, "    --oformat FORMAT                  Specify the format of output file (default msdos)\n");
+        fprintf (stderr, "                                          Supported formats are:\n");
+        /*fprintf (stderr, "                                              a.out-i386, elks-ia16, elks-i386,\n");*/
+        fprintf (stderr, "                                              pe-i386, binary, msdos\n");
+        fprintf (stderr, "    --image-base <address>            Set base address of the executable.\n");
         
         fprintf (stderr, "\n");
+        pe_print_help ();
+        fprintf (stderr, "\n");
+    
+    }
+
+}
+
+static void use_option (const char *cmd_arg, int idx, const char *optarg) {
+
+    switch (idx) {
+    
+        case LD_OPTION_IGNORED: {
+        
+            break;
+        
+        }
+        
+        case LD_OPTION_EMIT_RELOCS: {
+        
+            state->emit_relocs = 1;
+            break;
+        
+        }
+        
+        case LD_OPTION_ENTRY: {
+        
+            char *p;
+            state->entry_point = strtoul (optarg, &p, 0);
+            
+            if (p == optarg + strlen (optarg)) {
+                state->entry_symbol_name = "";
+            } else {
+            
+                state->entry_point = 0;
+                state->entry_symbol_name = optarg;
+            
+            }
+            
+            break;
+        
+        }
+        
+        case LD_OPTION_FORMAT: {
+        
+            if (xstrcasecmp (optarg, "binary") == 0) {
+            
+                state->format = LD_FORMAT_BIN;
+                break;
+            
+            }
+            
+            if (xstrcasecmp (optarg, "msdos") == 0) {
+            
+                state->format = LD_FORMAT_COM;
+                break;
+            
+            }
+            
+            /*if (xstrcasecmp (optarg, "elks-ia16") == 0) {
+            
+                state->format = LD_FORMAT_IA16_ELKS;
+                break;
+            
+            }*/
+            
+            /*if (xstrcasecmp (optarg, "elks-i386") == 0) {
+            
+                state->format = LD_FORMAT_I386_ELKS;
+                break;
+            
+            }*/
+            
+            /*if (xstrcasecmp (optarg, "a.out-i386") == 0) {
+            
+                state->format = LD_FORMAT_I386_AOUT;
+                break;
+            
+            }*/
+            
+            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);
+        
+        }
+        
+        case LD_OPTION_HELP: {
+        
+            print_usage ();
+            exit (EXIT_SUCCESS);
+        
+        }
+        
+        case LD_OPTION_IMAGE_BASE: {
+        
+            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 base address");
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            state->base_address = (unsigned long) conversion;
+            state->use_custom_base_address = 1;
+            
+            break;
+        
+        }
+        
+        case LD_OPTION_MAP: {
+        
+            state->output_map_filename = "";
+            break;
+        
+        }
+        
+        case LD_OPTION_MAP_FILE: {
+        
+            state->output_map_filename = optarg;
+            break;
+        
+        }
+        
+        case LD_OPTION_OUTFILE: {
+        
+            if (state->output_filename) {
+            
+                report_at (program_name, 0, REPORT_ERROR, "multiple output files provided");
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            state->output_filename = optarg;
+            break;
+        
+        }
+        
+        default: {
+        
+            report_at (program_name, 0, REPORT_ERROR, "unsupported option '%s'", cmd_arg);
+            exit (EXIT_FAILURE);
+        
+        }
+    
+    }
+
+}
+
+unsigned long array_to_integer (unsigned char *arr, int size) {
+
+    unsigned long value = 0;
+    int i;
+    
+    for (i = 0; i < size; i++) {
+        value |= arr[i] << (CHAR_BIT * i);
+    }
+    
+    return value;
+
+}
+
+void integer_to_array (unsigned long value, unsigned char *dest, int size) {
+
+    int i;
     
+    for (i = 0; i < size; i++) {
+        dest[i] = (value >> (CHAR_BIT * i)) & UCHAR_MAX;
     }
 
 }
@@ -166,7 +364,9 @@ void dynarray_add (void *ptab, long *nb_ptr, void *data) {
 
 void parse_args (int argc, char **argv, int optind) {
 
+    struct options_with_use *options_with_use;
     struct ld_option *popt;
+    
     const char *optarg, *r;
     
     if (argc <= optind) {
@@ -176,15 +376,13 @@ void parse_args (int argc, char **argv, int optind) {
     
     }
     
-    state->subsystem = 3;
-    
     while (optind < argc) {
     
         r = argv[optind++];
         
         if (r[0] != '-' || r[1] == '\0') {
         
-            dynarray_add (&state->files, &state->nb_files, xstrdup (r));
+            dynarray_add (&state->input_files, &state->nb_input_files, xstrdup (r));
             continue;
         
         }
@@ -195,10 +393,7 @@ void parse_args (int argc, char **argv, int optind) {
             const char *r1 = r;
             
             if (!p1) {
-            
-                report_at (program_name, 0, REPORT_ERROR, "invalid option -- '%s'", r);
-                exit (EXIT_FAILURE);
-            
+                break;    
             }
             
             if (!strstart (p1, &r1)) {
@@ -230,155 +425,32 @@ void parse_args (int argc, char **argv, int optind) {
         
         }
         
-        switch (popt->idx) {
+        if (popt && popt->name) {
         
-            case LD_OPTION_ENTRY: {
-            
-                if (state->entry) {
-                    free (state->entry);
-                }
-                
-                state->entry = xstrdup (optarg);
-                break;
-            
-            }
-            
-            case LD_OPTION_FORMAT: {
-            
-                if (xstrcasecmp (optarg, "binary") == 0) {
-                
-                    state->format = LD_FORMAT_BIN;
-                    break;
-                
-                }
-                
-                if (xstrcasecmp (optarg, "msdos") == 0) {
-                
-                    state->format = LD_FORMAT_COM;
-                    break;
-                
-                }
-                
-                if (xstrcasecmp (optarg, "elks-ia16") == 0) {
-                
-                    state->format = LD_FORMAT_IA16_ELKS;
-                    break;
-                
-                }
-                
-                if (xstrcasecmp (optarg, "elks-i386") == 0) {
-                
-                    state->format = LD_FORMAT_I386_ELKS;
-                    break;
-                
-                }
-                
-                if (xstrcasecmp (optarg, "a.out-i386") == 0) {
-                
-                    state->format = LD_FORMAT_I386_AOUT;
-                    break;
-                
-                }
-                
-                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);
-            
-            }
-            
-            case LD_OPTION_HELP: {
-            
-                print_usage ();
-                exit (EXIT_SUCCESS);
-            
-            }
-            
-            case LD_OPTION_IMPURE: {
-            
-                state->impure = 1;
-                break;
-            
-            }
-            
-            case LD_OPTION_OUTFILE: {
-            
-                if (state->ofile) {
-                
-                    report_at (program_name, 0, REPORT_ERROR, "multiple output files provided");
-                    exit (EXIT_FAILURE);
-                
-                }
-                
-                state->ofile = xstrdup (optarg);
-                break;
-            
-            }
-            
-            case LD_OPTION_PSP: {
-            
-                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 text start");
-                    exit (EXIT_FAILURE);
-                
-                }
-                
-                if (conversion < 0 || conversion > LONG_MAX) {
-                
-                    report_at (program_name, 0, REPORT_ERROR, "text start must be between 0 and %u", ULONG_MAX);
-                    exit (EXIT_FAILURE);
-                
-                }
-                
-                state->psp = (unsigned long) conversion;
-                break;
-            
-            }
-            
-            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;
-            
-            }
+            use_option (r, popt->idx, optarg);
+            continue;
+        
+        }
+        
+        options_with_use = &fmt_tbl[state->format];
+        
+        if (options_with_use->check_option && options_with_use->use_option) {
+        
+            int idx;
             
-            default: {
+            if ((idx = options_with_use->check_option (r, argc, argv, &optind, &optarg)) >= 0) {
             
-                report_at (program_name, 0, REPORT_ERROR, "unsupported option '%s'", r);
-                exit (EXIT_FAILURE);
+                options_with_use->use_option (r, idx, optarg);
+                continue;
             
             }
         
         }
+        
+        report_at (program_name, 0, REPORT_ERROR, "invalid option -- '%s'", r);
+        exit (EXIT_FAILURE);
     
     }
-    
-    if (!state->ofile) { state->ofile = "a.out"; }
 
 }
 
diff --git a/lib.h b/lib.h
index 1f82f9855b933c94ab4aefe833f8b56c00025b3b..ad1f86002b5c4f11588e1ace3e3df0e34102029f 100644 (file)
--- a/lib.h
+++ b/lib.h
@@ -4,6 +4,21 @@
 #ifndef     _LIB_H
 #define     _LIB_H
 
+#define     ALIGN(a, b)                 (((a) / (b) + (((a) % (b)) ? 1 : 0)) * (b))
+
+struct ld_option {
+
+    const char *name;
+    int idx, flgs;
+
+};
+
+#define     LD_OPTION_NO_ARG            0
+#define     LD_OPTION_HAS_ARG           1
+
+unsigned long array_to_integer (unsigned char *arr, int size);
+void integer_to_array (unsigned long value, unsigned char *dest, int size);
+
 int xstrcasecmp (const char *__s1, const char *__s2);
 
 int strstart (const char *val, const char **str);
diff --git a/link.c b/link.c
new file mode 100644 (file)
index 0000000..2573f94
--- /dev/null
+++ b/link.c
@@ -0,0 +1,449 @@
+/******************************************************************************
+ * @file            link.c
+ *****************************************************************************/
+#include    <limits.h>
+#include    <string.h>
+
+#include    "ld.h"
+#include    "lib.h"
+#include    "pe.h"
+#include    "reloc.h"
+#include    "report.h"
+#include    "section.h"
+#include    "symbol.h"
+
+struct reloc_howto reloc_howtos[RELOC_TYPE_END] = {
+
+    {   0,  0,  0,  0,  0,  "RELOC_TYPE_IGNORED",   0,  0   },
+    
+    {   8,  0,  0,  0,  0,  "RELOC_TYPE_64",        0,  0   },
+    {   8,  1,  0,  0,  0,  "RELOC_TYPE_PC64",      0,  0   },
+    
+    {   4,  0,  0,  0,  0,  "RELOC_TYPE_32",        0,  0   },
+    {   4,  1,  0,  0,  0,  "RELOC_TYPE_PC32",      0,  0   },
+    
+    {   2,  0,  0,  0,  0,  "RELOC_TYPE_16",        0,  0   },
+    {   2,  1,  0,  0,  0,  "RELOC_TYPE_PC16",      0,  0   },
+    
+    {   1,  0,  0,  0,  0,  "RELOC_TYPE_8",         0,  0   },
+    {   1,  1,  0,  0,  0,  "RELOC_TYPE_PC8",       0,  0   }
+
+};
+
+static void check_unresolved (void) {
+
+    struct object_file *of;
+    struct symbol *symbol;
+    
+    unsigned long i;
+    unsigned long unresolved = 0;
+    
+    for (of = all_object_files; of; of = of->next) {
+    
+        for (i = 0; i < of->symbol_cnt; i++) {
+        
+            symbol = of->symbol_arr + i;
+            
+            if (symbol->auxiliary || !symbol_is_undefined (symbol) || (symbol->flags & SYMBOL_FLAG_SECTION_SYMBOL) || !symbol->name) {
+                continue;
+            }
+            
+            if (!(symbol = symbol_find (symbol->name))) {
+            
+                symbol = of->symbol_arr + i;
+                report_at (program_name, 0, REPORT_INTERNAL_ERROR, "external symbol '%s' not found in hashtab", symbol->name);
+            
+            }
+            
+            if (symbol_is_undefined (symbol)) {
+            
+                report_at (program_name, 0, REPORT_ERROR, "%s: unresolved external symbol '%s'", of->filename, symbol->name);
+                unresolved++;
+            
+            }
+        
+        }
+    
+    }
+    
+    if (unresolved) {
+        report_at (program_name, 0, REPORT_FATAL_ERROR, "%lu unresolved external%s", unresolved, (unresolved > 1 ? "s" : ""));
+    }
+
+}
+
+static void collapse_subsections (void) {
+
+    struct section *section;
+    struct subsection *subsection;
+    
+    for (section = all_sections; section; section = section->next) {
+    
+        for (subsection = section->all_subsections; subsection; subsection = subsection->next) {
+        
+            if (subsection->first_part) {
+            
+                *section->last_part_p = subsection->first_part;
+                section->last_part_p = subsection->last_part_p;
+            
+            }
+        
+        }
+    
+    }
+
+}
+
+static void calculate_section_sizes_and_rvas (void) {
+
+    struct section *section;
+    struct section_part *part;
+    
+    unsigned long rva = 0;
+    
+    if (state->format == LD_FORMAT_I386_PE) {
+        rva = pe_get_first_section_rva ();
+    }
+    
+    for (section = all_sections; section; section = section->next) {
+    
+        rva = ALIGN (rva, section->section_alignment);
+        
+        section->rva = rva;
+        section->total_size = 0;
+        
+        for (part = section->first_part; part; part = part->next) {
+        
+            if (part->next && part->next->alignment > 1) {
+            
+                unsigned long new_rva = ALIGN (rva + part->content_size, part->next->alignment);
+                
+                if (new_rva != rva + part->content_size) {
+                
+                    part->content = xrealloc (part->content, new_rva - rva);
+                    memset (part->content + part->content_size, 0, new_rva - rva - part->content_size);
+                    
+                    part->content_size = new_rva - rva;
+                
+                }
+            
+            }
+            
+            part->rva = rva;
+            
+            section->total_size += part->content_size;
+            rva += part->content_size;
+        
+        }
+    
+    }
+
+}
+
+static void reloc_generic (struct section_part *part, struct reloc_entry *rel, struct symbol *symbol) {
+
+    unsigned long result = 0;
+    
+    switch (rel->howto->size) {
+    
+        case 8: {
+        
+            result = array_to_integer (part->content + rel->offset, 8);
+            break;
+        
+        }
+        
+        case 4: {
+        
+            result = array_to_integer (part->content + rel->offset, 4);
+            break;
+        
+        }
+        
+        case 3: {
+        
+            result = array_to_integer (part->content + rel->offset, 3);
+            break;
+        
+        }
+        
+        case 2: {
+        
+            result = array_to_integer (part->content + rel->offset, 2);
+            break;
+        
+        }
+        
+        case 1: {
+        
+            result = array_to_integer (part->content + rel->offset, 1);
+            break;
+        
+        }
+        
+        default: {
+        
+            report_at (program_name, 0, REPORT_INTERNAL_ERROR, "invalid relocation size");
+            break;
+        
+        }
+    
+    }
+    
+    result += rel->addend;
+    
+    if (rel->howto->pc_rel || rel->howto->no_base) {
+    
+        result += symbol_get_value_no_base (symbol);
+        
+        if (rel->howto->pc_rel) {
+        
+            result -= (part->rva + rel->offset);
+            result -= rel->howto->size;
+        
+        }
+    
+    } else {
+        result += symbol_get_value_with_base (symbol);
+    }
+    
+    if ((unsigned long) rel->howto->size < sizeof (result)) {
+    
+        unsigned long mask = (((unsigned long) 1) << (CHAR_BIT * rel->howto->size)) - 1;
+        result &= mask;
+    
+    }
+    
+    result >>= rel->howto->final_right_shift;
+    
+    switch (rel->howto->size) {
+    
+        case 8: {
+        
+            integer_to_array (result, part->content + rel->offset, 8);
+            break;
+        
+        }
+        
+        case 4: {
+        
+            integer_to_array (result, part->content + rel->offset, 4);
+            break;
+        
+        }
+        
+        case 3: {
+        
+            integer_to_array (result, part->content + rel->offset, 3);
+            break;
+        
+        }
+        
+        case 2: {
+        
+            integer_to_array (result, part->content + rel->offset, 2);
+            break;
+        
+        }
+        
+        case 1: {
+        
+            integer_to_array (result, part->content + rel->offset, 1);
+            break;
+        
+        }
+        
+        default: {
+        
+            report_at (program_name, 0, REPORT_INTERNAL_ERROR, "invalid relocation size");
+            break;
+        
+        }
+    
+    }
+
+}
+
+static void relocate_part (struct section_part *part) {
+
+    struct reloc_entry *relocs = part->reloc_arr;
+    
+    struct symbol *symbol;
+    unsigned long i;
+    
+    for (i = 0; i < part->reloc_cnt; i++) {
+    
+        if (relocs[i].howto->size == 0) {
+            continue;
+        }
+        
+        symbol = relocs[i].symbol;
+        
+        if (symbol_is_undefined (symbol)) {
+        
+            if (!(symbol = symbol_find (symbol->name))) {
+            
+                symbol = relocs[i].symbol;
+                report_at (program_name, 0, REPORT_INTERNAL_ERROR, "external symbol '%s' not found in hashtab", symbol->name);
+            
+            }
+            
+            if (symbol_is_undefined (symbol)) {
+            
+                report_at (program_name, 0, REPORT_ERROR, "%s:(%s+%#lu): undefined reference to '%s'", part->of->filename, part->section->name, relocs[i].offset, symbol->name);
+                continue;
+            
+            }
+        
+        }
+        
+        if (relocs[i].howto->special_function) {
+        
+            (*relocs[i].howto->special_function) (part, &relocs[i], symbol);
+            continue;
+        
+        }
+        
+        reloc_generic (part, &relocs[i], symbol);
+    
+    }
+
+}
+
+static void relocate_sections (void) {
+
+    struct section *section;
+    struct section_part *part;
+    
+    for (section = all_sections; section; section = section->next) {
+    
+        for (part = section->first_part; part; part = part->next) {
+            relocate_part (part);
+        }
+    
+    }
+
+}
+
+static void calculate_entry_point (void) {
+
+    struct symbol *symbol;
+    struct section *section;
+    
+    if (state->entry_symbol_name) {
+    
+        if (state->entry_symbol_name[0] == '\0') {
+        
+            state->entry_point -= state->base_address;
+            return;
+        
+        }
+        
+        if ((symbol = symbol_find (state->entry_symbol_name)) && !symbol_is_undefined (symbol)) {
+        
+            state->entry_point = symbol_get_value_no_base (symbol);
+            return;
+        
+        }
+    
+    }
+    
+    if (!state->entry_symbol_name) {
+    
+        if (state->format == LD_FORMAT_I386_AOUT || state->format == LD_FORMAT_I386_ELKS || state->format == LD_FORMAT_IA16_ELKS) {
+        
+            state->entry_symbol_name = xstrdup ("_start");
+            
+            if ((symbol = symbol_find (state->entry_symbol_name))) {
+            
+                state->entry_point = symbol_get_value_no_base (symbol);
+                return;
+            
+            }
+        
+        } else if (state->format == LD_FORMAT_I386_PE) {
+        
+            state->entry_symbol_name = xstrdup ("_mainCRTStartup");
+            
+            if ((symbol = symbol_find (state->entry_symbol_name))) {
+            
+                state->entry_point = symbol_get_value_no_base (symbol);
+                return;
+            
+            }
+        
+        }
+    
+    }
+    
+    if ((section = section_find (".text"))) {
+        state->entry_point = section->rva;
+    }
+    
+    if (state->entry_symbol_name) {
+        report_at (program_name, 0, REPORT_WARNING, "cannot find entry symbol '%s'; defaulting to 0x%08lx", state->entry_symbol_name, state->base_address + state->entry_point);
+    }
+
+}
+
+void link (void) {
+
+    struct section *section;
+    unsigned long value = 0;
+    
+    struct object_file *of;
+    struct symbol *symbol;
+    
+    collapse_subsections ();
+    calculate_section_sizes_and_rvas ();
+    
+    if (!(symbol = symbol_find ("__edata")) || symbol_is_undefined (symbol)) {
+    
+        if ((section = section_find (".text"))) {
+        
+            value += (/*section->rva + */section->total_size);
+            /*value -= state->size_of_headers;*/
+        
+        }
+        
+        of = object_file_make (FAKE_LD_FILENAME, 1);
+        
+        symbol = of->symbol_arr;
+        symbol->name = xstrdup ("__edata");
+        
+        symbol->section_number = ABSOLUTE_SECTION_NUMBER;
+        symbol->value = value / 16;
+        
+        symbol_record_external_symbol (symbol);
+        value %= 16;
+    
+    }
+    
+    if (!(symbol = symbol_find ("__end")) || symbol_is_undefined (symbol)) {
+    
+        if ((section = section_find (".data"))) {
+            value += section->total_size;
+        }
+        
+        if ((section = section_find (".bss"))) {
+            value += section->total_size;
+        }
+        
+        of = object_file_make (FAKE_LD_FILENAME, 1);
+        
+        symbol = of->symbol_arr;
+        symbol->name = xstrdup ("__end");
+        
+        symbol->section_number = ABSOLUTE_SECTION_NUMBER;
+        symbol->value = value % 16;
+        
+        symbol_record_external_symbol (symbol);
+    
+    }
+    
+    check_unresolved ();
+    
+    relocate_sections ();
+    calculate_entry_point ();
+
+}
diff --git a/map.c b/map.c
new file mode 100644 (file)
index 0000000..f3ca848
--- /dev/null
+++ b/map.c
@@ -0,0 +1,128 @@
+/******************************************************************************
+ * @file            map.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+#include    "ld.h"
+#include    "report.h"
+#include    "section.h"
+#include    "symbol.h"
+
+static int symbol_compare (const void *a, const void *b) {
+
+    const struct symbol *sa = a, *sb = b;
+    
+    if (sa->auxiliary && sb->auxiliary) {
+        return 0;
+    }
+    
+    if (sa->auxiliary) {
+        return 1;
+    }
+    
+    if (sb->auxiliary) {
+        return -1;
+    }
+    
+    if (symbol_get_value_with_base (sa) < symbol_get_value_with_base (sb)) {
+        return -1;
+    }
+    
+    if (symbol_get_value_with_base (sa) > symbol_get_value_with_base (sb)) {
+        return 1;
+    }
+    
+    return 0;
+
+}
+
+static void sort_symbols (void) {
+
+    struct object_file *of;
+    
+    for (of = all_object_files; of; of = of->next) {
+        qsort (of->symbol_arr, of->symbol_cnt, sizeof (*of->symbol_arr), &symbol_compare);
+    }
+
+}
+
+void map_write (const char *filename) {
+
+    FILE *fp;
+    
+    struct symbol *symbol;
+    struct section *section;
+    struct section_part *part;
+    
+    int printed_chars;
+    
+    if (strcmp (filename, "") == 0) {
+        fp = stdout;
+    } else if (!(fp = fopen (filename, "wb"))) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "cannot open '%s' for writing", filename);
+        return;
+    
+    }
+    
+    sort_symbols ();
+    
+    for (section = all_sections; section; section = section->next) {
+    
+        if ((printed_chars = fprintf (fp, "%-16s", section->name)) > 16) {
+            fprintf (fp, "\n%-16s", "");
+        }
+        
+        fprintf (fp, "0x%08lx  %12lu\n\n", state->base_address + section->rva, section->total_size);
+        
+        for (part = section->first_part; part; part = part->next) {
+        
+            if ((printed_chars = fprintf (fp, "    %-12s", section->name)) > 16) {
+                fprintf (fp, "\n%-16s", "");
+            }
+            
+            fprintf (fp, "0x%08lx  %12lu %s\n", state->base_address + part->rva, part->content_size, part->of->filename);
+            
+            for (symbol = part->of->symbol_arr; symbol < part->of->symbol_arr + part->of->symbol_cnt; symbol++) {
+            
+                if (symbol->auxiliary || symbol->part != part) {
+                    continue;
+                }
+                
+                if (symbol->value == 0 || strncmp (section->name, symbol->name, strlen (section->name)) == 0) {
+                    continue;
+                }
+                
+                fprintf (fp, "%-16s %12lu %10s %s\n", "", symbol_get_value_with_base (symbol), "", symbol->name);
+            
+            }
+        
+        }
+        
+        fprintf (fp, "\n");
+    
+    }
+    
+    fprintf (fp, "\n");
+    
+    {
+    
+        struct section *last_section = 0;
+        
+        for (section = all_sections; section; section = section->next) {
+            last_section = section;
+        }
+        
+        fprintf (fp, "Sizeof Module: %lu bytes\n", last_section ? (last_section->rva + last_section->total_size) : 0);
+    
+    }
+    
+    fprintf (fp, "Entry Point: 0x%08lx\n", state->base_address + state->entry_point);
+    
+    if (strcmp (filename, "") != 0) {
+        fclose (fp);
+    }
+
+}
diff --git a/pe.c b/pe.c
new file mode 100644 (file)
index 0000000..dee77cc
--- /dev/null
+++ b/pe.c
@@ -0,0 +1,872 @@
+/******************************************************************************
+ * @file            pe.c
+ *****************************************************************************/
+#include    <ctype.h>
+#include    <errno.h>
+#include    <limits.h>
+#include    <stddef.h>
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+#include    <time.h>
+
+#include    "ld.h"
+#include    "lib.h"
+#include    "pe.h"
+#include    "report.h"
+#include    "section.h"
+#include    "write7x.h"
+
+static unsigned short subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
+
+static unsigned long section_alignment = DEFAULT_SECTION_ALIGNMENT;
+static unsigned long file_alignment = DEFAULT_FILE_ALIGNMENT;
+
+struct exclude_symbol {
+
+    char *name;
+    struct exclude_symbol *next;
+
+};
+
+static struct exclude_symbol *exclude_symbols = 0;
+
+#define     LD_OPTION_IGNORED                               0
+#define     LD_OPTION_FILE_ALIGNMENT                        1
+#define     LD_OPTION_SECTION_ALIGNMENT                     2
+#define     LD_OPTION_STACK                                 3
+#define     LD_OPTION_SUBSYSTEM                             4
+
+static struct ld_option opts[] = {
+
+    {   "--file-alignment",         LD_OPTION_FILE_ALIGNMENT,       LD_OPTION_HAS_ARG   },
+    {   "--section-alignment",      LD_OPTION_SECTION_ALIGNMENT,    LD_OPTION_HAS_ARG   },
+    {   "--subsystem",              LD_OPTION_SUBSYSTEM,            LD_OPTION_HAS_ARG   },
+    
+    
+    {   0,                          0,                              0                   }
+
+};
+
+int pe_check_option (const char *cmd_arg, int argc, char **argv, int *optind, const char **optarg) {
+
+    struct ld_option *popt;
+    
+    for (popt = opts; ; popt++) {
+    
+        const char *p1 = popt->name;
+        const char *r1 = cmd_arg;
+        
+        if (!p1) {
+            break;    
+        }
+        
+        if (!strstart (p1, &r1)) {
+            continue;
+        }
+        
+        (*optarg) = r1;
+        
+        if (popt->flgs & LD_OPTION_HAS_ARG) {
+        
+            if (*r1 == '\0') {
+            
+                if ((*optind) >= argc) {
+                
+                    report_at (program_name, 0, REPORT_ERROR, "argument to '%s' is missing", cmd_arg);
+                    exit (EXIT_FAILURE);
+                
+                }
+                
+                (*optarg) = argv[(*optind)++];
+            
+            }
+        
+        } else if (*r1 != '\0') {
+            continue;
+        }
+        
+        return popt->idx;
+    
+    }
+    
+    return -1;
+
+}
+
+void pe_use_option (const char *cmd_arg, int idx, const char *optarg) {
+
+    switch (idx) {
+    
+        case LD_OPTION_IGNORED: {
+        
+            break;
+        
+        }
+        
+        case LD_OPTION_FILE_ALIGNMENT: {
+        
+            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, "invalid file alignment number '%s'", optarg);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            file_alignment = (unsigned long) conversion;
+            
+            if (file_alignment < 512 || file_alignment > 0x10000 || (file_alignment & (file_alignment - 1))) {
+                report_at (program_name, 0, REPORT_WARNING, "file alignment should be a power of two between 512 and 64 KiB (0x10000) inclusive according to the specification");
+            }
+            
+            break;
+        
+        }
+        
+        case LD_OPTION_SECTION_ALIGNMENT: {
+        
+            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, "invalid section alignment number '%s'", optarg);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            section_alignment = (unsigned long) conversion;
+            
+            if (section_alignment < file_alignment) {
+                report_at (program_name, 0, REPORT_WARNING, "section alignment must be greater than or equal to file alignment according to the specification");
+            }
+            
+            break;
+        
+        }
+        
+        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, "invalid subsystem type '%s'", optarg);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            subsystem = (unsigned short) conversion;
+            break;
+        
+        }
+        
+        default: {
+        
+            report_at (program_name, 0, REPORT_ERROR, "unsupported option '%s'", cmd_arg);
+            exit (EXIT_FAILURE);
+        
+        }
+    
+    }
+
+}
+
+
+#define     NUMBER_OF_DATA_DIRECTORIES                      16
+
+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 generate_reloc_section = 1;
+static int can_be_relocated = 0;
+
+static struct section_part *iat_first_part = 0, *iat_last_part = 0;
+
+static int check_reloc_section_needed_section_part (struct section_part *part) {
+
+    struct reloc_howto *reloc_howto;
+    unsigned long i;
+    
+    for (i = 0; i < part->reloc_cnt; i++) {
+    
+        reloc_howto = part->reloc_arr[i].howto;
+        
+        if (reloc_howto == &reloc_howtos[RELOC_TYPE_64] || reloc_howto == &reloc_howtos[RELOC_TYPE_32]) {
+            return 1;
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int check_reloc_section_needed (void) {
+
+    struct section *section;
+    struct section_part *part;
+    struct subsection *subsection;
+    
+    for (section = all_sections; section; section = section->next) {
+    
+        for (part = section->first_part; part; part = part->next) {
+        
+            if (check_reloc_section_needed_section_part (part)) {
+                return 1;
+            }
+        
+        }
+        
+        for (subsection = section->all_subsections; subsection; subsection = subsection->next) {
+        
+            for (part = subsection->first_part; part; part = part->next) {
+            
+                if (check_reloc_section_needed_section_part (part)) {
+                    return 1;
+                }
+            
+            }
+        
+        }
+    
+    }
+    
+    return 0;
+
+}
+
+static int translate_characteristics_to_section_flags (unsigned long characteristics) {
+
+    int flags = 0;
+    
+    if (!(characteristics & IMAGE_SCN_MEM_WRITE)) {
+        flags |= SECTION_FLAG_READONLY;
+    }
+    
+    if (characteristics & (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE)) {
+        flags |= SECTION_FLAG_CODE;
+    }
+    
+    if (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) {
+        flags |= SECTION_FLAG_DATA;
+    }
+    
+    if (characteristics & IMAGE_SCN_TYPE_NOLOAD) {
+        flags |= SECTION_FLAG_NEVER_LOAD;
+    }
+    
+    if (characteristics & IMAGE_SCN_LNK_INFO) {
+        flags |= SECTION_FLAG_DEBUGGING;
+    }
+    
+    if (characteristics & IMAGE_SCN_LNK_REMOVE) {
+        flags |= SECTION_FLAG_EXCLUDE;
+    }
+    
+    if (!(characteristics & IMAGE_SCN_MEM_READ)) {
+        flags |= SECTION_FLAG_NOREAD;
+    }
+    
+    if (characteristics & IMAGE_SCN_MEM_SHARED) {
+        flags |= SECTION_FLAG_SHARED;
+    }
+    
+    if (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
+        flags |= SECTION_FLAG_ALLOC;
+    }
+    
+    return flags;
+
+}
+
+static void exclude_symbols_free (void) {
+
+    struct exclude_symbol *exclude_symbol;
+    
+    for (exclude_symbol = exclude_symbols; exclude_symbol; exclude_symbol = exclude_symbols) {
+    
+        exclude_symbols = exclude_symbol->next;
+        
+        free (exclude_symbol->name);
+        free (exclude_symbol);
+    
+    }
+
+}
+
+#define     FLOOR_TO(a, b)              ((a) / (b) * (b))
+
+static void generate_base_relocation_block (struct section *reloc_section, struct pe_base_relocation *ibr_hdr_p, unsigned long num_relocs, struct section *saved_section, struct section_part *saved_part, unsigned long saved_i) {
+
+    struct section_part *reloc_part;
+    struct reloc_entry *relocs;
+    
+    unsigned char *write_pos;
+    unsigned long i;
+    
+    struct section *section;
+    struct section_part *part;
+    
+    integer_to_array (ALIGN (sizeof (*ibr_hdr_p) + num_relocs * 2, 4), ibr_hdr_p->SizeOfBlock, 4);
+    
+    reloc_part = section_part_new (reloc_section, object_file_make (FAKE_LD_FILENAME, 0));
+    reloc_part->content_size = array_to_integer (ibr_hdr_p->SizeOfBlock, 4);
+    
+    reloc_part->content = xmalloc (reloc_part->content_size);
+    reloc_part->content[reloc_part->content_size - 2] = reloc_part->content[reloc_part->content_size - 1] = 0;
+    
+    memcpy (reloc_part->content, ibr_hdr_p, sizeof (*ibr_hdr_p));
+    write_pos = reloc_part->content + sizeof (*ibr_hdr_p);
+    
+    for (section = saved_section; section; section = section->next) {
+    
+        for (part = ((section = saved_section) ? saved_part : section->first_part); part; part = part->next) {
+        
+            relocs = part->reloc_arr;
+            
+            for (i = ((part == saved_part) ? saved_i : 0); i < part->reloc_cnt; i++) {
+            
+                unsigned short base_relocation_type, rel_word;
+                
+                if (relocs[i].howto == &reloc_howtos[RELOC_TYPE_64]) {
+                    base_relocation_type = IMAGE_REL_BASED_DIR64;
+                } else if (relocs[i].howto == &reloc_howtos[RELOC_TYPE_32]) {
+                    base_relocation_type = IMAGE_REL_BASED_HIGHLOW;
+                } else {
+                    continue;
+                }
+                
+                rel_word  = (part->rva + relocs[i].offset - array_to_integer (ibr_hdr_p->RVAOfBlock, 4)) & 0xfff;
+                rel_word |= base_relocation_type << 12;
+                
+                integer_to_array (rel_word, write_pos, 2);
+                write_pos += 2;
+                
+                if (!--num_relocs) {
+                    goto _finish;
+                }
+            
+            }
+        
+        }
+    
+    }
+    
+    report_at (program_name, 0, REPORT_INTERNAL_ERROR, "num_relocs mismatch while generating .reloc section");
+    
+_finish:
+    
+    section_append_section_part (reloc_section, reloc_part);
+    reloc_section->total_size += reloc_part->content_size;
+
+}
+
+static struct section *last_section = 0;
+
+static unsigned long base_of_code = 0;
+static unsigned long base_of_data = 0;
+
+static unsigned long size_of_code = 0;
+static unsigned long size_of_initialized_data = 0;
+static unsigned long size_of_uninitialized_data = 0;
+
+static unsigned short translate_section_flags_to_characteristics (int flags) {
+
+    unsigned short characteristics = 0;
+    
+    if (!(flags & SECTION_FLAG_READONLY)) {
+        characteristics |= IMAGE_SCN_MEM_WRITE;
+    }
+    
+    if (flags & SECTION_FLAG_CODE) {
+        characteristics |= IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE;
+    }
+    
+    if (flags & SECTION_FLAG_DATA) {
+        characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;
+    }
+    
+    if (flags & SECTION_FLAG_NEVER_LOAD) {
+        characteristics |= IMAGE_SCN_TYPE_NOLOAD;
+    }
+    
+    if (flags & SECTION_FLAG_DEBUGGING) {
+        characteristics |= IMAGE_SCN_LNK_INFO;
+    }
+    
+    if (flags & SECTION_FLAG_EXCLUDE) {
+        characteristics |= IMAGE_SCN_LNK_REMOVE;
+    }
+    
+    if (!(flags & SECTION_FLAG_NOREAD)) {
+        characteristics |= IMAGE_SCN_MEM_READ;
+    }
+    
+    if (flags & SECTION_FLAG_SHARED) {
+        characteristics |= IMAGE_SCN_MEM_SHARED;
+    }
+    
+    if ((flags & SECTION_FLAG_ALLOC) && !(flags & SECTION_FLAG_LOAD)) {
+        characteristics |= IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+    }
+    
+    return characteristics;
+
+}
+
+static void write_sections (unsigned char *data) {
+
+    unsigned char *pos = data + state->size_of_headers;
+    unsigned short characteristics = 0;
+    
+    struct pe_section_table_entry *hdr;
+    struct section *section;
+    
+    for (section = all_sections; section; section = section->next) {
+    
+        section->object_dependent_data = (hdr = xmalloc (sizeof (*hdr)));
+        
+        memset (hdr->Name, 0, sizeof (hdr->Name));
+        memcpy (hdr->Name, section->name, (strlen (section->name) >= sizeof (hdr->Name)) ? sizeof (hdr->Name) : strlen (section->name));
+        
+        write741_to_byte_array (hdr->VirtualSize, section->total_size);
+        write741_to_byte_array (hdr->VirtualAddress, section->rva);
+        
+        if (!section->is_bss) {
+        
+            write741_to_byte_array (hdr->SizeOfRawData, ALIGN (section->total_size, file_alignment));
+            write741_to_byte_array (hdr->PointerToRawData, pos - data);
+            
+            section_write (section, pos);
+            pos += ALIGN (section->total_size, file_alignment);
+        
+        }
+        
+        characteristics = translate_section_flags_to_characteristics (section->flags);
+        write721_to_byte_array (hdr->Characteristics, characteristics);
+        
+        if (characteristics & IMAGE_SCN_CNT_CODE) {
+        
+            if (!base_of_code) {
+                base_of_code = array_to_integer (hdr->VirtualAddress, 4);
+            }
+            
+            size_of_code += array_to_integer (hdr->VirtualSize, 4);
+        
+        } else if (characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) {
+        
+            if (!base_of_data) {
+                base_of_data = array_to_integer (hdr->VirtualAddress, 4);
+            }
+            
+            size_of_initialized_data += array_to_integer (hdr->VirtualSize, 4);
+        
+        } else if (characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) {
+            size_of_uninitialized_data += array_to_integer (hdr->VirtualSize, 4);
+        }
+        
+        last_section = section;
+    
+    }
+
+}
+
+static unsigned long bytearray_read_4_bytes (unsigned char *src) {
+
+    unsigned long value = 0;
+    int i;
+    
+    for (i = 0; i < 4; i++) {
+        value |= (unsigned long) src[i] << (CHAR_BIT * i);
+    }
+    
+    return value;
+
+}
+
+static unsigned long calculate_checksum (unsigned char *base, unsigned long chksum_off, unsigned long size) {
+
+    unsigned long checksum = 0, data, i;
+    int carry;
+    
+    for (i = 0; i < size / 4; i++) {
+    
+        if (i == chksum_off / 4) {
+            continue;
+        }
+        
+        data  = bytearray_read_4_bytes (base + i * 4);
+        
+        carry = checksum > 0xFFFFFFFFLU - data;
+        
+        checksum += data;
+        checksum += carry;
+        
+        checksum &= 0xFFFFFFFFLU;
+    
+    }
+    
+    checksum = (checksum >> 16) + (checksum & 0xFFFF);
+    
+    checksum += checksum >> 16;
+    checksum &= 0xFFFF;
+    checksum += size;
+    
+    return checksum & 0xFFFFFFFFLU;
+
+}
+
+void pe_after_link (void) {
+
+    unsigned long num_relocs = 0, saved_i = 0, i;
+    
+    struct section *saved_section = 0, *section, *reloc_section;
+    struct section_part *saved_part = 0, *part;
+    
+    struct pe_base_relocation ibr_hdr;
+    struct reloc_entry *relocs;
+    
+    if (!generate_reloc_section) {
+        return;
+    }
+    
+    if (!(reloc_section = section_find (".reloc"))) {
+        report_at (program_name, 0, REPORT_INTERNAL_ERROR, ".reloc section count not be found");
+    }
+    
+    integer_to_array (0, ibr_hdr.RVAOfBlock, 4);
+    
+    for (section = all_sections; section; section = section->next) {
+    
+        for (part = section->first_part; part; part = part->next) {
+        
+            relocs = part->reloc_arr;
+            
+            for (i = 0; i < part->reloc_cnt; i++) {
+            
+                if (relocs[i].howto != &reloc_howtos[RELOC_TYPE_64] && relocs[i].howto != &reloc_howtos[RELOC_TYPE_32]) {
+                    continue;
+                }
+                
+                if (num_relocs && (part->rva + relocs[i].offset >= array_to_integer (ibr_hdr.RVAOfBlock, 4) + BASE_RELOCATION_PAGE_SIZE || part->rva + relocs[i].offset < array_to_integer (ibr_hdr.RVAOfBlock, 4))) {
+                
+                    generate_base_relocation_block (reloc_section, &ibr_hdr, num_relocs, saved_section, saved_part, saved_i);
+                    num_relocs = 0;
+                
+                }
+                
+                if (num_relocs == 0) {
+                
+                    integer_to_array (FLOOR_TO (part->rva + relocs[i].offset, BASE_RELOCATION_PAGE_SIZE), ibr_hdr.RVAOfBlock, 4);
+                    
+                    saved_section = section;
+                    saved_part = part;
+                    
+                    saved_i = i;
+                
+                }
+                
+                num_relocs++;
+            
+            }
+        
+        }
+    
+    }
+    
+    if (num_relocs) {
+        generate_base_relocation_block (reloc_section, &ibr_hdr, num_relocs, saved_section, saved_part, saved_i);
+    }
+
+}
+
+void pe_before_link (void) {
+
+    struct section *section;
+    struct section_part *part;
+    struct subsection *subsection;
+    
+    if (state->base_address % 0x10000) {
+        report_at (program_name, 0, REPORT_WARNING, "base address must be a multiple of 64 KiB (0x10000) according to the specification");
+    }
+    
+    exclude_symbols_free ();
+    
+    if (!check_reloc_section_needed ()) {
+    
+        can_be_relocated = 1;
+        generate_reloc_section = 0;
+    
+    }
+    
+    if (generate_reloc_section) {
+    
+        can_be_relocated = 1;
+        
+        section = section_find_or_make (".reloc");
+        section->flags = translate_characteristics_to_section_flags (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE);
+    
+    }
+    
+    for (section = all_sections; section; section = section->next) {
+    
+        if (section->section_alignment < section_alignment) {
+            section->section_alignment = section_alignment;
+        }
+    
+    }
+    
+    state->size_of_headers = sizeof (struct msdos_header) + sizeof (dos_stub) + sizeof (struct pe_header) + sizeof (struct pe_optional_header);
+    
+    state->size_of_headers += NUMBER_OF_DATA_DIRECTORIES * sizeof (struct pe_image_data_directory);
+    state->size_of_headers += sizeof (struct pe_section_table_entry) * section_count ();
+    
+    state->size_of_headers = ALIGN (state->size_of_headers, file_alignment);
+    
+    if (!(section = section_find (".idata"))) {
+        return;
+    }
+    
+    if (!(subsection = subsection_find (section, "2"))) {
+        return;
+    }
+    
+    part = section_part_new (section, object_file_make (FAKE_LD_FILENAME, 0));
+    
+    part->content_size = sizeof (struct pe_import_directory_table);
+    part->content = xmalloc (part->content_size);
+    
+    subsection_append_section_part (subsection, part);
+    
+    if (!(subsection = subsection_find (section, "5"))) {
+        return;
+    }
+    
+    iat_first_part = subsection->first_part;
+    
+    if (!iat_first_part) {
+        return;
+    }
+    
+    for (part = iat_first_part; ; part = part->next) {
+    
+        if (!part->next) {
+            break;
+        }
+    
+    }
+    
+    iat_last_part = part;
+
+}
+
+void pe_write (const char *filename) {
+
+    FILE *fp;
+    
+    unsigned long data_size = 0, checksum_pos = 0;
+    unsigned char *data, *pos;
+    
+    struct msdos_header *doshdr;
+    struct pe_header *pehdr;
+    struct pe_optional_header *opthdr;
+    
+    struct section *section;
+    
+    if (!(fp = fopen (filename, "wb"))) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", filename);
+        return;
+    
+    }
+    
+    for (section = all_sections; section; section = section->next) {
+    
+        if (!section->is_bss) {
+            data_size += ALIGN (section->total_size, file_alignment);
+        }
+    
+    }
+    
+    data_size += state->size_of_headers;
+    
+    data = xmalloc (data_size);
+    write_sections (data);
+    
+    doshdr = (struct msdos_header *) data;
+    pehdr = (struct pe_header *) ((char *) doshdr + sizeof (*doshdr) + sizeof (dos_stub));
+    
+    opthdr = (struct pe_optional_header *) ((char *) pehdr + sizeof (*pehdr));
+    pos = (unsigned char *) opthdr + sizeof (*opthdr);
+    
+    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 (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 *) data + array_to_integer (doshdr->e_lfarlc, 2), 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, section_count ());
+    write741_to_byte_array (pehdr->TimeDateStamp, time (0));
+    write721_to_byte_array (pehdr->SizeOfOptionalHeader, sizeof (*opthdr));
+    
+    {
+    
+        unsigned short characteristics = 0;
+        
+        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;
+        
+        if (!can_be_relocated) {
+            characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
+        }
+        
+        write721_to_byte_array (pehdr->Characteristics, characteristics);
+    
+    }
+    
+    
+    write721_to_byte_array (opthdr->Magic, IMAGE_FILE_MAGIC_I386);
+    
+    opthdr->MajorLinkerVersion = 0;
+    opthdr->MinorLinkerVersion = 10;
+    
+    write741_to_byte_array (opthdr->SizeOfCode, ALIGN (size_of_code, file_alignment));
+    write741_to_byte_array (opthdr->SizeOfInitializedData, ALIGN (size_of_initialized_data, file_alignment));
+    write741_to_byte_array (opthdr->SizeOfUninitializedData, ALIGN (size_of_uninitialized_data, file_alignment));
+    
+    write741_to_byte_array (opthdr->AddressOfEntryPoint, state->entry_point);
+    
+    write741_to_byte_array (opthdr->BaseOfCode, base_of_code);
+    write741_to_byte_array (opthdr->BaseOfData, base_of_data);
+    
+    write741_to_byte_array (opthdr->ImageBase, state->base_address);
+    
+    write741_to_byte_array (opthdr->SectionAlignment, section_alignment);
+    write741_to_byte_array (opthdr->FileAlignment, file_alignment);
+    
+    write721_to_byte_array (opthdr->MajorOperatingSystemVersion, 4);
+    write721_to_byte_array (opthdr->MajorImageVersion, 1);
+    write721_to_byte_array (opthdr->MajorSubsystemVersion, 4);
+    
+    if (last_section) {
+        write741_to_byte_array (opthdr->SizeOfImage, ALIGN (last_section->rva + last_section->total_size, section_alignment));
+    } else {
+        write741_to_byte_array (opthdr->SizeOfImage, state->size_of_headers);
+    }
+    
+    write741_to_byte_array (opthdr->SizeOfHeaders, state->size_of_headers);
+    write721_to_byte_array (opthdr->Subsystem, subsystem);
+    
+    {
+    
+        struct section *bss_section;
+        
+        if (!(bss_section = section_find (".bss"))) {
+        
+            write741_to_byte_array (opthdr->SizeOfStackReserved, section_alignment << 9);
+            write741_to_byte_array (opthdr->SizeOfStackCommit, 0x1000);
+            write741_to_byte_array (opthdr->SizeOfHeapReserved, section_alignment << 8);
+            write741_to_byte_array (opthdr->SizeOfHeapCommit, 0x1000);
+        
+        } else {
+        
+            unsigned long ibss_addr = bss_section->rva;
+            unsigned long ibss_size = bss_section->total_size;
+            
+            unsigned long stack_addr = ibss_addr + ibss_size;
+            unsigned long stack_size = ALIGN (stack_addr, section_alignment);
+            
+            write741_to_byte_array (opthdr->SizeOfStackReserved, section_alignment << 9);
+            write741_to_byte_array (opthdr->SizeOfStackCommit, ALIGN (stack_addr % 16 + stack_size, section_alignment));
+            write741_to_byte_array (opthdr->SizeOfHeapReserved, section_alignment << 8);
+            write741_to_byte_array (opthdr->SizeOfHeapCommit, ALIGN (stack_addr % 16 + stack_size, section_alignment));
+        
+        }
+    
+    }
+    
+    write741_to_byte_array (opthdr->NumberOfRvaAndSizes, NUMBER_OF_DATA_DIRECTORIES);
+    
+    
+    for (section = all_sections; section; section = section->next) {
+    
+        struct pe_section_table_entry *hdr = section->object_dependent_data;
+        
+        memcpy (pos, hdr, sizeof (*hdr));
+        pos += sizeof (*hdr);
+        
+        free (hdr);
+    
+    }
+    
+    
+    checksum_pos = sizeof (*doshdr) + sizeof (dos_stub) + sizeof (*pehdr) + offsetof (struct pe_optional_header, Checksum);
+    write741_to_byte_array (opthdr->Checksum, calculate_checksum (data, checksum_pos, data_size));
+    
+    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);
+
+}
+
+void pe_print_help (void) {
+
+    fprintf (stderr, "i386pe:\n\n");
+    
+    fprintf (stderr, "    --file-alignment <size>           Set file alignment.\n");
+    fprintf (stderr, "    --section-alignment <size>        Set section alignment.\n");
+    fprintf (stderr, "    --subsystem <name>                Set required OS subsystem.\n");
+
+}
+
+unsigned long pe_get_first_section_rva (void) {
+    return ALIGN (state->size_of_headers, section_alignment);
+}
diff --git a/pe.h b/pe.h
index 59a7724e62ece14e86bfd4d0f31b3923f06c2a67..88723fc06962267b0cc85bb08a2ad5f45973e567 100644 (file)
--- a/pe.h
+++ b/pe.h
@@ -4,6 +4,9 @@
 #ifndef     _PE_H
 #define     _PE_H
 
+#define     DEFAULT_SECTION_ALIGNMENT       0x1000
+#define     DEFAULT_FILE_ALIGNMENT          0x0200
+
 struct msdos_header {
 
     unsigned char e_magic[2];           /* Magic number                         */
@@ -28,6 +31,19 @@ struct msdos_header {
 
 };
 
+#define     IMAGE_SUBSYSTEM_UNKNOWN                         0
+#define     IMAGE_SUBSYSTEM_NATIVE                          1
+#define     IMAGE_SUBSYSTEM_WINDOWS_GUI                     2
+#define     IMAGE_SUBSYSTEM_WINDOWS_CUI                     3
+#define     IMAGE_SUBSYSTEM_OS2_CUI                         5
+#define     IMAGE_SUBSYSTEM_POSIX_CUI                       7
+#define     IMAGE_SUBSYSTEM_EFI_APPLICATION                 10
+#define     IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER         11
+#define     IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER              12
+#define     IMAGE_SUBSYSTEM_EFI_ROM                         13
+#define     IMAGE_SUBSYSTEM_XBOX                            14
+#define     IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPILCATION        16
+
 struct pe_header {
 
     unsigned char Signature[4];
@@ -105,7 +121,7 @@ struct pe_optional_header {
 
 #define     IMAGE_FILE_MAGIC_I386                           0x010B
 
-struct section_table_entry {
+struct pe_section_table_entry {
 
     char Name[8];
     
@@ -124,54 +140,67 @@ struct section_table_entry {
 
 };
 
+#define     IMAGE_SCN_TYPE_NOLOAD                           0x00000002
 #define     IMAGE_SCN_CNT_CODE                              0x00000020
 #define     IMAGE_SCN_CNT_INITIALIZED_DATA                  0x00000040
 #define     IMAGE_SCN_CNT_UNINITIALIZED_DATA                0x00000080
+#define     IMAGE_SCN_LNK_INFO                              0x00000200
+#define     IMAGE_SCN_LNK_REMOVE                            0x00000800
 #define     IMAGE_SCN_ALIGN_4BYTES                          0x00300000
+#define     IMAGE_SCN_MEM_SHARED                            0x10000000
 #define     IMAGE_SCN_MEM_EXECUTE                           0x20000000
 #define     IMAGE_SCN_MEM_READ                              0x40000000
 #define     IMAGE_SCN_MEM_WRITE                             0x80000000
 
-struct relocation_entry {
+struct pe_image_data_directory {
 
-    unsigned int VirtualAddress;
-    unsigned int SymbolTableIndex;
-    
-    unsigned short Type;
+    unsigned char VirtualAddress[4];
+    unsigned char Size[4];
 
 };
 
-#define     RELOCATION_ENTRY_SIZE                           10
+struct pe_base_relocation {
 
-#define     IMAGE_REL_I386_ABSOLUTE                         0x0000
-#define     IMAGE_REL_I386_DIR32                            0x0006
-#define     IMAGE_REL_I386_DIR32NB                          0x0007
-#define     IMAGE_REL_I386_REL32                            0x0014
+    unsigned char RVAOfBlock[4];
+    unsigned char SizeOfBlock[4];
 
-struct symbol_table_entry {
+};
 
-    char Name[8];
-    unsigned int Value;
-    
-    signed short SectionNumber;
-    unsigned short Type;
-    
-    unsigned char StorageClass;
-    unsigned char NumberOfAuxSymbols;
+#define     BASE_RELOCATION_PAGE_SIZE                       4096
+
+#define     IMAGE_REL_BASED_ABSOLUTE                        0
+#define     IMAGE_REL_BASED_HIGH                            1
+#define     IMAGE_REL_BASED_LOW                             2
+#define     IMAGE_REL_BASED_HIGHLOW                         3
+#define     IMAGE_REL_BASED_HIGHADJ                         4
+#define     IMAGE_REL_BASED_MIPS_JMPADDR                    5
+#define     IMAGE_REL_BASED_ARM_MOV32                       5
+#define     IMAGE_REL_BASED_RISCV_HIGH20                    5
+#define     IMAGE_REL_BASED_THUMB_MOV32                     7
+#define     IMAGE_REL_BASED_RISCV_LOW12I                    7
+#define     IMAGE_REL_BASED_RISCV_LOW12S                    8
+#define     IMAGE_REL_BASED_MIPS_JMPADDR16                  9
+#define     IMAGE_REL_BASED_DIR64                           10
+
+struct pe_import_directory_table {
+
+    unsigned char ImportNameTableRVA[4];
+    unsigned char TimeDateStamp[4];
+    unsigned char ForwarderChain[4];
+    unsigned char NameRVA[4];
+    unsigned char ImportAddressTableRVA[4];
 
 };
 
-#define     SYMBOL_TABLE_ENTRY_SIZE                         18
-#define     IMAGE_SYM_UNDEFINED                             0
+int pe_check_option (const char *cmd_arg, int argc, char **argv, int *optind, const char **optarg);
 
-#define     IMAGE_SYM_ABSOLUTE                              -1
-#define     IMAGE_SYM_DEBUG                                 -2
+void pe_after_link (void);
+void pe_before_link (void);
+void pe_print_help (void);
 
-#define     IMAGE_SYM_TYPE_NULL                             0
-#define     IMAGE_SYM_DTYPE_NULL                            0
+unsigned long pe_get_first_section_rva (void);
 
-#define     IMAGE_SYM_CLASS_EXTERNAL                        2
-#define     IMAGE_SYM_CLASS_STATIC                          3
-#define     IMAGE_SYM_CLASS_FILE                            103
+void pe_write (const char *filename);
+void pe_use_option (const char *cmd_arg, int idx, const char *optarg);
 
 #endif      /* _PE_H */
diff --git a/reloc.h b/reloc.h
new file mode 100644 (file)
index 0000000..118719e
--- /dev/null
+++ b/reloc.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ * @file            reloc.h
+ *****************************************************************************/
+#ifndef     _RELOC_H
+#define     _RELOC_H
+
+enum {
+
+    RELOC_TYPE_IGNORED,
+    
+    RELOC_TYPE_64,
+    RELOC_TYPE_PC64,
+    
+    RELOC_TYPE_32,
+    RELOC_TYPE_PC32,
+    
+    RELOC_TYPE_16,
+    RELOC_TYPE_PC16,
+    
+    RELOC_TYPE_8,
+    RELOC_TYPE_PC8,
+    
+    RELOC_TYPE_END
+
+};
+
+struct section_part;
+struct symbol;
+struct reloc_entry;
+
+struct reloc_howto {
+
+    int size, pc_rel, no_base, final_right_shift;
+    void (*special_function) (struct section_part *part, struct reloc_entry *rel, struct symbol *symbol);
+    
+    const char *name;
+    unsigned long dst_mask;
+    
+    int final_left_shift;
+
+};
+
+extern struct reloc_howto reloc_howtos[RELOC_TYPE_END];
+
+struct reloc_entry {
+
+    struct symbol *symbol;
+    
+    unsigned long offset;
+    unsigned long addend;
+    
+    struct reloc_howto *howto;
+
+};
+
+#endif      /* _RELOC_H */
index fb010ce568d1fbdfb83969d72ccf572a249024d9..8f020a3857b0fa26c9a872f0f04fa1427ee8cfd3 100644 (file)
--- a/report.c
+++ b/report.c
@@ -110,13 +110,17 @@ static void output_message (const char *filename, unsigned int lineno, unsigned
         
         fprintf (stderr, "internal error:");
     
-    } else if (type == REPORT_WARNING) {
+    } else if (type == REPORT_WARNING || type == REPORT_NOTE) {
     
 #ifndef     __PDOS__
         set_console_color (COLOR_WARNING);
 #endif
         
-        fprintf (stderr, "warning:");
+        if (type == REPORT_WARNING) {
+            fprintf (stderr, "warning:");
+        } else {
+            fprintf (stderr, "note:");
+        }
     
     }
     
index 8e694dd502b022a4b63addb7485532c426d626d6..fefee4b5c45437a2d3d7cffe130fc6c8f89a6e28 100644 (file)
--- a/report.h
+++ b/report.h
@@ -16,6 +16,7 @@
 
 #define     REPORT_WARNING              0
 #define     REPORT_ERROR                1
+#define     REPORT_NOTE                 2
 #define     REPORT_FATAL_ERROR          3
 #define     REPORT_INTERNAL_ERROR       4
 
diff --git a/section.c b/section.c
new file mode 100644 (file)
index 0000000..f8a9d48
--- /dev/null
+++ b/section.c
@@ -0,0 +1,184 @@
+/******************************************************************************
+ * @file            section.c
+ *****************************************************************************/
+#include    <string.h>
+
+#include    "lib.h"
+#include    "section.h"
+
+struct object_file *all_object_files = 0;
+struct section *all_sections = 0;
+
+static struct object_file **last_object_file_p = &all_object_files;
+static struct section **last_section_p = &all_sections;
+
+static struct section *discarded_sections = 0;
+
+struct object_file *object_file_make (const char *filename, unsigned long symbol_cnt) {
+
+    struct object_file *of = xmalloc (sizeof (*of));
+    
+    of->filename = xstrdup (filename);
+    
+    of->symbol_arr = symbol_cnt ? xmalloc (sizeof (*of->symbol_arr) * symbol_cnt) : 0;
+    of->symbol_cnt = symbol_cnt;
+    
+    *last_object_file_p = of;
+    last_object_file_p = &of->next;
+    
+    return of;
+
+}
+
+struct section *section_find (const char *name) {
+
+    struct section *section = 0;
+    
+    for (section = all_sections; section; section = section->next) {
+    
+        if (strcmp (section->name, name) == 0) {
+            break;
+        }
+    
+    }
+    
+    return section;
+
+}
+
+struct section *section_find_or_make (const char *name) {
+
+    struct section *section;
+    
+    if ((section = section_find (name))) {
+        return section;
+    }
+    
+    section = xmalloc (sizeof (*section));
+    section->name = xstrdup (name);
+    
+    section->last_part_p = &section->first_part;
+    section->section_alignment = 1;
+    
+    *last_section_p = section;
+    last_section_p = &section->next;
+    
+    return section;
+
+}
+
+struct section_part *section_part_new (struct section *section, struct object_file *of) {
+
+    struct section_part *part = xmalloc (sizeof (*part));
+    
+    part->section = section;
+    part->of = of;
+    part->alignment = 1;
+    
+    return part;
+
+}
+
+void section_append_section_part (struct section *section, struct section_part *part) {
+
+    *section->last_part_p = part;
+    section->last_part_p = &part->next;
+
+}
+
+void sections_destroy_empty_before_collapse (void) {
+
+    struct section *section, **next_p;
+    
+    struct section_part *part;
+    struct subsection *subsection;
+    
+    for (next_p = &all_sections, section = *next_p; section; section = *next_p) {
+    
+        for (part = section->first_part; part; part = part->next) {
+        
+            if (part->content_size) {
+                goto _done_section;
+            }
+        
+        }
+        
+        for (subsection = section->all_subsections; subsection; subsection = subsection->next) {
+        
+            for (part = subsection->first_part; part; part = part->next) {
+            
+                if (part->content_size) {
+                    goto _done_section;
+                }
+            
+            }
+        
+        }
+        
+    _done_section:
+        
+        if (part && part->content_size) {
+            next_p = &section->next;
+        } else {
+        
+            *next_p = section->next;
+            
+            section->next = discarded_sections;
+            discarded_sections = section;
+        
+        }
+    
+    }
+    
+    last_section_p = next_p;
+
+}
+
+void section_write (struct section *section, unsigned char *memory) {
+
+    struct section_part *part;
+    
+    for (part = section->first_part; part; part = part->next) {
+    
+        memcpy (memory, part->content, part->content_size);
+        memory += part->content_size;
+    
+    }
+
+}
+
+int section_count (void) {
+
+    struct section *section;
+    int cnt = 0;
+    
+    for (section = all_sections; section; section = section->next) {
+        cnt++;
+    }
+    
+    return cnt;
+
+}
+
+struct subsection *subsection_find (struct section *section, const char *name) {
+
+    struct subsection *subsection;
+    
+    for (subsection = section->all_subsections; subsection; subsection = subsection->next) {
+    
+        if (strcmp (subsection->name, name) == 0) {
+            break;
+        }
+    
+    }
+    
+    return subsection;
+
+}
+
+void subsection_append_section_part (struct subsection *subsection, struct section_part *part) {
+
+    *subsection->last_part_p = part;
+    subsection->last_part_p = &part->next;
+
+}
diff --git a/section.h b/section.h
new file mode 100644 (file)
index 0000000..0f0686b
--- /dev/null
+++ b/section.h
@@ -0,0 +1,104 @@
+/******************************************************************************
+ * @file            section.h
+ *****************************************************************************/
+#ifndef     _SECTION_H
+#define     _SECTION_H
+
+#include    "reloc.h"
+#include    "symbol.h"
+
+struct object_file {
+
+    char *filename;
+    
+    struct symbol *symbol_arr;
+    unsigned long symbol_cnt;
+    
+    struct object_file *next;
+
+};
+
+struct section_part {
+
+    struct section *section;
+    struct object_file *of;
+    
+    unsigned char *content;
+    unsigned long content_size, alignment;
+    
+    struct reloc_entry *reloc_arr;
+    unsigned long reloc_cnt;
+    
+    unsigned long rva;
+    struct section_part *next;
+
+};
+
+struct subsection {
+
+    char *name;
+    
+    struct section_part *first_part;
+    struct section_part **last_part_p;
+    
+    struct subsection *next;
+
+};
+
+#define     UNDEFINED_SECTION_NUMBER    0
+#define     ABSOLUTE_SECTION_NUMBER     (-1)
+
+struct section {
+
+    char *name;
+    int flags;
+    
+    struct section_part *first_part;
+    struct section_part **last_part_p;
+    
+    struct subsection *all_subsections;
+    
+    unsigned long total_size;
+    int is_bss;
+    
+    unsigned long rva;
+    unsigned long section_alignment;
+    
+    int target_index;
+    void *object_dependent_data;
+    
+    struct section *next;
+
+};
+
+#define     SECTION_FLAG_ALLOC          (1U << 0)
+#define     SECTION_FLAG_LOAD           (1U << 1)
+#define     SECTION_FLAG_READONLY       (1U << 2)
+#define     SECTION_FLAG_CODE           (1U << 3)
+#define     SECTION_FLAG_DATA           (1U << 4)
+#define     SECTION_FLAG_NEVER_LOAD     (1U << 5)
+#define     SECTION_FLAG_DEBUGGING      (1U << 6)
+#define     SECTION_FLAG_EXCLUDE        (1U << 7)
+#define     SECTION_FLAG_NOREAD         (1U << 8)
+#define     SECTION_FLAG_SHARED         (1U << 9)
+
+extern struct object_file *all_object_files;
+extern struct section *all_sections;
+
+struct object_file *object_file_make (const char *filename, unsigned long symbol_cnt);
+
+struct section_part *section_part_new (struct section *section, struct object_file *of);
+void section_append_section_part (struct section *section, struct section_part *part);
+
+struct section *section_find (const char *name);
+struct section *section_find_or_make (const char *name);
+
+void sections_destroy_empty_before_collapse (void);
+void section_write (struct section *section, unsigned char *memory);
+
+int section_count (void);
+
+struct subsection *subsection_find (struct section *section, const char *name);
+void subsection_append_section_part (struct subsection *subsection, struct section_part *part);
+
+#endif      /* _SECTION_H */
diff --git a/symbol.c b/symbol.c
new file mode 100644 (file)
index 0000000..d6598e9
--- /dev/null
+++ b/symbol.c
@@ -0,0 +1,105 @@
+/******************************************************************************
+ * @file            symbol.c
+ *****************************************************************************/
+#include    <stdlib.h>
+
+#include    "hashtab.h"
+#include    "ld.h"
+#include    "report.h"
+#include    "symbol.h"
+
+static struct hashtab symbol_hashtab = { 0 };
+
+struct symbol *symbol_find (const char *name) {
+
+    struct hashtab_name *key;
+    struct symbol *symbol;
+    
+    if (!(key = hashtab_alloc_name (name))) {
+        return 0;
+    }
+    
+    symbol = hashtab_get (&symbol_hashtab, key);
+    free (key);
+    
+    return symbol;
+
+}
+
+void symbol_record_external_symbol (struct symbol *symbol) {
+
+    struct symbol *old_symbol = symbol_find (symbol->name);
+    
+    if (!old_symbol) {
+    
+        symbol_add_to_hashtab (symbol);
+        return;
+    
+    }
+    
+    if (symbol_is_undefined (old_symbol)) {
+    
+        symbol_remove_from_hashtab (old_symbol);
+        symbol_add_to_hashtab (symbol);
+        
+        return;
+    
+    }
+    
+    if (symbol_is_undefined (symbol)) {
+        return;
+    }
+    
+    report_at (program_name, 0, REPORT_ERROR, "%s:(%s+0x%lx): multiple definition of '%s'", symbol->part->of->filename, symbol->part->section->name, symbol->value, symbol->name);
+    report_at (program_name, 0, REPORT_NOTE, "%s:(%s+0x%lx): multiple definition of '%s'", old_symbol->part->of->filename, old_symbol->part->section->name, old_symbol->value, old_symbol->name);
+
+}
+
+int symbol_is_undefined (const struct symbol *symbol) {
+    return symbol->section_number == UNDEFINED_SECTION_NUMBER;
+}
+
+void symbol_add_to_hashtab (struct symbol *symbol) {
+
+    struct hashtab_name *key;
+    
+    if (!(key = hashtab_alloc_name (symbol->name))) {
+        return;
+    }
+    
+    hashtab_put (&symbol_hashtab, key, symbol);
+
+}
+
+void symbol_remove_from_hashtab (struct symbol *symbol) {
+
+    struct hashtab_name *key;
+    
+    if (!(key = hashtab_alloc_name (symbol->name))) {
+        return;
+    }
+    
+    hashtab_remove (&symbol_hashtab, key);
+    free (key);
+
+}
+
+unsigned long symbol_get_value_with_base (const struct symbol *symbol) {
+
+    if (symbol->part) {
+        return state->base_address + symbol->part->rva + symbol->value;
+    }
+    
+    return symbol->value;
+
+}
+
+unsigned long symbol_get_value_no_base (const struct symbol *symbol) {
+
+    if (symbol->part) {
+        return symbol->part->rva + symbol->value;
+    }
+    
+    return (symbol->value - state->base_address);
+
+}
diff --git a/symbol.h b/symbol.h
new file mode 100644 (file)
index 0000000..82e8c98
--- /dev/null
+++ b/symbol.h
@@ -0,0 +1,38 @@
+/******************************************************************************
+ * @file            symbol.h
+ *****************************************************************************/
+#ifndef     _SYMBOL_H
+#define     _SYMBOL_H
+
+#include    "section.h"
+
+struct symbol {
+
+    char *name;
+    int flags;
+    
+    unsigned long value;
+    unsigned long size;
+    
+    long section_number;                /* 1-based, 0 means undefined, negative numbers have special meaning. */
+    int auxiliary;                      /* such symbol should be ignored and is only a filter. */
+    
+    struct section_part *part;
+
+};
+
+#define     SYMBOL_FLAG_EXCLUDE_EXPORT                      (1U << 0)
+#define     SYMBOL_FLAG_SECTION_SYMBOL                      (1U << 1)
+
+struct symbol *symbol_find (const char *name);
+
+void symbol_record_external_symbol (struct symbol *symbol);
+int symbol_is_undefined (const struct symbol *symbol);
+
+void symbol_add_to_hashtab (struct symbol *symbol);
+void symbol_remove_from_hashtab (struct symbol *symbol);
+
+unsigned long symbol_get_value_with_base (const struct symbol *symbol);
+unsigned long symbol_get_value_no_base (const struct symbol *symbol);
+
+#endif      /* _SYMBOL_H */