From: Robert Pengelly Date: Mon, 3 Jun 2024 03:36:14 +0000 (+0100) Subject: New server X-Git-Url: https://git.candlhat.org/?a=commitdiff_plain;h=88e82a858e9125eb34cde1c56a16f6f0dfa4afc1;p=slink.git New server --- 88e82a858e9125eb34cde1c56a16f6f0dfa4afc1 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fdddb29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/Makefile.p32 b/Makefile.p32 new file mode 100644 index 0000000..4f335bc --- /dev/null +++ b/Makefile.p32 @@ -0,0 +1,25 @@ +#****************************************************************************** +# @file Makefile.p32 +#****************************************************************************** +AS=as386 +CC=gcc386 +LD=ld386 + +COPTS=-S -O2 -fno-common -ansi -I. -I./include -I../pdos/pdpclib -I../pdos/src -D__PDOS386__ -D__32BIT__ -D__NOBIVA__ -D__PDOS__ -Wall -Werror -ansi -m32 -pedantic +COBJ=aout.c hashtab.o ld.o lib.o report.o vector.o write7x.o + +all: clean slink.exe + +slink.exe: $(COBJ) + $(LD) -s -o slink.exe ../pdos/pdpclib/pdosst32.o $(COBJ) ../pdos/pdpclib/pdos.a + +.c.o: + $(CC) $(COPTS) -o $*.s $< + $(AS) -o $@ $*.s + rm -f $*.s + +clean: + for %f in ($(COBJ)) do ( rm -f %f ) + + rm -f slink + rm -f slink.exe diff --git a/Makefile.pdw b/Makefile.pdw new file mode 100644 index 0000000..b61185a --- /dev/null +++ b/Makefile.pdw @@ -0,0 +1,25 @@ +#****************************************************************************** +# @file Makefile.pdw +#****************************************************************************** +AS=aswin +CC=gccwin +LD=ldwin + +COPTS=-S -O2 -fno-common -ansi -I. -I./include -I../pdos/pdpclib -I../pdos/src -D__WIN32__ -D__NOBIVA__ -D__PDOS__ -Wall -Werror -ansi -m32 -pedantic +COBJ=aout.c hashtab.o ld.o lib.o report.o vector.o write7x.o + +all: clean slink.exe + +slink.exe: $(COBJ) + $(LD) -s -o slink.exe ../pdos/pdpclib/w32start.o $(COBJ) ../pdos/pdpclib/msvcrt.a ../pdos/src/kernel32.a + +.c.o: + $(CC) $(COPTS) -o $*.s $< + $(AS) -o $@ $*.s + rm -f $*.s + +clean: + for %f in ($(COBJ)) do ( rm -f %f ) + + rm -f slink + rm -f slink.exe diff --git a/Makefile.unix b/Makefile.unix new file mode 100644 index 0000000..1289dc3 --- /dev/null +++ b/Makefile.unix @@ -0,0 +1,28 @@ +#****************************************************************************** +# @file Makefile.unix +#****************************************************************************** +OBJDIR ?= $(CURDIR) +SRCDIR ?= $(CURDIR) + +VPATH := $(SRCDIR) + +CC := gcc +CFLAGS := -D_FILE_OFFSET_BITS=64 -I$(OBJDIR) -I$(SRCDIR)/include -O2 -Wall -Werror -Wextra -ansi -pedantic -std=c90 + +CSRC := aout.c hashtab.c ld.c lib.c report.c vector.c write7x.c + +ifeq ($(OS), Windows_NT) +all: slink.exe + +slink.exe: $(CSRC) + $(CC) $(CFLAGS) -o $@ $^ +else +all: slink + +slink: $(CSRC) + $(CC) $(CFLAGS) -o $@ $^ +endif + +clean: + if [ -f slink ]; then rm -rf slink; fi + if [ -f slink.exe ]; then rm -rf slink.exe; fi diff --git a/Makefile.w32 b/Makefile.w32 new file mode 100644 index 0000000..ee7f0f7 --- /dev/null +++ b/Makefile.w32 @@ -0,0 +1,21 @@ +#****************************************************************************** +# @file Makefile.w32 +#****************************************************************************** +OBJDIR ?= $(CURDIR) +SRCDIR ?= $(CURDIR) + +VPATH := $(SRCDIR) + +CC := gcc +CFLAGS := -D_FILE_OFFSET_BITS=64 -I$(OBJDIR) -I$(SRCDIR)/include -O2 -Wall -Werror -Wextra -ansi -pedantic -std=c90 + +CSRC := aout.c hashtab.c ld.c lib.c report.c vector.c write7x.c + +all: slink.exe + +clean: + if exist slink ( del /q slink ) + if exist slink.exe ( del /q slink.exe ) + +slink.exe: $(CSRC) + $(CC) $(CFLAGS) -o $@ $^ diff --git a/README.md b/README.md new file mode 100644 index 0000000..73f161e --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +## What is slink? + + Small Linker (SLINK) is a very small linker for linking slightly + modified a.out object files into an executable. + +## License + + All source code is Public Domain. + +## Obtain the source code + + git clone https://git.candlhat.org/slink.git + +## Building + + BSD: + + Make sure you have gcc and gmake installed then run gmake -f Makefile.unix. + + Linux: + + Make sure you have gcc and make installed then run make -f Makefile.unix. + + macOS: + + Make sure you have xcode command line tools installed then run + make -f Makefile.unix. + + Windows: + + Make sure you have mingw installed and the location within your PATH variable + then run mingw32-make.exe -f Makefile.w32. diff --git a/aout.c b/aout.c new file mode 100644 index 0000000..c2d6e91 --- /dev/null +++ b/aout.c @@ -0,0 +1,550 @@ +/****************************************************************************** + * @file aout.c + *****************************************************************************/ +#include +#include +#include +#include +#include + +#include "aout.h" +#include "ld.h" +#include "lib.h" +#include "report.h" +#include "write7x.h" + +#include + +typedef signed char int8_t; +typedef signed short int16_t; + +#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 relocation_info *relocations; + +}; + +static struct gr tgr = { 0, 64, NULL }; +static struct gr dgr = { 0, 64, NULL }; + +static int get_symbol (struct aout_object **obj_out, long *index, const char *name, int quiet) { + + long object_i, symbol_i; + + for (object_i = 0; object_i < state->nb_aout_objs; ++object_i) { + + struct aout_object *obj = state->aout_objs[object_i]; + + for (symbol_i = 0; symbol_i < obj->symtab_count; symbol_i++) { + + struct 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; + + } + + } + + } + + if (!quiet) { + report_at (program_name, 0, REPORT_ERROR, "undefined symbol '%s'", name); + } + + return 1; + +} + +static void number_to_chars (unsigned char *p, unsigned long number, unsigned long size) { + + 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 aout_object *object) { + + long i; + + for (i = 0; i < object->symtab_count; i++) { + + struct nlist *symbol = &object->symtab[i]; + unsigned long final_slide = 0, n_value = GET_UINT32 (symbol->n_value); + + 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; + + } + + write741_to_byte_array (symbol->n_value, n_value); + + } + + for (i = 0; i < object->trelocs_count; i++) { + + struct relocation_info *rel = &object->trelocs[i]; + + long r_address = GET_INT32 (rel->r_address); + r_address += object->text_slide; + + write741_to_byte_array ((unsigned char *) rel->r_address, r_address); + + } + + for (i = 0; i < object->drelocs_count; i++) { + + struct relocation_info *rel = &object->drelocs[i]; + + long r_address = GET_INT32 (rel->r_address); + r_address += state->text_size + object->data_slide; + + write741_to_byte_array ((unsigned char *) rel->r_address, r_address); + + } + +} + +static void paste (struct aout_object *object) { + + struct aout_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 { + 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 { + 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 { + obj_bss_size = ALIGN_UP (GET_UINT32 (header->a_bss), SECTION_ALIGNMENT); + } + + bss_ptr += obj_bss_size; + +} + +static void undef_collect (struct aout_object *object) { + + long i, val; + + for (i = 0; i < object->symtab_count; i++) { + + struct 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 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; + + 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 aout_object *object, struct relocation_info *r, int is_data) { + + struct nlist *symbol; + unsigned char *p; + + unsigned long r_symbolnum = GET_UINT32 (r->r_symbolnum); + long result = 0, symbolnum = 0; + + int far_call = 0, pcrel = 0, ext = 0, length = 0; + + 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 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 aout_object *symobj; + long symidx; + + if (!get_symbol (&symobj, &symidx, symname, 0)) { + symbol = &symobj->symtab[symidx]; + } else { + return 1; + } + + } + + if (pcrel) { + result = (long) GET_UINT32 (symbol->n_value) - (GET_INT32 (r->r_address) + length); + } else { + + long r_address; + + if (!ext || (symbol->n_type & N_TYPE) == N_BSS || (symbol->n_type & N_TYPE) == N_DATA || (symbol->n_type & N_TYPE) == N_TEXT) { + + struct relocation_info new_relocation; + + unsigned long r_symbolnum; + long r_address; + + r_symbolnum = GET_UINT32 (r->r_symbolnum) & (3L << 29); + r_address = GET_INT32 (r->r_address); + + if (((r_symbolnum >> 28) & 0xff) != N_ABS) { + + if (state->format == LD_OUTPUT_BIN || state->format == LD_OUTPUT_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); + + } + + } + + r_address = GET_INT32 (r->r_address); + + 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); + } + + if (ext) { + + symbolnum = (symbol->n_type & N_TYPE); + + result += GET_UINT32 (symbol->n_value); + result += state->psp; + + } else { + + 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) { + + result -= GET_UINT32 (object->header->a_data); + result += state->data_size; + result += objbsssize; + + } + + result += state->psp; + + } + + } + + number_to_chars (p, result, length); + return 0; + +} + +static int glue (struct aout_object *object) { + + long i, err = 0; + + for (i = 0; i < object->trelocs_count; i++) { + + if (relocate (object, &object->trelocs[i], 0)) { + err = 1; + } + + } + + for (i = 0; i < object->drelocs_count; i++) { + + if (relocate (object, &object->drelocs[i], 1)) { + err = 1; + } + + } + + objtextsize += GET_UINT32 (object->header->a_text); + objdatasize += GET_UINT32 (object->header->a_data); + objbsssize += GET_UINT32 (object->header->a_bss); + + return err; + +} + + +int create_executable_from_aout_objects (void) { + + struct aout_object *object; + long i; + + int err = 0; + output_size = state->text_size + state->data_size; + + if ((output = malloc (output_size)) == NULL) { + return EXIT_FAILURE; + } + + memset (output, 0, output_size); + + text = (void *) (char *) output; + data = (void *) ((char *) text + state->text_size); + + for (i = 0; i < state->nb_aout_objs; ++i) { + paste (state->aout_objs[i]); + } + + for (i = 0; i < state->nb_aout_objs; ++i) { + apply_slides (state->aout_objs[i]); + } + + for (i = 0; i < state->nb_aout_objs; ++i) { + undef_collect (state->aout_objs[i]); + } + + if (!state->impure) { + state->bss_size = ALIGN_UP (state->bss_size, SECTION_ALIGNMENT); + } + + for (i = 0; i < state->nb_aout_objs; ++i) { + + if (glue (state->aout_objs[i])) { + err = 1; + } + + } + + if (err) { return EXIT_FAILURE; } + + for (i = 0; i < state->nb_aout_objs; i++) { + + if ((object = state->aout_objs[i]) == NULL) { + return EXIT_FAILURE; + } + + /*if (state->mapfile) { + init_map (object); + }*/ + + free (object->raw); + free (object); + + } + + state->nb_aout_objs = 0; + + /*if (state->mapfile) { + + 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 (); + + }*/ + + 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; + + } + + 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; + + } + + return EXIT_SUCCESS; + +} diff --git a/aout.h b/aout.h new file mode 100644 index 0000000..885ff80 --- /dev/null +++ b/aout.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * @file aout.h + *****************************************************************************/ +#ifndef _AOUT_H +#define _AOUT_H + +struct aout_exec { + + unsigned char a_info[4]; + unsigned char a_text[4]; + unsigned char a_data[4]; + unsigned char a_bss[4]; + unsigned char a_syms[4]; + unsigned char a_entry[4]; + unsigned char a_trsize[4]; + unsigned char a_drsize[4]; + +}; + +#define N_UNDF 0x00 +#define N_ABS 0x02 +#define N_TEXT 0x04 +#define N_DATA 0x06 +#define N_BSS 0x08 + +struct relocation_info { + + unsigned char r_address[4]; + unsigned char r_symbolnum[4]; + +}; + +#define N_EXT 0x01 + +struct nlist { + + unsigned char n_strx[4]; + unsigned char n_type; + + unsigned char n_value[4]; + +}; + +#define N_TYPE 0x1e +int create_executable_from_aout_objects (void); + +#endif /* _AOUT_H */ diff --git a/hashtab.c b/hashtab.c new file mode 100644 index 0000000..b6863a5 --- /dev/null +++ b/hashtab.c @@ -0,0 +1,215 @@ +/****************************************************************************** + * @file hashtab.c + *****************************************************************************/ +#include +#include +#include + +#include "hashtab.h" + +static struct hashtab_entry *find_entry (struct hashtab_entry *entries, unsigned int capacity, struct hashtab_name *key); + +static int adjust_capacity (struct hashtab *table, unsigned int new_capacity) { + + struct hashtab_entry *new_entries, *old_entries; + unsigned int i, new_count, old_capacity; + + if ((new_entries = malloc (sizeof (*new_entries) * new_capacity)) == NULL) { + return -2; + } + + for (i = 0; i < new_capacity; i++) { + + struct hashtab_entry *entry = &new_entries[i]; + + entry->key = NULL; + entry->value = NULL; + + } + + old_entries = table->entries; + old_capacity = table->capacity; + + new_count = 0; + + for (i = 0; i < old_capacity; i++) { + + struct hashtab_entry *entry = &old_entries[i], *dest; + + if (entry->key == NULL) { + continue; + } + + dest = find_entry (new_entries, new_capacity, entry->key); + + dest->key = entry->key; + dest->value = entry->value; + + new_count++; + + } + + free (old_entries); + + table->capacity = new_capacity; + table->count = new_count; + table->entries = new_entries; + table->used = new_count; + + return 0; + +} + +static struct hashtab_entry *find_entry (struct hashtab_entry *entries, unsigned int capacity, struct hashtab_name *key) { + + struct hashtab_entry *tombstone = NULL; + unsigned int index; + + for (index = key->hash % capacity; ; index = (index + 1) % capacity) { + + struct hashtab_entry *entry = &entries[index]; + + if (entry->key == NULL) { + + if (entry->value == NULL) { + + if (tombstone == NULL) { + return entry; + } + + return tombstone; + + } else if (tombstone == NULL) { + tombstone = entry; + } + + } else if (entry->key->bytes == key->bytes) { + + if (memcmp (entry->key->chars, key->chars, key->bytes) == 0 && entry->key->hash == key->hash) { + return entry; + } + + } + + } + +} + +static unsigned int hash_string (const void *p, unsigned int length) { + + unsigned char *str = (unsigned char *) p; + unsigned int i, result = 0; + + for (i = 0; i < length; i++) { + result = (((unsigned int) str[i]) << 12) + (result >> 6) + result + (result >> 3) + (((unsigned int) str[i]) << 8) - result; + } + + return result; + +} + +struct hashtab_name *hashtab_alloc_name (const char *str) { + + struct hashtab_name *name; + unsigned int bytes = strlen (str), hash = hash_string (str, bytes); + + if ((name = malloc (sizeof (*name))) == NULL) { + return NULL; + } + + name->bytes = bytes; + name->chars = str; + name->hash = hash; + + return name; + +} + +struct hashtab_name *hashtab_get_key (struct hashtab *table, const char *name) { + + struct hashtab_name *key; + struct hashtab_entry *entry; + + if (table == NULL || table->count == 0 || !(key = hashtab_alloc_name (name))) { + return 0; + } + + entry = find_entry (table->entries, table->capacity, key); + free (key); + + return entry->key; + +} + +void *hashtab_get (struct hashtab *table, struct hashtab_name *key) { + + struct hashtab_entry *entry; + + if (table == NULL || table->count == 0) { + return NULL; + } + + entry = find_entry (table->entries, table->capacity, key); + + if (entry->key == NULL) { + return NULL; + } + + return entry->value; + +} + +int hashtab_put (struct hashtab *table, struct hashtab_name *key, void *value) { + + const int MIN_CAPACITY = 15; + + struct hashtab_entry *entry; + int ret = 0; + + if (table->used >= table->capacity / 2) { + + int capacity = table->capacity * 2 - 1; + + if (capacity < MIN_CAPACITY) { + capacity = MIN_CAPACITY; + } + + if ((ret = adjust_capacity (table, capacity))) { + return ret; + } + + } + + entry = find_entry (table->entries, table->capacity, key); + + if (entry->key == NULL) { + + table->count++; + + if (entry->value == NULL) { + table->used++; + } + + } + + entry->key = key; + entry->value = value; + + return 0; + +} + +void hashtab_remove (struct hashtab *table, struct hashtab_name *key) { + + struct hashtab_entry *entry; + + if ((entry = find_entry (table->entries, table->capacity, key)) != NULL) { + + entry->key = NULL; + entry->value = NULL; + + --table->count; + + } + +} diff --git a/hashtab.h b/hashtab.h new file mode 100644 index 0000000..47aab3b --- /dev/null +++ b/hashtab.h @@ -0,0 +1,36 @@ +/****************************************************************************** + * @file hashtab.h + *****************************************************************************/ +#ifndef _HASHTAB_H +#define _HASHTAB_H + +struct hashtab_name { + + const char *chars; + int bytes, hash; + +}; + +struct hashtab_entry { + + struct hashtab_name *key; + void *value; + +}; + +struct hashtab { + + struct hashtab_entry *entries; + int capacity, count, used; + +}; + +struct hashtab_name *hashtab_alloc_name (const char *str); +struct hashtab_name *hashtab_get_key (struct hashtab *table, const char *name); + +void *hashtab_get (struct hashtab *table, struct hashtab_name *key); + +int hashtab_put (struct hashtab *table, struct hashtab_name *key, void *value); +void hashtab_remove (struct hashtab *table, struct hashtab_name *key); + +#endif /* _HASHTAB_H */ diff --git a/ld.c b/ld.c new file mode 100644 index 0000000..76eaa15 --- /dev/null +++ b/ld.c @@ -0,0 +1,686 @@ +/****************************************************************************** + * @file ld.c + *****************************************************************************/ +#include +#include +#include + +#include "aout.h" +#include "hashtab.h" +#include "ld.h" +#include "lib.h" +#include "report.h" +#include "vector.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_aout_objs; ++i) { + + struct aout_object *obj = state->aout_objs[i]; + + if (obj == NULL) { + continue; + } + + 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_aout (void *obj, unsigned long sz, const char *fname, int quiet) { + + struct aout_exec *hdr = obj; + + struct aout_object *data_obj; + struct nlist *symtab; + + struct relocation_info *trelocs; + struct relocation_info *drelocs; + + long symtab_count, trelocs_count, drelocs_count; + unsigned long symtab_off, strtab_off, trelocs_off, drelocs_off; + + char *strtab; + long i; + + if (!(hdr->a_info[0] == 0x39 && hdr->a_info[1] == 0x01 && hdr->a_info[2] == 0x64 && hdr->a_info[3] == 0x00)) { + + if (!quiet) { + report_at (program_name, 0, REPORT_ERROR, "'%s' is not a valid object", fname); + } + + return 1; + + } + + for (i = 0; i < state->nb_aout_objs; ++i) { + + struct aout_object *obj_to_compare = state->aout_objs[i]; + + if (obj_to_compare->size != sz) { + continue; + } + + if (memcmp (obj_to_compare->raw, obj, sz) == 0) { + return 0; + } + + } + + if (state->impure) { + + 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 { + + 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)))) { + 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->aout_objs, &state->nb_aout_objs, data_obj); + + for (i = 0; i < symtab_count; ++i) { + + struct 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); + + } + + } + + return 0; + +} + +struct ar_header { + + 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; + + 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; + + } + + fseek (ar_file, index, SEEK_SET); + + if (fread (&hdr, sizeof (hdr), 1, ar_file) != 1) { + + if (feof (ar_file)) { + return 0; + } + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", root_fname); + return 1; + + } + + sz = conv_dec (hdr.size, 10); + sz_aligned = (sz % 2) ? (sz + 1) : sz; + + memcpy (fname, hdr.name, 16); + + for (i = 0; i < 16; ++i) { + + if (fname[i] == 0x20 || fname[i] == '/') { + + fname[i] = '\0'; + break; + + } + + } + + 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) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", root_fname); + free (obj); + + return 1; + + } + + 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; + + } + + memset (path, 0, len); + sprintf (path, "%s(%s)", root_fname, fname); + + if (process_aout (obj, sz, path, 1)) { + + free (obj); + return 1; + + } + + } else { + + if (process_aout (obj, sz, "", 1)) { + + free (obj); + return 1; + + } + + } + + 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 (fseek (ar_file, 8, SEEK_SET) != 0) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst seeking '%s'", root_fname); + return 1; + + } + + for (;;) { + + struct ar_header hdr; + + int err, i; + unsigned long sz, sz_aligned; + + if (fread (&hdr, sizeof (hdr), 1, ar_file) != 1) { + + if (feof (ar_file)) { + break; + } + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", root_fname); + return 1; + + } + + 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; + + } + + memcpy (fname, hdr.name, 16); + + for (i = 0; i < 16; ++i) { + + if (fname[i] == 0x20 || fname[i] == '/') { + + fname[i] = '\0'; + break; + + } + + } + + 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) { + + report_at (program_name, 0, REPORT_ERROR, "failed whilst reading '%s'", root_fname); + free (obj); + + return 1; + + } + + 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; + + } + + memset (path, 0, len); + sprintf (path, "%s(%s)", root_fname, fname); + + if ((err = process_aout (obj, sz, path, 1))) { + free (obj); + } + + } else { + + if ((err = process_aout (obj, sz, "", 1))) { + free (obj); + } + + } + + 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, "!\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_aout (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->ofile) { + state->ofile = xstrdup ("a.out"); + } + + if (state->format == LD_OUTPUT_BIN || state->format == LD_OUTPUT_COM) { + + if (state->format == LD_OUTPUT_COM) { + state->psp = 0x100; + } + + state->impure = 1; + + } + + for (i = 0; i < state->nb_files; i++) { + + if (process_file (state->files[i])) { + return EXIT_FAILURE; + } + + } + + if (state->nb_aout_objs > 0) { + + if (create_executable_from_aout_objects ()) { + return EXIT_FAILURE; + } + + } + + return EXIT_SUCCESS; + +} diff --git a/ld.h b/ld.h new file mode 100644 index 0000000..741a068 --- /dev/null +++ b/ld.h @@ -0,0 +1,62 @@ +/****************************************************************************** + * @file ld.h + *****************************************************************************/ +#ifndef _LD_H +#define _LD_H + +#include "aout.h" + +struct aout_object { + + const char *filename; + void *raw; + + unsigned long size; + + struct aout_exec *header; + struct relocation_info *trelocs, *drelocs; + + struct nlist *symtab; + char *strtab; + + long symtab_count, trelocs_count, drelocs_count; + unsigned long text_slide, data_slide, bss_slide; + +}; + +#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 + +struct ld_state { + + const char **files; + long nb_files; + + const char *ofile; + FILE *ofp; + + int format, impure; + int psp; + + struct aout_object **aout_objs; + long nb_aout_objs; + + unsigned long text_size, data_size, bss_size; + +}; + +#define LD_OUTPUT_COM 0x00 +#define LD_OUTPUT_BIN 0x01 + +extern struct ld_state *state; +extern const char *program_name; + +#define FILE_ALIGNMENT 512 +#define SECTION_ALIGNMENT 4096 + +#define DIV_ROUNDUP(a, b) (((a) + ((b) - 1)) / (b)) +#define ALIGN_UP(x, a) (DIV_ROUNDUP ((x), (a)) * (a)) + +#endif /* _LD_H */ diff --git a/lib.c b/lib.c new file mode 100644 index 0000000..07fb4f6 --- /dev/null +++ b/lib.c @@ -0,0 +1,315 @@ +/****************************************************************************** + * @file lib.c + *****************************************************************************/ +#include +#include +#include +#include + +#include "ld.h" +#include "lib.h" +#include "report.h" + +#if defined (_WIN32) +# define PATHSEP ';' +#else +# define PATHSEP ':' +#endif + +struct ld_option { + + const char *name; + int idx, flgs; + +}; + +#define LD_OPTION_NO_ARG 0 +#define LD_OPTION_HAS_ARG 1 + +#define LD_OPTION_NONE 0 +#define LD_OPTION_FORMAT 1 +#define LD_OPTION_HELP 2 +#define LD_OPTION_IMPURE 3 +#define LD_OPTION_MAP 4 +#define LD_OPTION_OUTFILE 5 + +static struct ld_option opts[] = { + + { "-o", LD_OPTION_OUTFILE, LD_OPTION_HAS_ARG }, + + { "--oformat", LD_OPTION_FORMAT, LD_OPTION_HAS_ARG }, + { "--help", LD_OPTION_HELP, LD_OPTION_NO_ARG }, + + { 0, 0, 0 } + +}; + + +static void print_usage (void) { + + if (program_name) { + + 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, " --oformat FORMAT Specify the format of output file (default msdos)\n"); + fprintf (stderr, " Supported formats are:\n"); + fprintf (stderr, " binary, msdos\n"); + + /*fprintf (stderr, " -e ADDRESS Set start address.\n");*/ + fprintf (stderr, " -s Ignored.\n"); + + fprintf (stderr, " -o FILE Set output file name (default a.out).\n"); + fprintf (stderr, " --help Print this help information.\n"); + + fprintf (stderr, "\n"); + + } + +} + +char *xstrdup (const char *__p) { + + char *p = xmalloc (strlen (__p) + 1); + + strcpy (p, __p); + return p; + +} + +int xstrcasecmp (const char *__s1, const char *__s2) { + + const unsigned char *p1 = (const unsigned char *) __s1; + const unsigned char *p2 = (const unsigned char *) __s2; + + while (*p1 != '\0') { + + if (tolower ((int) *p1) < tolower ((int) *p2)) { + return (-1); + } else if (tolower ((int) *p1) > tolower ((int) *p2)) { + return (1); + } + + p1++; + p2++; + + } + + if (*p2 == '\0') { + return (0); + } + + return (-1); + +} + +int strstart (const char *val, const char **str) { + + const char *p = *str; + const char *q = val; + + while (*q != '\0') { + + if (*p != *q) { + return 0; + } + + ++p; + ++q; + + } + + *str = p; + return 1; + +} + +void dynarray_add (void *ptab, long *nb_ptr, void *data) { + + long nb, nb_alloc; + void **pp; + + nb = *nb_ptr; + pp = *(void ***) ptab; + + if ((nb & (nb - 1)) == 0) { + + if (!nb) { + nb_alloc = 1; + } else { + nb_alloc = nb * 2; + } + + pp = xrealloc (pp, nb_alloc * sizeof (void *)); + *(void ***) ptab = pp; + + } + + pp[nb++] = data; + *nb_ptr = nb; + +} + +void parse_args (int argc, char **argv, int optind) { + + struct ld_option *popt; + const char *optarg, *r; + + if (argc <= optind) { + + print_usage (); + exit (EXIT_SUCCESS); + + } + + while (optind < argc) { + + r = argv[optind++]; + + if (r[0] != '-' || r[1] == '\0') { + + dynarray_add (&state->files, &state->nb_files, xstrdup (r)); + continue; + + } + + for (popt = opts; ; popt++) { + + const char *p1 = popt->name; + const char *r1 = r; + + if (!p1) { + + report_at (program_name, 0, REPORT_ERROR, "invalid option -- '%s'", r); + exit (EXIT_FAILURE); + + } + + 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", r); + exit (EXIT_FAILURE); + + } + + optarg = argv[optind++]; + + } + + } else if (*r1 != '\0') { + continue; + } + + break; + + } + + switch (popt->idx) { + + case LD_OPTION_FORMAT: { + + if (xstrcasecmp (optarg, "binary") == 0) { + + state->format = LD_OUTPUT_BIN; + break; + + } + + if (xstrcasecmp (optarg, "msdos") == 0) { + + state->format = LD_OUTPUT_COM; + 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; + + } + + default: { + + report_at (program_name, 0, REPORT_ERROR, "unsupported option '%s'", r); + exit (EXIT_FAILURE); + + } + + } + + } + + if (!state->ofile) { state->ofile = "a.out"; } + +} + +void *xmalloc (unsigned long __size) { + + void *ptr = malloc (__size); + + if (!ptr && __size) { + + report_at (program_name, 0, REPORT_ERROR, "memory full (malloc)"); + exit (EXIT_FAILURE); + + } + + memset (ptr, 0, __size); + return ptr; + +} + +void *xrealloc (void *__ptr, unsigned long __size) { + + void *ptr = realloc (__ptr, __size); + + if (!ptr && __size) { + + report_at (program_name, 0, REPORT_ERROR, "memory full (realloc)"); + exit (EXIT_FAILURE); + + } + + return ptr; + +} diff --git a/lib.h b/lib.h new file mode 100644 index 0000000..1f82f98 --- /dev/null +++ b/lib.h @@ -0,0 +1,18 @@ +/****************************************************************************** + * @file lib.h + *****************************************************************************/ +#ifndef _LIB_H +#define _LIB_H + +int xstrcasecmp (const char *__s1, const char *__s2); + +int strstart (const char *val, const char **str); +void dynarray_add (void *ptab, long *nb_ptr, void *data); + +char *xstrdup (const char *__p); +void parse_args (int argc, char **argv, int optind); + +void *xmalloc (unsigned long __size); +void *xrealloc (void *__ptr, unsigned long __size); + +#endif /* _LIB_H */ diff --git a/report.c b/report.c new file mode 100644 index 0000000..fb010ce --- /dev/null +++ b/report.c @@ -0,0 +1,149 @@ +/****************************************************************************** + * @file report.c + *****************************************************************************/ +#include +#include +#include + +#include "report.h" +unsigned int errors = 0; + +#ifndef __PDOS__ +#if defined (_WIN32) +# include +static int OriginalConsoleColor = -1; +#endif + +static void reset_console_color (void) { + +#if defined (_WIN32) + + HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE); + + if (OriginalConsoleColor == -1) { return; } + + SetConsoleTextAttribute (hStdError, OriginalConsoleColor); + OriginalConsoleColor = -1; + +#else + + fprintf (stderr, "\033[0m"); + +#endif + +} + +static void set_console_color (int color) { + +#if defined (_WIN32) + + HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE); + WORD wColor; + + if (OriginalConsoleColor == -1) { + + CONSOLE_SCREEN_BUFFER_INFO csbi; + + if (!GetConsoleScreenBufferInfo (hStdError, &csbi)) { + return; + } + + OriginalConsoleColor = csbi.wAttributes; + + } + + wColor = (OriginalConsoleColor & 0xF0) + (color & 0xF); + SetConsoleTextAttribute (hStdError, wColor); + +#else + + fprintf (stderr, "\033[%dm", color); + +#endif + +} +#endif + +static void output_message (const char *filename, unsigned int lineno, unsigned int idx, int type, const char *fmt, va_list ap) { + + if (filename) { + + if (lineno == 0) { + fprintf (stderr, "%s: ", filename); + } else { + fprintf (stderr, "%s:", filename); + } + + } + + if (lineno > 0) { + + if (idx == 0) { + fprintf (stderr, "%u: ", lineno); + } else { + fprintf (stderr, "%u:", lineno); + } + + } + + if (idx > 0) { + fprintf (stderr, "%u: ", idx); + } + + if (type == REPORT_ERROR || type == REPORT_FATAL_ERROR) { + +#ifndef __PDOS__ + set_console_color (COLOR_ERROR); +#endif + + if (type == REPORT_ERROR) { + fprintf (stderr, "error:"); + } else { + fprintf (stderr, "fatal error:"); + } + + } else if (type == REPORT_INTERNAL_ERROR) { + +#ifndef __PDOS__ + set_console_color (COLOR_INTERNAL_ERROR); +#endif + + fprintf (stderr, "internal error:"); + + } else if (type == REPORT_WARNING) { + +#ifndef __PDOS__ + set_console_color (COLOR_WARNING); +#endif + + fprintf (stderr, "warning:"); + + } + +#ifndef __PDOS__ + reset_console_color (); +#endif + + fprintf (stderr, " "); + vfprintf (stderr, fmt, ap); + fprintf (stderr, "\n"); + + if (type != REPORT_WARNING) { + ++errors; + } + +} + +unsigned int get_error_count (void) { + return errors; +} + +void report_at (const char *filename, unsigned int lineno, int type, const char *fmt, ...) { + + va_list ap; + + va_start (ap, fmt); + output_message (filename, lineno, 0, type, fmt, ap); + va_end (ap); + +} diff --git a/report.h b/report.h new file mode 100644 index 0000000..8e694dd --- /dev/null +++ b/report.h @@ -0,0 +1,25 @@ +/****************************************************************************** + * @file report.h + *****************************************************************************/ +#ifndef _REPORT_H +#define _REPORT_H + +#if defined (_WIN32) +# define COLOR_ERROR 12 +# define COLOR_WARNING 13 +# define COLOR_INTERNAL_ERROR 19 +#else +# define COLOR_ERROR 91 +# define COLOR_INTERNAL_ERROR 94 +# define COLOR_WARNING 95 +#endif + +#define REPORT_WARNING 0 +#define REPORT_ERROR 1 +#define REPORT_FATAL_ERROR 3 +#define REPORT_INTERNAL_ERROR 4 + +unsigned int get_error_count (void); +void report_at (const char *filename, unsigned int lineno, int type, const char *fmt, ...); + +#endif /* _REPORT_H */ diff --git a/vector.c b/vector.c new file mode 100644 index 0000000..3984039 --- /dev/null +++ b/vector.c @@ -0,0 +1,54 @@ +/****************************************************************************** + * @file vector.c + *****************************************************************************/ +#include +#include + +#include "vector.h" + +extern void *xrealloc (void *__ptr, unsigned int __size); + +int vec_adjust (struct vector *vec, int length) { + + if (vec->capacity <= length) { + + if (vec->capacity == 0) { + vec->capacity = 16; + } else { + vec->capacity <<= 1; + } + + vec->data = xrealloc (vec->data, sizeof (*(vec->data)) * vec->capacity); + + } + + return 0; + +} + +void *vec_pop (struct vector *vec) { + + if (!vec || vec == NULL) { + return NULL; + } + + if (vec->length == 0) { + return NULL; + } + + return vec->data[--vec->length]; + +} + +int vec_push (struct vector *vec, void *elem) { + + int ret; + + if ((ret = vec_adjust (vec, vec->length)) != 0) { + return ret; + } + + vec->data[vec->length++] = elem; + return 0; + +} diff --git a/vector.h b/vector.h new file mode 100644 index 0000000..29d957a --- /dev/null +++ b/vector.h @@ -0,0 +1,19 @@ +/****************************************************************************** + * @file vector.h + *****************************************************************************/ +#ifndef _VECTOR_H +#define _VECTOR_H + +struct vector { + + void **data; + int capacity, length; + +}; + +int vec_adjust (struct vector *vec, int length); +int vec_push (struct vector *vec, void *elem); + +void *vec_pop (struct vector *vec); + +#endif /* _VECTOR_H */ diff --git a/write7x.c b/write7x.c new file mode 100644 index 0000000..144d71c --- /dev/null +++ b/write7x.c @@ -0,0 +1,26 @@ +/****************************************************************************** + * @file write7x.c + *****************************************************************************/ +#include + +#include "write7x.h" + +void write721_to_byte_array (unsigned char *dest, unsigned int val) { + + int i; + + for (i = 0; i < 2; ++i) { + dest[i] = (val >> (CHAR_BIT * i)) & UCHAR_MAX; + } + +} + +void write741_to_byte_array (unsigned char *dest, unsigned long val) { + + int i; + + for (i = 0; i < 4; ++i) { + dest[i] = (val >> (CHAR_BIT * i)) & UCHAR_MAX; + } + +} diff --git a/write7x.h b/write7x.h new file mode 100644 index 0000000..056910b --- /dev/null +++ b/write7x.h @@ -0,0 +1,10 @@ +/****************************************************************************** + * @file write7x.h + *****************************************************************************/ +#ifndef _WRITE7X_H +#define _WRITE7X_H + +void write721_to_byte_array (unsigned char *dest, unsigned int val); +void write741_to_byte_array (unsigned char *dest, unsigned long val); + +#endif /* _WRITE7X_H */