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
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
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
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
/******************************************************************************
* @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;
}
#define N_TEXT 0x04
#define N_DATA 0x06
#define N_BSS 0x08
+#define N_COMM 0x12
struct elks_relocation_info {
};
#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 */
#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);
}
#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;
};
#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 */
#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 }
};
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;
}
}
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) {
}
- 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;
}
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)) {
}
- 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"; }
}
#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);
--- /dev/null
+/******************************************************************************
+ * @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 ();
+
+}
--- /dev/null
+/******************************************************************************
+ * @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);
+ }
+
+}
--- /dev/null
+/******************************************************************************
+ * @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);
+}
#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 */
};
+#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];
#define IMAGE_FILE_MAGIC_I386 0x010B
-struct section_table_entry {
+struct pe_section_table_entry {
char Name[8];
};
+#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 */
--- /dev/null
+/******************************************************************************
+ * @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 */
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:");
+ }
}
#define REPORT_WARNING 0
#define REPORT_ERROR 1
+#define REPORT_NOTE 2
#define REPORT_FATAL_ERROR 3
#define REPORT_INTERNAL_ERROR 4
--- /dev/null
+/******************************************************************************
+ * @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 = §ion->first_part;
+ section->section_alignment = 1;
+
+ *last_section_p = section;
+ last_section_p = §ion->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 = §ion->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;
+
+}
--- /dev/null
+/******************************************************************************
+ * @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 */
--- /dev/null
+/******************************************************************************
+ * @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);
+
+}
--- /dev/null
+/******************************************************************************
+ * @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 */