summaryrefslogtreecommitdiff
path: root/lib/linker.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/linker.c')
-rw-r--r--lib/linker.c314
1 files changed, 314 insertions, 0 deletions
diff --git a/lib/linker.c b/lib/linker.c
new file mode 100644
index 0000000..5fe1162
--- /dev/null
+++ b/lib/linker.c
@@ -0,0 +1,314 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "config.h"
+#include "linker.h"
+#include "types.h"
+#include "exceptions.h"
+#include "hash.h"
+
+typedef struct object_t {
+ Uint32 s_text, s_data, s_bss, * text, * data, textstart, datastart, bssstart;
+} object_t;
+
+typedef struct symbol_t {
+ char * name;
+ int objindex;
+ Uint32 offset;
+ int type;
+ struct symbol_t * next;
+} symbol_t;
+
+Uint32 startpoint = -1, textsize = 0, datasize = 0, bsssize = 0;
+
+object_t ** objects;
+symbol_t * symbols, * psymbols;
+int objindex = 0, nbrsymbs = 0;
+
+_TableauVariable symbs;
+
+static FILE * openfilewriting(char * name) {
+ FILE * f;
+
+ if (!(f = fopen(name, "wb"))) {
+ pushcontext(strerror(errno));
+ exception(1, _("Error writing file"));
+ }
+ return f;
+}
+
+static FILE * openfilereading(char * name) {
+ FILE * f;
+
+ if (!(f = fopen(name, "rb"))) {
+ pushcontext(strerror(errno));
+ exception(1, _("Error reading file"));
+ }
+ return f;
+}
+
+static void writeword(Uint32 a, FILE * f) {
+ if (fwrite(&a, sizeof(unsigned long int), 1, f) != 1) {
+ if (ferror(f)) {
+ pushcontext(strerror(errno));
+ }
+ exception(1, _("Error writing file"));
+ }
+}
+
+static Uint32 readword(FILE * f) {
+ Uint32 a;
+
+ if (fread(&a, sizeof(a), 1, f) != 1) {
+ exception(1, _("premature end of file"));
+ }
+ return a;
+}
+
+static char * readstring(FILE * f) {
+ Uint32 s;
+ char * r;
+ int i;
+
+ s = readword(f);
+ r = (char *) Emalloc(s + 1);
+ for (i = 0; i < s; i++) {
+ r[i] = readword(f);
+ }
+ r[i] = '\0';
+ return r;
+}
+
+static void addsymbol(char * name, int offset, int type) {
+ symbol_t * newsymbol;
+
+ newsymbol = (symbol_t *) Emalloc(sizeof(symbol_t));
+ newsymbol->next = NULL;
+ newsymbol->type = type;
+ newsymbol->offset = offset;
+ newsymbol->objindex = objindex;
+ newsymbol->name = name;
+
+ psymbols->next = newsymbol;
+ psymbols = newsymbol;
+
+ if (newsymbol->type & 1) {
+ nbrsymbs++;
+ } else {
+ InsererVarDansTab(&symbs, CreerElement(name, newsymbol));
+ }
+}
+
+void addfile(char * nom) {
+ FILE * f;
+ Uint32 start, nbsymbols, type, offset;
+ int i;
+ char * snom, errctx[BUFSIZ];
+
+ f = openfilereading(nom);
+ sprintf(errctx, _("Processing file %s"), nom);
+ pushcontext(errctx);
+
+ if (readword(f) != 0x4f424e4e) {
+ exception(1, _("Bad signature"));
+ }
+
+ readword(f); /* Taille du fichier */
+ start = readword(f);
+ if ((startpoint != -1) && (start != -1)) {
+ exception(1, _("Startpoint already defined."));
+ }
+ startpoint = start;
+
+ objects[objindex]->s_text = readword(f);
+ objects[objindex]->s_data = readword(f);
+ objects[objindex]->s_bss = readword(f);
+ readword(f); /* Taille de la table des symboles */
+ nbsymbols = readword(f);
+
+ pushcontext(_("Reading symbols"));
+ for (i = 0; i < nbsymbols; i++) {
+ type = readword(f);
+ offset = readword(f);
+ snom = readstring(f);
+ addsymbol(snom, offset, type);
+ }
+ popcontext();
+
+ objects[objindex]->textstart = textsize;
+ objects[objindex]->datastart = datasize;
+ objects[objindex]->bssstart = bsssize;
+
+ objects[objindex]->text = (Uint32 *) Emalloc(objects[objindex]->s_text * sizeof(Uint32));
+ objects[objindex]->data = (Uint32 *) Emalloc(objects[objindex]->s_data * sizeof(Uint32));
+
+ pushcontext(_("Reading text and data segments"));
+ for (i = 0; i < objects[objindex]->s_text; i++) {
+ objects[objindex]->text[i] = readword(f);
+ }
+
+ for (i = 0; i < objects[objindex]->s_data; i++) {
+ objects[objindex]->data[i] = readword(f);
+ }
+ popcontext();
+ fclose(f);
+
+ textsize += objects[objindex]->s_text;
+ datasize += objects[objindex]->s_data;
+ bsssize += objects[objindex]->s_bss;
+
+ objindex++;
+ popcontext();
+}
+
+static void dumptab(Uint32 * tab, int s, FILE * f) {
+ int i;
+
+ for (i = 0; i < s; i++) {
+ writeword(tab[i], f);
+ }
+}
+
+static void dumptext(object_t * obj, FILE * f) {
+ dumptab(obj->text, obj->s_text, f);
+}
+
+static void dumpdata(object_t * obj, FILE * f) {
+ dumptab(obj->data, obj->s_data, f);
+}
+
+static void dumprelog(FILE * f) {
+ symbol_t * s = symbols, * t;
+ char trouve, err[BUFSIZ];
+
+ for (s = s->next; s; s = s->next) {
+ if (s->type & 1) {
+ t = (symbol_t *) NomVarToVar(s->name, symbs, &trouve);
+ if (!trouve) {
+ sprintf(err, _("Symbol %s not found"), s->name);
+ exception(1, err);
+ }
+ switch(s->type) {
+ case 1: /* text */
+ switch(t->type) {
+ case 0:
+ objects[s->objindex]->text[s->offset] += objects[t->objindex]->textstart + t->offset;
+ break;
+ case 2:
+ objects[s->objindex]->text[s->offset] += textsize + objects[t->objindex]->datastart + t->offset;
+ break;
+ case 4:
+ objects[s->objindex]->text[s->offset] += textsize + datasize + objects[t->objindex]->bssstart + t->offset;
+ break;
+ default:
+ exception(1, _("Internal error"));
+ break;
+ }
+ writeword(objects[s->objindex]->textstart + s->offset, f);
+ break;
+ case 3: /* data */
+ switch(t->type) {
+ case 0:
+ objects[s->objindex]->data[s->offset] += objects[t->objindex]->textstart + t->offset;
+ break;
+ case 2:
+ objects[s->objindex]->data[s->offset] += textsize + objects[t->objindex]->datastart + t->offset;
+ break;
+ case 4:
+ objects[s->objindex]->data[s->offset] += textsize + datasize + objects[t->objindex]->bssstart + t->offset;
+ break;
+ default:
+ exception(1, _("Internal error"));
+ break;
+ }
+ writeword(textsize + objects[s->objindex]->datastart + s->offset, f);
+ break;
+ default:
+ exception(1, _("Internal error"));
+ break;
+ }
+ }
+ }
+}
+
+void dumpfile(char * nom) {
+ FILE * f;
+ int i;
+
+ pushcontext(_("Writing output file"));
+ f = openfilewriting(nom);
+
+ if (startpoint == -1) {
+ exception(1, _("No startpoint defined."));
+ }
+
+ pushcontext(_("Writing headers"));
+ writeword(0x58454e4e, f);
+ writeword(nbrsymbs + textsize + datasize + 7, f);
+ writeword(textsize, f);
+ writeword(datasize, f);
+ writeword(bsssize, f);
+ writeword(nbrsymbs, f);
+ popcontext();
+ pushcontext(_("Writing relocating informations"));
+ dumprelog(f);
+ popcontext();
+ pushcontext(_("Writing text segments"));
+ for (i = 0; i < objindex; i++) {
+ dumptext(objects[i], f);
+ }
+ popcontext();
+ pushcontext(_("Writing data segments"));
+ for (i = 0; i < objindex; i++) {
+ dumpdata(objects[i], f);
+ }
+ popcontext();
+
+ popcontext();
+ fprintf(stderr, _("Statistics: %i words of text, %i words of data and reserving %i words\n"), textsize, datasize, bsssize);
+ fprintf(stderr, _("Output file size: %i words containing %i relocating offsets.\n"), ftell(f), nbrsymbs);
+ fclose(f);
+}
+
+void init(int n) {
+ int i;
+
+ Initialise(&symbs);
+
+ objects = (object_t **) Emalloc(n * sizeof(object_t *));
+ psymbols = symbols = (symbol_t *) Emalloc(sizeof(symbol_t));
+
+ for (i = 0; i < n; i++) {
+ objects[i] = (object_t *) Emalloc(sizeof(object_t));
+ objects[i]->s_text = objects[i]->s_data = objects[i]->s_bss = objects[i]->textstart = objects[i]->datastart = 0;
+ objects[i]->text = objects[i]->data = NULL;
+ }
+
+ symbols->next = NULL;
+}
+
+void free_symbol(symbol_t * s) {
+ if (s->next)
+ free_symbol(s);
+
+ free(s->name);
+ free(s);
+}
+
+void flush(void) {
+ int i;
+
+ DetruitTab(&symbs);
+
+ for (i = 0; i < objindex; i++) {
+ if (objects[i]->text)
+ free(objects[i]->text);
+ if (objects[i]->data);
+ free(objects[i]->data);
+ free(objects[i]);
+ }
+ free(objects);
+}