/*
|
/*
|
* ld.c -- ECO32 linking loader
|
* ld.c -- ECO32 linking loader
|
*/
|
*/
|
|
|
|
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <string.h>
|
#include <string.h>
|
#include <stdarg.h>
|
#include <stdarg.h>
|
#include <ctype.h>
|
#include <ctype.h>
|
#include <unistd.h>
|
#include <unistd.h>
|
|
|
#include "../include/a.out.h"
|
#include "../include/a.out.h"
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
#define MAX_STRLEN 200
|
#define MAX_STRLEN 200
|
|
|
#define PAGE_SHIFT 12
|
#define PAGE_SHIFT 12
|
#define PAGE_SIZE (1 << PAGE_SHIFT)
|
#define PAGE_SIZE (1 << PAGE_SHIFT)
|
#define PAGE_MASK (PAGE_SIZE - 1)
|
#define PAGE_MASK (PAGE_SIZE - 1)
|
#define PAGE_ROUND(n) (((n) + PAGE_SIZE - 1) & ~PAGE_MASK)
|
#define PAGE_ROUND(n) (((n) + PAGE_SIZE - 1) & ~PAGE_MASK)
|
|
|
#define MSB ((unsigned int) 1 << (sizeof(unsigned int) * 8 - 1))
|
#define MSB ((unsigned int) 1 << (sizeof(unsigned int) * 8 - 1))
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
int debugLink = 0;
|
int debugLink = 0;
|
int debugFixup = 0;
|
int debugFixup = 0;
|
|
|
int withHeader = 1;
|
int withHeader = 1;
|
|
|
char codeName[L_tmpnam];
|
char codeName[L_tmpnam];
|
char dataName[L_tmpnam];
|
char dataName[L_tmpnam];
|
char *outName = NULL;
|
char *outName = NULL;
|
char *mapName = NULL;
|
char *mapName = NULL;
|
char *inName = NULL;
|
char *inName = NULL;
|
|
|
FILE *codeFile = NULL;
|
FILE *codeFile = NULL;
|
FILE *dataFile = NULL;
|
FILE *dataFile = NULL;
|
FILE *outFile = NULL;
|
FILE *outFile = NULL;
|
FILE *mapFile = NULL;
|
FILE *mapFile = NULL;
|
FILE *inFile = NULL;
|
FILE *inFile = NULL;
|
|
|
unsigned int segPtr[4] = { 0, 0, 0, 0 };
|
unsigned int segPtr[4] = { 0, 0, 0, 0 };
|
int segStartDefined[4] = { 0, 0, 0, 0 };
|
int segStartDefined[4] = { 0, 0, 0, 0 };
|
unsigned int segStart[4] = { 0, 0, 0, 0 };
|
unsigned int segStart[4] = { 0, 0, 0, 0 };
|
char *segName[4] = { "ABS", "CODE", "DATA", "BSS" };
|
char *segName[4] = { "ABS", "CODE", "DATA", "BSS" };
|
char *methodName[5] = { "H16", "L16", "R16", "R26", "W32" };
|
char *methodName[5] = { "H16", "L16", "R16", "R26", "W32" };
|
|
|
|
|
typedef struct reloc {
|
typedef struct reloc {
|
int segment; /* in which segment to relocate */
|
int segment; /* in which segment to relocate */
|
unsigned int offset; /* where in the segment to relocate */
|
unsigned int offset; /* where in the segment to relocate */
|
int method; /* how to relocate */
|
int method; /* how to relocate */
|
int value; /* additive part of value */
|
int value; /* additive part of value */
|
int type; /* 0: base is a segment */
|
int type; /* 0: base is a segment */
|
/* 1: base is a symbol */
|
/* 1: base is a symbol */
|
union { /* relocation relative to .. */
|
union { /* relocation relative to .. */
|
int segment; /* .. a segment */
|
int segment; /* .. a segment */
|
struct symbol *symbol; /* .. a symbol */
|
struct symbol *symbol; /* .. a symbol */
|
} base;
|
} base;
|
struct reloc *next; /* next relocation */
|
struct reloc *next; /* next relocation */
|
} Reloc;
|
} Reloc;
|
|
|
|
|
typedef struct symbol {
|
typedef struct symbol {
|
char *name; /* name of symbol */
|
char *name; /* name of symbol */
|
int type; /* if MSB = 0: the symbol's segment */
|
int type; /* if MSB = 0: the symbol's segment */
|
/* if MSB = 1: the symbol is undefined */
|
/* if MSB = 1: the symbol is undefined */
|
int value; /* if symbol defined: the symbol's value */
|
int value; /* if symbol defined: the symbol's value */
|
/* if symbol not defined: meaningless */
|
/* if symbol not defined: meaningless */
|
struct symbol *left; /* left son in binary search tree */
|
struct symbol *left; /* left son in binary search tree */
|
struct symbol *right; /* right son in binary search tree */
|
struct symbol *right; /* right son in binary search tree */
|
} Symbol;
|
} Symbol;
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
void error(char *fmt, ...) {
|
void error(char *fmt, ...) {
|
va_list ap;
|
va_list ap;
|
|
|
va_start(ap, fmt);
|
va_start(ap, fmt);
|
fprintf(stderr, "Error: ");
|
fprintf(stderr, "Error: ");
|
vfprintf(stderr, fmt, ap);
|
vfprintf(stderr, fmt, ap);
|
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
va_end(ap);
|
va_end(ap);
|
if (codeFile != NULL) {
|
if (codeFile != NULL) {
|
fclose(codeFile);
|
fclose(codeFile);
|
codeFile = NULL;
|
codeFile = NULL;
|
}
|
}
|
if (dataFile != NULL) {
|
if (dataFile != NULL) {
|
fclose(dataFile);
|
fclose(dataFile);
|
dataFile = NULL;
|
dataFile = NULL;
|
}
|
}
|
if (outFile != NULL) {
|
if (outFile != NULL) {
|
fclose(outFile);
|
fclose(outFile);
|
outFile = NULL;
|
outFile = NULL;
|
}
|
}
|
if (mapFile != NULL) {
|
if (mapFile != NULL) {
|
fclose(mapFile);
|
fclose(mapFile);
|
mapFile = NULL;
|
mapFile = NULL;
|
}
|
}
|
if (inFile != NULL) {
|
if (inFile != NULL) {
|
fclose(inFile);
|
fclose(inFile);
|
inFile = NULL;
|
inFile = NULL;
|
}
|
}
|
if (codeName != NULL) {
|
if (codeName != NULL) {
|
unlink(codeName);
|
unlink(codeName);
|
}
|
}
|
if (dataName != NULL) {
|
if (dataName != NULL) {
|
unlink(dataName);
|
unlink(dataName);
|
}
|
}
|
if (outName != NULL) {
|
if (outName != NULL) {
|
unlink(outName);
|
unlink(outName);
|
}
|
}
|
if (mapName != NULL) {
|
if (mapName != NULL) {
|
unlink(mapName);
|
unlink(mapName);
|
}
|
}
|
exit(1);
|
exit(1);
|
}
|
}
|
|
|
|
|
void *allocateMemory(unsigned int size) {
|
void *allocateMemory(unsigned int size) {
|
void *p;
|
void *p;
|
|
|
p = malloc(size);
|
p = malloc(size);
|
if (p == NULL) {
|
if (p == NULL) {
|
error("out of memory");
|
error("out of memory");
|
}
|
}
|
return p;
|
return p;
|
}
|
}
|
|
|
|
|
void freeMemory(void *p) {
|
void freeMemory(void *p) {
|
free(p);
|
free(p);
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
Reloc *relocs = NULL;
|
Reloc *relocs = NULL;
|
|
|
|
|
void addReloc(int segment, RelocRecord *relRec, Symbol **symMap) {
|
void addReloc(int segment, RelocRecord *relRec, Symbol **symMap) {
|
Reloc *rel;
|
Reloc *rel;
|
|
|
rel = allocateMemory(sizeof(Reloc));
|
rel = allocateMemory(sizeof(Reloc));
|
rel->segment = segment;
|
rel->segment = segment;
|
rel->offset = relRec->offset + segPtr[segment];
|
rel->offset = relRec->offset + segPtr[segment];
|
rel->method = relRec->method;
|
rel->method = relRec->method;
|
rel->value = relRec->value;
|
rel->value = relRec->value;
|
if ((relRec->base & MSB) == 0) {
|
if ((relRec->base & MSB) == 0) {
|
/* relocation is relative to a segment */
|
/* relocation is relative to a segment */
|
rel->type = 0;
|
rel->type = 0;
|
rel->base.segment = relRec->base;
|
rel->base.segment = relRec->base;
|
rel->value += segPtr[relRec->base];
|
rel->value += segPtr[relRec->base];
|
} else {
|
} else {
|
/* relocation is relative to a symbol */
|
/* relocation is relative to a symbol */
|
rel->type = 1;
|
rel->type = 1;
|
rel->base.symbol = symMap[relRec->base & ~MSB];
|
rel->base.symbol = symMap[relRec->base & ~MSB];
|
}
|
}
|
rel->next = relocs;
|
rel->next = relocs;
|
relocs = rel;
|
relocs = rel;
|
}
|
}
|
|
|
|
|
void linkSymbol(Reloc *rel) {
|
void linkSymbol(Reloc *rel) {
|
Symbol *sym;
|
Symbol *sym;
|
|
|
/* check if this is a reference to a symbol */
|
/* check if this is a reference to a symbol */
|
if (rel->type != 1) {
|
if (rel->type != 1) {
|
/* no: nothing to do here */
|
/* no: nothing to do here */
|
return;
|
return;
|
}
|
}
|
/* get information from the symbol table record */
|
/* get information from the symbol table record */
|
sym = rel->base.symbol;
|
sym = rel->base.symbol;
|
if (sym->type & MSB) {
|
if (sym->type & MSB) {
|
error("undefined symbol '%s'", sym->name);
|
error("undefined symbol '%s'", sym->name);
|
}
|
}
|
/* output debugging info */
|
/* output debugging info */
|
if (debugLink) {
|
if (debugLink) {
|
printf("DEBUG: link '%s' (s:%s, v:%08X)\n",
|
printf("DEBUG: link '%s' (s:%s, v:%08X)\n",
|
sym->name, segName[sym->type], sym->value);
|
sym->name, segName[sym->type], sym->value);
|
printf(" (s:%s, o:%08X, m:%s, v:%08X --> %08X, b:%s)\n",
|
printf(" (s:%s, o:%08X, m:%s, v:%08X --> %08X, b:%s)\n",
|
segName[rel->segment], rel->offset, methodName[rel->method],
|
segName[rel->segment], rel->offset, methodName[rel->method],
|
rel->value, rel->value + sym->value, segName[sym->type]);
|
rel->value, rel->value + sym->value, segName[sym->type]);
|
}
|
}
|
/* update relocation information */
|
/* update relocation information */
|
rel->value += sym->value;
|
rel->value += sym->value;
|
rel->type = 0;
|
rel->type = 0;
|
rel->base.segment = sym->type;
|
rel->base.segment = sym->type;
|
}
|
}
|
|
|
|
|
void linkSymbols(void) {
|
void linkSymbols(void) {
|
Reloc *rel;
|
Reloc *rel;
|
|
|
rel = relocs;
|
rel = relocs;
|
while (rel != NULL) {
|
while (rel != NULL) {
|
linkSymbol(rel);
|
linkSymbol(rel);
|
rel = rel->next;
|
rel = rel->next;
|
}
|
}
|
}
|
}
|
|
|
|
|
void fixupRef(Reloc *rel) {
|
void fixupRef(Reloc *rel) {
|
FILE *file;
|
FILE *file;
|
unsigned int value;
|
unsigned int value;
|
unsigned int final;
|
unsigned int final;
|
|
|
/* determine the segment in which to do fixup */
|
/* determine the segment in which to do fixup */
|
switch (rel->segment) {
|
switch (rel->segment) {
|
case SEGMENT_ABS:
|
case SEGMENT_ABS:
|
/* this should never happen */
|
/* this should never happen */
|
error("cannot do fixup in ABS");
|
error("cannot do fixup in ABS");
|
break;
|
break;
|
case SEGMENT_CODE:
|
case SEGMENT_CODE:
|
file = codeFile;
|
file = codeFile;
|
break;
|
break;
|
case SEGMENT_DATA:
|
case SEGMENT_DATA:
|
file = dataFile;
|
file = dataFile;
|
break;
|
break;
|
case SEGMENT_BSS:
|
case SEGMENT_BSS:
|
/* this should never happen */
|
/* this should never happen */
|
error("cannot do fixup in BSS");
|
error("cannot do fixup in BSS");
|
break;
|
break;
|
default:
|
default:
|
/* this should never happen */
|
/* this should never happen */
|
error("illegal segment in doFixup()");
|
error("illegal segment in doFixup()");
|
break;
|
break;
|
}
|
}
|
/* check that the base is indeed a segment */
|
/* check that the base is indeed a segment */
|
if (rel->type != 0) {
|
if (rel->type != 0) {
|
/* this should never happen */
|
/* this should never happen */
|
error("fixup cannot handle reference to symbol");
|
error("fixup cannot handle reference to symbol");
|
}
|
}
|
/* now patch according to method */
|
/* now patch according to method */
|
switch (rel->method) {
|
switch (rel->method) {
|
case METHOD_H16:
|
case METHOD_H16:
|
value = rel->value + segStart[rel->base.segment];
|
value = rel->value + segStart[rel->base.segment];
|
final = (value >> 16) & 0x0000FFFF;
|
final = (value >> 16) & 0x0000FFFF;
|
fseek(file, rel->offset + 2, SEEK_SET);
|
fseek(file, rel->offset + 2, SEEK_SET);
|
fputc((final >> 8) & 0xFF, file);
|
fputc((final >> 8) & 0xFF, file);
|
fputc((final >> 0) & 0xFF, file);
|
fputc((final >> 0) & 0xFF, file);
|
break;
|
break;
|
case METHOD_L16:
|
case METHOD_L16:
|
value = rel->value + segStart[rel->base.segment];
|
value = rel->value + segStart[rel->base.segment];
|
final = value & 0x0000FFFF;
|
final = value & 0x0000FFFF;
|
fseek(file, rel->offset + 2, SEEK_SET);
|
fseek(file, rel->offset + 2, SEEK_SET);
|
fputc((final >> 8) & 0xFF, file);
|
fputc((final >> 8) & 0xFF, file);
|
fputc((final >> 0) & 0xFF, file);
|
fputc((final >> 0) & 0xFF, file);
|
break;
|
break;
|
case METHOD_R16:
|
case METHOD_R16:
|
value = (rel->value - (rel->offset + 4)) / 4;
|
value = (rel->value - (rel->offset + 4)) / 4;
|
final = value & 0x0000FFFF;
|
final = value & 0x0000FFFF;
|
fseek(file, rel->offset + 2, SEEK_SET);
|
fseek(file, rel->offset + 2, SEEK_SET);
|
fputc((final >> 8) & 0xFF, file);
|
fputc((final >> 8) & 0xFF, file);
|
fputc((final >> 0) & 0xFF, file);
|
fputc((final >> 0) & 0xFF, file);
|
break;
|
break;
|
case METHOD_R26:
|
case METHOD_R26:
|
value = (rel->value - (rel->offset + 4)) / 4;
|
value = (rel->value - (rel->offset + 4)) / 4;
|
fseek(file, rel->offset, SEEK_SET);
|
fseek(file, rel->offset, SEEK_SET);
|
final = (fgetc(file) << 24) & 0xFC000000;
|
final = (fgetc(file) << 24) & 0xFC000000;
|
final |= value & 0x03FFFFFF;
|
final |= value & 0x03FFFFFF;
|
fseek(file, -1, SEEK_CUR);
|
fseek(file, -1, SEEK_CUR);
|
fputc((final >> 24) & 0xFF, file);
|
fputc((final >> 24) & 0xFF, file);
|
fputc((final >> 16) & 0xFF, file);
|
fputc((final >> 16) & 0xFF, file);
|
fputc((final >> 8) & 0xFF, file);
|
fputc((final >> 8) & 0xFF, file);
|
fputc((final >> 0) & 0xFF, file);
|
fputc((final >> 0) & 0xFF, file);
|
break;
|
break;
|
case METHOD_W32:
|
case METHOD_W32:
|
value = rel->value + segStart[rel->base.segment];
|
value = rel->value + segStart[rel->base.segment];
|
final = value;
|
final = value;
|
fseek(file, rel->offset, SEEK_SET);
|
fseek(file, rel->offset, SEEK_SET);
|
fputc((final >> 24) & 0xFF, file);
|
fputc((final >> 24) & 0xFF, file);
|
fputc((final >> 16) & 0xFF, file);
|
fputc((final >> 16) & 0xFF, file);
|
fputc((final >> 8) & 0xFF, file);
|
fputc((final >> 8) & 0xFF, file);
|
fputc((final >> 0) & 0xFF, file);
|
fputc((final >> 0) & 0xFF, file);
|
break;
|
break;
|
default:
|
default:
|
/* this should never happen */
|
/* this should never happen */
|
error("illegal method in doFixup()");
|
error("illegal method in doFixup()");
|
break;
|
break;
|
}
|
}
|
/* output debugging info */
|
/* output debugging info */
|
if (debugFixup) {
|
if (debugFixup) {
|
printf("DEBUG: fixup (s:%s, o:%08X, m:%s, v:%08X), %08X --> %08X\n",
|
printf("DEBUG: fixup (s:%s, o:%08X, m:%s, v:%08X), %08X --> %08X\n",
|
segName[rel->segment], rel->offset, methodName[rel->method],
|
segName[rel->segment], rel->offset, methodName[rel->method],
|
rel->value, value, final);
|
rel->value, value, final);
|
}
|
}
|
}
|
}
|
|
|
|
|
void relocateSegments(void) {
|
void relocateSegments(void) {
|
Reloc *rel;
|
Reloc *rel;
|
|
|
/* determine start of segments */
|
/* determine start of segments */
|
if (!segStartDefined[SEGMENT_CODE]) {
|
if (!segStartDefined[SEGMENT_CODE]) {
|
segStart[SEGMENT_CODE] = 0;
|
segStart[SEGMENT_CODE] = 0;
|
segStartDefined[SEGMENT_CODE] = 1;
|
segStartDefined[SEGMENT_CODE] = 1;
|
}
|
}
|
if (!segStartDefined[SEGMENT_DATA]) {
|
if (!segStartDefined[SEGMENT_DATA]) {
|
segStart[SEGMENT_DATA] = segStart[SEGMENT_CODE] +
|
segStart[SEGMENT_DATA] = segStart[SEGMENT_CODE] +
|
PAGE_ROUND(segPtr[SEGMENT_CODE]);
|
PAGE_ROUND(segPtr[SEGMENT_CODE]);
|
segStartDefined[SEGMENT_DATA] = 1;
|
segStartDefined[SEGMENT_DATA] = 1;
|
}
|
}
|
if (!segStartDefined[SEGMENT_BSS]) {
|
if (!segStartDefined[SEGMENT_BSS]) {
|
segStart[SEGMENT_BSS] = segStart[SEGMENT_DATA] +
|
segStart[SEGMENT_BSS] = segStart[SEGMENT_DATA] +
|
segPtr[SEGMENT_DATA];
|
segPtr[SEGMENT_DATA];
|
segStartDefined[SEGMENT_BSS] = 1;
|
segStartDefined[SEGMENT_BSS] = 1;
|
}
|
}
|
/* fixup all references (which now are only relative to segments) */
|
/* fixup all references (which now are only relative to segments) */
|
while (relocs != NULL) {
|
while (relocs != NULL) {
|
rel = relocs;
|
rel = relocs;
|
relocs = rel->next;
|
relocs = rel->next;
|
fixupRef(rel);
|
fixupRef(rel);
|
freeMemory(rel);
|
freeMemory(rel);
|
}
|
}
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
Symbol *symbolTable = NULL;
|
Symbol *symbolTable = NULL;
|
|
|
|
|
Symbol *newSymbol(char *name) {
|
Symbol *newSymbol(char *name) {
|
Symbol *p;
|
Symbol *p;
|
|
|
p = allocateMemory(sizeof(Symbol));
|
p = allocateMemory(sizeof(Symbol));
|
p->name = allocateMemory(strlen(name) + 1);
|
p->name = allocateMemory(strlen(name) + 1);
|
strcpy(p->name, name);
|
strcpy(p->name, name);
|
p->type = MSB;
|
p->type = MSB;
|
p->value = 0;
|
p->value = 0;
|
p->left = NULL;
|
p->left = NULL;
|
p->right = NULL;
|
p->right = NULL;
|
return p;
|
return p;
|
}
|
}
|
|
|
|
|
Symbol *lookupEnter(char *name) {
|
Symbol *lookupEnter(char *name) {
|
Symbol *p, *q, *r;
|
Symbol *p, *q, *r;
|
int cmp;
|
int cmp;
|
|
|
p = symbolTable;
|
p = symbolTable;
|
if (p == NULL) {
|
if (p == NULL) {
|
r = newSymbol(name);
|
r = newSymbol(name);
|
symbolTable = r;
|
symbolTable = r;
|
return r;
|
return r;
|
}
|
}
|
while (1) {
|
while (1) {
|
q = p;
|
q = p;
|
cmp = strcmp(name, q->name);
|
cmp = strcmp(name, q->name);
|
if (cmp == 0) {
|
if (cmp == 0) {
|
return q;
|
return q;
|
}
|
}
|
if (cmp < 0) {
|
if (cmp < 0) {
|
p = q->left;
|
p = q->left;
|
} else {
|
} else {
|
p = q->right;
|
p = q->right;
|
}
|
}
|
if (p == NULL) {
|
if (p == NULL) {
|
r = newSymbol(name);
|
r = newSymbol(name);
|
if (cmp < 0) {
|
if (cmp < 0) {
|
q->left = r;
|
q->left = r;
|
} else {
|
} else {
|
q->right = r;
|
q->right = r;
|
}
|
}
|
return r;
|
return r;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|
void walkTree(Symbol *s, void (*fp)(Symbol *sp)) {
|
void walkTree(Symbol *s, void (*fp)(Symbol *sp)) {
|
if (s == NULL) {
|
if (s == NULL) {
|
return;
|
return;
|
}
|
}
|
walkTree(s->left, fp);
|
walkTree(s->left, fp);
|
(*fp)(s);
|
(*fp)(s);
|
walkTree(s->right, fp);
|
walkTree(s->right, fp);
|
}
|
}
|
|
|
|
|
void walkSymbols(void (*fp)(Symbol *sym)) {
|
void walkSymbols(void (*fp)(Symbol *sym)) {
|
walkTree(symbolTable, fp);
|
walkTree(symbolTable, fp);
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
unsigned int read4FromEco(unsigned char *p) {
|
unsigned int read4FromEco(unsigned char *p) {
|
return (unsigned int) p[0] << 24 |
|
return (unsigned int) p[0] << 24 |
|
(unsigned int) p[1] << 16 |
|
(unsigned int) p[1] << 16 |
|
(unsigned int) p[2] << 8 |
|
(unsigned int) p[2] << 8 |
|
(unsigned int) p[3] << 0;
|
(unsigned int) p[3] << 0;
|
}
|
}
|
|
|
|
|
void write4ToEco(unsigned char *p, unsigned int data) {
|
void write4ToEco(unsigned char *p, unsigned int data) {
|
p[0] = data >> 24;
|
p[0] = data >> 24;
|
p[1] = data >> 16;
|
p[1] = data >> 16;
|
p[2] = data >> 8;
|
p[2] = data >> 8;
|
p[3] = data >> 0;
|
p[3] = data >> 0;
|
}
|
}
|
|
|
|
|
void conv4FromEcoToNative(unsigned char *p) {
|
void conv4FromEcoToNative(unsigned char *p) {
|
unsigned int data;
|
unsigned int data;
|
|
|
data = read4FromEco(p);
|
data = read4FromEco(p);
|
* (unsigned int *) p = data;
|
* (unsigned int *) p = data;
|
}
|
}
|
|
|
|
|
void conv4FromNativeToEco(unsigned char *p) {
|
void conv4FromNativeToEco(unsigned char *p) {
|
unsigned int data;
|
unsigned int data;
|
|
|
data = * (unsigned int *) p;
|
data = * (unsigned int *) p;
|
write4ToEco(p, data);
|
write4ToEco(p, data);
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
#define CODE_START(h) (sizeof(ExecHeader))
|
#define CODE_START(h) (sizeof(ExecHeader))
|
#define DATA_START(h) (CODE_START(h) + (h).csize)
|
#define DATA_START(h) (CODE_START(h) + (h).csize)
|
#define CRELOC_START(h) (DATA_START(h) + (h).dsize)
|
#define CRELOC_START(h) (DATA_START(h) + (h).dsize)
|
#define DRELOC_START(h) (CRELOC_START(h) + (h).crsize)
|
#define DRELOC_START(h) (CRELOC_START(h) + (h).crsize)
|
#define SYMTBL_START(h) (DRELOC_START(h) + (h).drsize)
|
#define SYMTBL_START(h) (DRELOC_START(h) + (h).drsize)
|
#define STRING_START(h) (SYMTBL_START(h) + (h).symsize)
|
#define STRING_START(h) (SYMTBL_START(h) + (h).symsize)
|
|
|
|
|
ExecHeader inHeader;
|
ExecHeader inHeader;
|
Symbol **symMap;
|
Symbol **symMap;
|
|
|
|
|
void readHeader(void) {
|
void readHeader(void) {
|
if (fseek(inFile, 0, SEEK_SET) < 0) {
|
if (fseek(inFile, 0, SEEK_SET) < 0) {
|
error("cannot seek to exec header");
|
error("cannot seek to exec header");
|
}
|
}
|
if (fread(&inHeader, sizeof(ExecHeader), 1, inFile) != 1) {
|
if (fread(&inHeader, sizeof(ExecHeader), 1, inFile) != 1) {
|
error("cannot read exec header");
|
error("cannot read exec header");
|
}
|
}
|
conv4FromEcoToNative((unsigned char *) &inHeader.magic);
|
conv4FromEcoToNative((unsigned char *) &inHeader.magic);
|
conv4FromEcoToNative((unsigned char *) &inHeader.csize);
|
conv4FromEcoToNative((unsigned char *) &inHeader.csize);
|
conv4FromEcoToNative((unsigned char *) &inHeader.dsize);
|
conv4FromEcoToNative((unsigned char *) &inHeader.dsize);
|
conv4FromEcoToNative((unsigned char *) &inHeader.bsize);
|
conv4FromEcoToNative((unsigned char *) &inHeader.bsize);
|
conv4FromEcoToNative((unsigned char *) &inHeader.crsize);
|
conv4FromEcoToNative((unsigned char *) &inHeader.crsize);
|
conv4FromEcoToNative((unsigned char *) &inHeader.drsize);
|
conv4FromEcoToNative((unsigned char *) &inHeader.drsize);
|
conv4FromEcoToNative((unsigned char *) &inHeader.symsize);
|
conv4FromEcoToNative((unsigned char *) &inHeader.symsize);
|
conv4FromEcoToNative((unsigned char *) &inHeader.strsize);
|
conv4FromEcoToNative((unsigned char *) &inHeader.strsize);
|
if (inHeader.magic != EXEC_MAGIC) {
|
if (inHeader.magic != EXEC_MAGIC) {
|
error("wrong magic number in exec header");
|
error("wrong magic number in exec header");
|
}
|
}
|
}
|
}
|
|
|
|
|
void readCode(void) {
|
void readCode(void) {
|
unsigned char *buffer;
|
unsigned char *buffer;
|
|
|
if (fseek(inFile, CODE_START(inHeader), SEEK_SET) < 0) {
|
if (fseek(inFile, CODE_START(inHeader), SEEK_SET) < 0) {
|
error("cannot seek to code section");
|
error("cannot seek to code section");
|
}
|
}
|
buffer = allocateMemory(inHeader.csize);
|
buffer = allocateMemory(inHeader.csize);
|
if (fread(buffer, 1, inHeader.csize, inFile) != inHeader.csize) {
|
if (fread(buffer, 1, inHeader.csize, inFile) != inHeader.csize) {
|
error("cannot read code segment");
|
error("cannot read code segment");
|
}
|
}
|
if (fwrite(buffer, 1, inHeader.csize, codeFile) != inHeader.csize) {
|
if (fwrite(buffer, 1, inHeader.csize, codeFile) != inHeader.csize) {
|
error("cannot write code segment");
|
error("cannot write code segment");
|
}
|
}
|
freeMemory(buffer);
|
freeMemory(buffer);
|
}
|
}
|
|
|
|
|
void readData(void) {
|
void readData(void) {
|
unsigned char *buffer;
|
unsigned char *buffer;
|
|
|
if (fseek(inFile, DATA_START(inHeader), SEEK_SET) < 0) {
|
if (fseek(inFile, DATA_START(inHeader), SEEK_SET) < 0) {
|
error("cannot seek to data section");
|
error("cannot seek to data section");
|
}
|
}
|
buffer = allocateMemory(inHeader.dsize);
|
buffer = allocateMemory(inHeader.dsize);
|
if (fread(buffer, 1, inHeader.dsize, inFile) != inHeader.dsize) {
|
if (fread(buffer, 1, inHeader.dsize, inFile) != inHeader.dsize) {
|
error("cannot read data segment");
|
error("cannot read data segment");
|
}
|
}
|
if (fwrite(buffer, 1, inHeader.dsize, dataFile) != inHeader.dsize) {
|
if (fwrite(buffer, 1, inHeader.dsize, dataFile) != inHeader.dsize) {
|
error("cannot write data segment");
|
error("cannot write data segment");
|
}
|
}
|
freeMemory(buffer);
|
freeMemory(buffer);
|
}
|
}
|
|
|
|
|
void readCodeRelocs(void) {
|
void readCodeRelocs(void) {
|
int n, i;
|
int n, i;
|
RelocRecord relRec;
|
RelocRecord relRec;
|
|
|
if (fseek(inFile, CRELOC_START(inHeader), SEEK_SET) < 0) {
|
if (fseek(inFile, CRELOC_START(inHeader), SEEK_SET) < 0) {
|
error("cannot seek to code relocation section");
|
error("cannot seek to code relocation section");
|
}
|
}
|
n = inHeader.crsize / sizeof(RelocRecord);
|
n = inHeader.crsize / sizeof(RelocRecord);
|
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
if (fread(&relRec, sizeof(RelocRecord), 1, inFile) != 1) {
|
if (fread(&relRec, sizeof(RelocRecord), 1, inFile) != 1) {
|
error("cannot read code relocation records");
|
error("cannot read code relocation records");
|
}
|
}
|
conv4FromEcoToNative((unsigned char *) &relRec.offset);
|
conv4FromEcoToNative((unsigned char *) &relRec.offset);
|
conv4FromEcoToNative((unsigned char *) &relRec.method);
|
conv4FromEcoToNative((unsigned char *) &relRec.method);
|
conv4FromEcoToNative((unsigned char *) &relRec.value);
|
conv4FromEcoToNative((unsigned char *) &relRec.value);
|
conv4FromEcoToNative((unsigned char *) &relRec.base);
|
conv4FromEcoToNative((unsigned char *) &relRec.base);
|
addReloc(SEGMENT_CODE, &relRec, symMap);
|
addReloc(SEGMENT_CODE, &relRec, symMap);
|
}
|
}
|
}
|
}
|
|
|
|
|
void readDataRelocs(void) {
|
void readDataRelocs(void) {
|
int n, i;
|
int n, i;
|
RelocRecord relRec;
|
RelocRecord relRec;
|
|
|
if (fseek(inFile, DRELOC_START(inHeader), SEEK_SET) < 0) {
|
if (fseek(inFile, DRELOC_START(inHeader), SEEK_SET) < 0) {
|
error("cannot seek to data relocation section");
|
error("cannot seek to data relocation section");
|
}
|
}
|
n = inHeader.drsize / sizeof(RelocRecord);
|
n = inHeader.drsize / sizeof(RelocRecord);
|
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
if (fread(&relRec, sizeof(RelocRecord), 1, inFile) != 1) {
|
if (fread(&relRec, sizeof(RelocRecord), 1, inFile) != 1) {
|
error("cannot read data relocation records");
|
error("cannot read data relocation records");
|
}
|
}
|
conv4FromEcoToNative((unsigned char *) &relRec.offset);
|
conv4FromEcoToNative((unsigned char *) &relRec.offset);
|
conv4FromEcoToNative((unsigned char *) &relRec.method);
|
conv4FromEcoToNative((unsigned char *) &relRec.method);
|
conv4FromEcoToNative((unsigned char *) &relRec.value);
|
conv4FromEcoToNative((unsigned char *) &relRec.value);
|
conv4FromEcoToNative((unsigned char *) &relRec.base);
|
conv4FromEcoToNative((unsigned char *) &relRec.base);
|
addReloc(SEGMENT_DATA, &relRec, symMap);
|
addReloc(SEGMENT_DATA, &relRec, symMap);
|
}
|
}
|
}
|
}
|
|
|
|
|
void readString(unsigned int offset, char *buffer, int size) {
|
void readString(unsigned int offset, char *buffer, int size) {
|
long pos;
|
long pos;
|
int c;
|
int c;
|
|
|
pos = ftell(inFile);
|
pos = ftell(inFile);
|
if (fseek(inFile, STRING_START(inHeader) + offset, SEEK_SET) < 0) {
|
if (fseek(inFile, STRING_START(inHeader) + offset, SEEK_SET) < 0) {
|
error("cannot seek to string");
|
error("cannot seek to string");
|
}
|
}
|
do {
|
do {
|
c = fgetc(inFile);
|
c = fgetc(inFile);
|
if (c == EOF) {
|
if (c == EOF) {
|
error("unexpected end of file");
|
error("unexpected end of file");
|
}
|
}
|
*buffer++ = c;
|
*buffer++ = c;
|
if (--size == 0) {
|
if (--size == 0) {
|
error("string buffer overflow");
|
error("string buffer overflow");
|
}
|
}
|
} while (c != 0);
|
} while (c != 0);
|
fseek(inFile, pos, SEEK_SET);
|
fseek(inFile, pos, SEEK_SET);
|
}
|
}
|
|
|
|
|
void readSymbols(void) {
|
void readSymbols(void) {
|
int n, i;
|
int n, i;
|
SymbolRecord symRec;
|
SymbolRecord symRec;
|
char strBuf[MAX_STRLEN];
|
char strBuf[MAX_STRLEN];
|
Symbol *sym;
|
Symbol *sym;
|
|
|
if (fseek(inFile, SYMTBL_START(inHeader), SEEK_SET) < 0) {
|
if (fseek(inFile, SYMTBL_START(inHeader), SEEK_SET) < 0) {
|
error("cannot seek to symbol table section");
|
error("cannot seek to symbol table section");
|
}
|
}
|
n = inHeader.symsize / sizeof(SymbolRecord);
|
n = inHeader.symsize / sizeof(SymbolRecord);
|
symMap = allocateMemory(n * sizeof(Symbol *));
|
symMap = allocateMemory(n * sizeof(Symbol *));
|
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
if (fread(&symRec, sizeof(SymbolRecord), 1, inFile) != 1) {
|
if (fread(&symRec, sizeof(SymbolRecord), 1, inFile) != 1) {
|
error("cannot read symbol table");
|
error("cannot read symbol table");
|
}
|
}
|
conv4FromEcoToNative((unsigned char *) &symRec.name);
|
conv4FromEcoToNative((unsigned char *) &symRec.name);
|
conv4FromEcoToNative((unsigned char *) &symRec.type);
|
conv4FromEcoToNative((unsigned char *) &symRec.type);
|
conv4FromEcoToNative((unsigned char *) &symRec.value);
|
conv4FromEcoToNative((unsigned char *) &symRec.value);
|
readString(symRec.name, strBuf, MAX_STRLEN);
|
readString(symRec.name, strBuf, MAX_STRLEN);
|
sym = lookupEnter(strBuf);
|
sym = lookupEnter(strBuf);
|
if ((symRec.type & MSB) == 0) {
|
if ((symRec.type & MSB) == 0) {
|
/* the symbol is defined in this symbol record */
|
/* the symbol is defined in this symbol record */
|
if ((sym->type & MSB) == 0) {
|
if ((sym->type & MSB) == 0) {
|
/* the symbol was already defined in the table */
|
/* the symbol was already defined in the table */
|
error("symbol '%s' multiply defined", sym->name);
|
error("symbol '%s' multiply defined", sym->name);
|
} else {
|
} else {
|
/* the symbol was not yet defined in the table, so define it now */
|
/* the symbol was not yet defined in the table, so define it now */
|
/* the segment is copied directly from the file */
|
/* the segment is copied directly from the file */
|
/* the value is the sum of the value given in the file */
|
/* the value is the sum of the value given in the file */
|
/* and this module's segment start of the symbol's segment */
|
/* and this module's segment start of the symbol's segment */
|
sym->type = symRec.type;
|
sym->type = symRec.type;
|
sym->value = symRec.value + segPtr[symRec.type];
|
sym->value = symRec.value + segPtr[symRec.type];
|
}
|
}
|
} else {
|
} else {
|
/* the symbol is undefined in this symbol record */
|
/* the symbol is undefined in this symbol record */
|
/* nothing to do here: lookupEnter already entered */
|
/* nothing to do here: lookupEnter already entered */
|
/* the symbol into the symbol table, if necessary */
|
/* the symbol into the symbol table, if necessary */
|
}
|
}
|
/* in any case remember the symbol table entry, so that */
|
/* in any case remember the symbol table entry, so that */
|
/* a symbol index in a relocation record can be resolved */
|
/* a symbol index in a relocation record can be resolved */
|
symMap[i] = sym;
|
symMap[i] = sym;
|
}
|
}
|
}
|
}
|
|
|
|
|
void readModule(void) {
|
void readModule(void) {
|
/* read the file header to determine the sizes */
|
/* read the file header to determine the sizes */
|
readHeader();
|
readHeader();
|
/* read and transfer the code and data segments */
|
/* read and transfer the code and data segments */
|
readCode();
|
readCode();
|
readData();
|
readData();
|
/* read and build the symbol table and a symbol map */
|
/* read and build the symbol table and a symbol map */
|
readSymbols();
|
readSymbols();
|
/* read and build a list of relocation records */
|
/* read and build a list of relocation records */
|
readCodeRelocs();
|
readCodeRelocs();
|
readDataRelocs();
|
readDataRelocs();
|
/* free the symbol map, it is no longer needed */
|
/* free the symbol map, it is no longer needed */
|
freeMemory(symMap);
|
freeMemory(symMap);
|
/* update accumulated segment sizes */
|
/* update accumulated segment sizes */
|
segPtr[SEGMENT_CODE] += inHeader.csize;
|
segPtr[SEGMENT_CODE] += inHeader.csize;
|
segPtr[SEGMENT_DATA] += inHeader.dsize;
|
segPtr[SEGMENT_DATA] += inHeader.dsize;
|
segPtr[SEGMENT_BSS] += inHeader.bsize;
|
segPtr[SEGMENT_BSS] += inHeader.bsize;
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
void printSymbol(Symbol *s) {
|
void printSymbol(Symbol *s) {
|
fprintf(mapFile, "%-32s", s->name);
|
fprintf(mapFile, "%-32s", s->name);
|
if (s->type & MSB) {
|
if (s->type & MSB) {
|
/* symbol is undefined */
|
/* symbol is undefined */
|
fprintf(mapFile, "%-15s", "UNDEFINED");
|
fprintf(mapFile, "%-15s", "UNDEFINED");
|
} else {
|
} else {
|
/* symbol is defined */
|
/* symbol is defined */
|
switch (s->type) {
|
switch (s->type) {
|
case SEGMENT_ABS:
|
case SEGMENT_ABS:
|
fprintf(mapFile, "%-15s", "ABS");
|
fprintf(mapFile, "%-15s", "ABS");
|
break;
|
break;
|
case SEGMENT_CODE:
|
case SEGMENT_CODE:
|
fprintf(mapFile, "%-15s", "CODE");
|
fprintf(mapFile, "%-15s", "CODE");
|
break;
|
break;
|
case SEGMENT_DATA:
|
case SEGMENT_DATA:
|
fprintf(mapFile, "%-15s", "DATA");
|
fprintf(mapFile, "%-15s", "DATA");
|
break;
|
break;
|
case SEGMENT_BSS:
|
case SEGMENT_BSS:
|
fprintf(mapFile, "%-15s", "BSS");
|
fprintf(mapFile, "%-15s", "BSS");
|
break;
|
break;
|
default:
|
default:
|
error("illegal symbol segment in printToMap()");
|
error("illegal symbol segment in printToMap()");
|
}
|
}
|
}
|
}
|
fprintf(mapFile, "0x%08X", s->value);
|
fprintf(mapFile, "0x%08X", s->value);
|
fprintf(mapFile, "\n");
|
fprintf(mapFile, "\n");
|
}
|
}
|
|
|
|
|
void printToMapFile(void) {
|
void printToMapFile(void) {
|
walkSymbols(printSymbol);
|
walkSymbols(printSymbol);
|
fprintf(mapFile, "\n");
|
fprintf(mapFile, "\n");
|
fprintf(mapFile, "CODE start 0x%08X size 0x%08X\n",
|
fprintf(mapFile, "CODE start 0x%08X size 0x%08X\n",
|
segStart[SEGMENT_CODE], segPtr[SEGMENT_CODE]);
|
segStart[SEGMENT_CODE], segPtr[SEGMENT_CODE]);
|
fprintf(mapFile, "DATA start 0x%08X size 0x%08X\n",
|
fprintf(mapFile, "DATA start 0x%08X size 0x%08X\n",
|
segStart[SEGMENT_DATA], segPtr[SEGMENT_DATA]);
|
segStart[SEGMENT_DATA], segPtr[SEGMENT_DATA]);
|
fprintf(mapFile, "BSS start 0x%08X size 0x%08X\n",
|
fprintf(mapFile, "BSS start 0x%08X size 0x%08X\n",
|
segStart[SEGMENT_BSS], segPtr[SEGMENT_BSS]);
|
segStart[SEGMENT_BSS], segPtr[SEGMENT_BSS]);
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
void writeHeader(void) {
|
void writeHeader(void) {
|
ExecHeader outHeader;
|
ExecHeader outHeader;
|
|
|
if (withHeader) {
|
if (withHeader) {
|
outHeader.magic = EXEC_MAGIC;
|
outHeader.magic = EXEC_MAGIC;
|
outHeader.csize = segPtr[SEGMENT_CODE];
|
outHeader.csize = segPtr[SEGMENT_CODE];
|
outHeader.dsize = segPtr[SEGMENT_DATA];
|
outHeader.dsize = segPtr[SEGMENT_DATA];
|
outHeader.bsize = segPtr[SEGMENT_BSS];
|
outHeader.bsize = segPtr[SEGMENT_BSS];
|
outHeader.crsize = 0;
|
outHeader.crsize = 0;
|
outHeader.drsize = 0;
|
outHeader.drsize = 0;
|
outHeader.symsize = 0;
|
outHeader.symsize = 0;
|
outHeader.strsize = 0;
|
outHeader.strsize = 0;
|
conv4FromNativeToEco((unsigned char *) &outHeader.magic);
|
conv4FromNativeToEco((unsigned char *) &outHeader.magic);
|
conv4FromNativeToEco((unsigned char *) &outHeader.csize);
|
conv4FromNativeToEco((unsigned char *) &outHeader.csize);
|
conv4FromNativeToEco((unsigned char *) &outHeader.dsize);
|
conv4FromNativeToEco((unsigned char *) &outHeader.dsize);
|
conv4FromNativeToEco((unsigned char *) &outHeader.bsize);
|
conv4FromNativeToEco((unsigned char *) &outHeader.bsize);
|
conv4FromNativeToEco((unsigned char *) &outHeader.crsize);
|
conv4FromNativeToEco((unsigned char *) &outHeader.crsize);
|
conv4FromNativeToEco((unsigned char *) &outHeader.drsize);
|
conv4FromNativeToEco((unsigned char *) &outHeader.drsize);
|
conv4FromNativeToEco((unsigned char *) &outHeader.symsize);
|
conv4FromNativeToEco((unsigned char *) &outHeader.symsize);
|
conv4FromNativeToEco((unsigned char *) &outHeader.strsize);
|
conv4FromNativeToEco((unsigned char *) &outHeader.strsize);
|
fwrite(&outHeader, sizeof(ExecHeader), 1, outFile);
|
fwrite(&outHeader, sizeof(ExecHeader), 1, outFile);
|
}
|
}
|
}
|
}
|
|
|
|
|
void writeCode(void) {
|
void writeCode(void) {
|
int data;
|
int data;
|
|
|
rewind(codeFile);
|
rewind(codeFile);
|
while (1) {
|
while (1) {
|
data = fgetc(codeFile);
|
data = fgetc(codeFile);
|
if (data == EOF) {
|
if (data == EOF) {
|
break;
|
break;
|
}
|
}
|
fputc(data, outFile);
|
fputc(data, outFile);
|
}
|
}
|
}
|
}
|
|
|
|
|
void writeData(void) {
|
void writeData(void) {
|
int data;
|
int data;
|
|
|
rewind(dataFile);
|
rewind(dataFile);
|
while (1) {
|
while (1) {
|
data = fgetc(dataFile);
|
data = fgetc(dataFile);
|
if (data == EOF) {
|
if (data == EOF) {
|
break;
|
break;
|
}
|
}
|
fputc(data, outFile);
|
fputc(data, outFile);
|
}
|
}
|
}
|
}
|
|
|
|
|
/**************************************************************/
|
/**************************************************************/
|
|
|
|
|
int readNumber(char *str, unsigned int *np) {
|
int readNumber(char *str, unsigned int *np) {
|
int base;
|
int base;
|
int value;
|
int value;
|
int digit;
|
int digit;
|
|
|
base = 10;
|
base = 10;
|
value = 0;
|
value = 0;
|
if (*str == '0') {
|
if (*str == '0') {
|
str++;
|
str++;
|
if (*str == 'x' || *str == 'X') {
|
if (*str == 'x' || *str == 'X') {
|
base = 16;
|
base = 16;
|
str++;
|
str++;
|
} else
|
} else
|
if (isdigit((int) *str)) {
|
if (isdigit((int) *str)) {
|
base = 8;
|
base = 8;
|
} else
|
} else
|
if (*str == '\0') {
|
if (*str == '\0') {
|
*np = value;
|
*np = value;
|
return 1;
|
return 1;
|
} else {
|
} else {
|
return 0;
|
return 0;
|
}
|
}
|
}
|
}
|
while (isxdigit((int) *str)) {
|
while (isxdigit((int) *str)) {
|
digit = *str++ - '0';
|
digit = *str++ - '0';
|
if (digit >= 'A' - '0') {
|
if (digit >= 'A' - '0') {
|
if (digit >= 'a' - '0') {
|
if (digit >= 'a' - '0') {
|
digit += '0' - 'a' + 10;
|
digit += '0' - 'a' + 10;
|
} else {
|
} else {
|
digit += '0' - 'A' + 10;
|
digit += '0' - 'A' + 10;
|
}
|
}
|
}
|
}
|
if (digit >= base) {
|
if (digit >= base) {
|
return 0;
|
return 0;
|
}
|
}
|
value *= base;
|
value *= base;
|
value += digit;
|
value += digit;
|
}
|
}
|
if (*str == '\0') {
|
if (*str == '\0') {
|
*np = value;
|
*np = value;
|
return 1;
|
return 1;
|
} else {
|
} else {
|
return 0;
|
return 0;
|
}
|
}
|
}
|
}
|
|
|
|
|
void usage(char *myself) {
|
void usage(char *myself) {
|
fprintf(stderr, "Usage: %s\n", myself);
|
fprintf(stderr, "Usage: %s\n", myself);
|
fprintf(stderr, " [-h] do not write object header\n");
|
fprintf(stderr, " [-h] do not write object header\n");
|
fprintf(stderr, " [-o objfile] set output file name\n");
|
fprintf(stderr, " [-o objfile] set output file name\n");
|
fprintf(stderr, " [-m mapfile] produce map file\n");
|
fprintf(stderr, " [-m mapfile] produce map file\n");
|
fprintf(stderr, " [-rc addr] relocate code segment\n");
|
fprintf(stderr, " [-rc addr] relocate code segment\n");
|
fprintf(stderr, " [-rd addr] relocate data segment\n");
|
fprintf(stderr, " [-rd addr] relocate data segment\n");
|
fprintf(stderr, " [-rb addr] relocate bss segment\n");
|
fprintf(stderr, " [-rb addr] relocate bss segment\n");
|
fprintf(stderr, " file object file name\n");
|
fprintf(stderr, " file object file name\n");
|
fprintf(stderr, " [files...] additional object files\n");
|
fprintf(stderr, " [files...] additional object files\n");
|
exit(1);
|
exit(1);
|
}
|
}
|
|
|
|
|
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
int i;
|
int i;
|
char *argp;
|
char *argp;
|
unsigned int *ssp;
|
unsigned int *ssp;
|
int *ssdp;
|
int *ssdp;
|
|
|
tmpnam(codeName);
|
tmpnam(codeName);
|
tmpnam(dataName);
|
tmpnam(dataName);
|
outName = "a.out";
|
outName = "a.out";
|
for (i = 1; i < argc; i++) {
|
for (i = 1; i < argc; i++) {
|
argp = argv[i];
|
argp = argv[i];
|
if (*argp != '-') {
|
if (*argp != '-') {
|
break;
|
break;
|
}
|
}
|
argp++;
|
argp++;
|
switch (*argp) {
|
switch (*argp) {
|
case 'h':
|
case 'h':
|
withHeader = 0;
|
withHeader = 0;
|
break;
|
break;
|
case 'o':
|
case 'o':
|
if (i == argc - 1) {
|
if (i == argc - 1) {
|
usage(argv[0]);
|
usage(argv[0]);
|
}
|
}
|
outName = argv[++i];
|
outName = argv[++i];
|
break;
|
break;
|
case 'm':
|
case 'm':
|
if (i == argc - 1) {
|
if (i == argc - 1) {
|
usage(argv[0]);
|
usage(argv[0]);
|
}
|
}
|
mapName = argv[++i];
|
mapName = argv[++i];
|
break;
|
break;
|
case 'r':
|
case 'r':
|
if (argp[1] == 'c') {
|
if (argp[1] == 'c') {
|
ssp = &segStart[SEGMENT_CODE];
|
ssp = &segStart[SEGMENT_CODE];
|
ssdp = &segStartDefined[SEGMENT_CODE];
|
ssdp = &segStartDefined[SEGMENT_CODE];
|
} else
|
} else
|
if (argp[1] == 'd') {
|
if (argp[1] == 'd') {
|
ssp = &segStart[SEGMENT_DATA];
|
ssp = &segStart[SEGMENT_DATA];
|
ssdp = &segStartDefined[SEGMENT_DATA];
|
ssdp = &segStartDefined[SEGMENT_DATA];
|
} else
|
} else
|
if (argp[1] == 'b') {
|
if (argp[1] == 'b') {
|
ssp = &segStart[SEGMENT_BSS];
|
ssp = &segStart[SEGMENT_BSS];
|
ssdp = &segStartDefined[SEGMENT_BSS];
|
ssdp = &segStartDefined[SEGMENT_BSS];
|
} else {
|
} else {
|
usage(argv[0]);
|
usage(argv[0]);
|
}
|
}
|
if (i == argc - 1) {
|
if (i == argc - 1) {
|
usage(argv[0]);
|
usage(argv[0]);
|
}
|
}
|
if (!readNumber(argv[++i], ssp)) {
|
if (!readNumber(argv[++i], ssp)) {
|
error("cannot read number given with option '-%s'", argp);
|
error("cannot read number given with option '-%s'", argp);
|
}
|
}
|
*ssdp = 1;
|
*ssdp = 1;
|
break;
|
break;
|
default:
|
default:
|
usage(argv[0]);
|
usage(argv[0]);
|
}
|
}
|
}
|
}
|
if (i == argc) {
|
if (i == argc) {
|
usage(argv[0]);
|
usage(argv[0]);
|
}
|
}
|
codeFile = fopen(codeName, "w+b");
|
codeFile = fopen(codeName, "w+b");
|
if (codeFile == NULL) {
|
if (codeFile == NULL) {
|
error("cannot create temporary code file '%s'", codeName);
|
error("cannot create temporary code file '%s'", codeName);
|
}
|
}
|
dataFile = fopen(dataName, "w+b");
|
dataFile = fopen(dataName, "w+b");
|
if (dataFile == NULL) {
|
if (dataFile == NULL) {
|
error("cannot create temporary data file '%s'", dataName);
|
error("cannot create temporary data file '%s'", dataName);
|
}
|
}
|
outFile = fopen(outName, "wb");
|
outFile = fopen(outName, "wb");
|
if (outFile == NULL) {
|
if (outFile == NULL) {
|
error("cannot open output file '%s'", outName);
|
error("cannot open output file '%s'", outName);
|
}
|
}
|
if (mapName != NULL) {
|
if (mapName != NULL) {
|
mapFile = fopen(mapName, "wt");
|
mapFile = fopen(mapName, "wt");
|
if (mapFile == NULL) {
|
if (mapFile == NULL) {
|
error("cannot open map file '%s'", mapName);
|
error("cannot open map file '%s'", mapName);
|
}
|
}
|
}
|
}
|
do {
|
do {
|
inName = argv[i];
|
inName = argv[i];
|
if (*inName == '-') {
|
if (*inName == '-') {
|
usage(argv[0]);
|
usage(argv[0]);
|
}
|
}
|
inFile = fopen(inName, "rb");
|
inFile = fopen(inName, "rb");
|
if (inFile == NULL) {
|
if (inFile == NULL) {
|
error("cannot open input file '%s'", inName);
|
error("cannot open input file '%s'", inName);
|
}
|
}
|
fprintf(stderr, "Reading module '%s'...\n", inName);
|
fprintf(stderr, "Reading module '%s'...\n", inName);
|
readModule();
|
readModule();
|
if (inFile != NULL) {
|
if (inFile != NULL) {
|
fclose(inFile);
|
fclose(inFile);
|
inFile = NULL;
|
inFile = NULL;
|
}
|
}
|
} while (++i < argc);
|
} while (++i < argc);
|
fprintf(stderr, "Linking modules...\n");
|
fprintf(stderr, "Linking modules...\n");
|
linkSymbols();
|
linkSymbols();
|
fprintf(stderr, "Relocating segments...\n");
|
fprintf(stderr, "Relocating segments...\n");
|
relocateSegments();
|
relocateSegments();
|
writeHeader();
|
writeHeader();
|
writeCode();
|
writeCode();
|
writeData();
|
writeData();
|
if (mapFile != NULL) {
|
if (mapFile != NULL) {
|
printToMapFile();
|
printToMapFile();
|
}
|
}
|
if (codeFile != NULL) {
|
if (codeFile != NULL) {
|
fclose(codeFile);
|
fclose(codeFile);
|
codeFile = NULL;
|
codeFile = NULL;
|
}
|
}
|
if (dataFile != NULL) {
|
if (dataFile != NULL) {
|
fclose(dataFile);
|
fclose(dataFile);
|
dataFile = NULL;
|
dataFile = NULL;
|
}
|
}
|
if (outFile != NULL) {
|
if (outFile != NULL) {
|
fclose(outFile);
|
fclose(outFile);
|
outFile = NULL;
|
outFile = NULL;
|
}
|
}
|
if (mapFile != NULL) {
|
if (mapFile != NULL) {
|
fclose(mapFile);
|
fclose(mapFile);
|
mapFile = NULL;
|
mapFile = NULL;
|
}
|
}
|
if (codeName != NULL) {
|
if (codeName != NULL) {
|
unlink(codeName);
|
unlink(codeName);
|
}
|
}
|
if (dataName != NULL) {
|
if (dataName != NULL) {
|
unlink(dataName);
|
unlink(dataName);
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
|
|