URL
https://opencores.org/ocsvn/eco32/eco32/trunk
Subversion Repositories eco32
Compare Revisions
- This comparison shows the changes necessary to convert path
/eco32/trunk
- from Rev 6 to Rev 7
- ↔ Reverse comparison
Rev 6 → Rev 7
/binutils/ld/ld.c
0,0 → 1,924
/* |
* ld.c -- ECO32 linking loader |
*/ |
|
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <stdarg.h> |
#include <ctype.h> |
#include <unistd.h> |
|
#include "../include/a.out.h" |
|
|
/**************************************************************/ |
|
|
#define MAX_STRLEN 200 |
|
#define PAGE_SHIFT 12 |
#define PAGE_SIZE (1 << PAGE_SHIFT) |
#define PAGE_MASK (PAGE_SIZE - 1) |
#define PAGE_ROUND(n) (((n) + PAGE_SIZE - 1) & ~PAGE_MASK) |
|
#define MSB ((unsigned int) 1 << (sizeof(unsigned int) * 8 - 1)) |
|
|
/**************************************************************/ |
|
|
int debugLink = 0; |
int debugFixup = 0; |
|
int withHeader = 1; |
|
char codeName[L_tmpnam]; |
char dataName[L_tmpnam]; |
char *outName = NULL; |
char *mapName = NULL; |
char *inName = NULL; |
|
FILE *codeFile = NULL; |
FILE *dataFile = NULL; |
FILE *outFile = NULL; |
FILE *mapFile = NULL; |
FILE *inFile = NULL; |
|
unsigned int segPtr[4] = { 0, 0, 0, 0 }; |
int segStartDefined[4] = { 0, 0, 0, 0 }; |
unsigned int segStart[4] = { 0, 0, 0, 0 }; |
char *segName[4] = { "ABS", "CODE", "DATA", "BSS" }; |
char *methodName[5] = { "H16", "L16", "R16", "R26", "W32" }; |
|
|
typedef struct reloc { |
int segment; /* in which segment to relocate */ |
unsigned int offset; /* where in the segment to relocate */ |
int method; /* how to relocate */ |
int value; /* additive part of value */ |
int type; /* 0: base is a segment */ |
/* 1: base is a symbol */ |
union { /* relocation relative to .. */ |
int segment; /* .. a segment */ |
struct symbol *symbol; /* .. a symbol */ |
} base; |
struct reloc *next; /* next relocation */ |
} Reloc; |
|
|
typedef struct symbol { |
char *name; /* name of symbol */ |
int type; /* if MSB = 0: the symbol's segment */ |
/* if MSB = 1: the symbol is undefined */ |
int value; /* if symbol defined: the symbol's value */ |
/* if symbol not defined: meaningless */ |
struct symbol *left; /* left son in binary search tree */ |
struct symbol *right; /* right son in binary search tree */ |
} Symbol; |
|
|
/**************************************************************/ |
|
|
void error(char *fmt, ...) { |
va_list ap; |
|
va_start(ap, fmt); |
fprintf(stderr, "Error: "); |
vfprintf(stderr, fmt, ap); |
fprintf(stderr, "\n"); |
va_end(ap); |
if (codeFile != NULL) { |
fclose(codeFile); |
codeFile = NULL; |
} |
if (dataFile != NULL) { |
fclose(dataFile); |
dataFile = NULL; |
} |
if (outFile != NULL) { |
fclose(outFile); |
outFile = NULL; |
} |
if (mapFile != NULL) { |
fclose(mapFile); |
mapFile = NULL; |
} |
if (inFile != NULL) { |
fclose(inFile); |
inFile = NULL; |
} |
if (codeName != NULL) { |
unlink(codeName); |
} |
if (dataName != NULL) { |
unlink(dataName); |
} |
if (outName != NULL) { |
unlink(outName); |
} |
if (mapName != NULL) { |
unlink(mapName); |
} |
exit(1); |
} |
|
|
void *allocateMemory(unsigned int size) { |
void *p; |
|
p = malloc(size); |
if (p == NULL) { |
error("out of memory"); |
} |
return p; |
} |
|
|
void freeMemory(void *p) { |
free(p); |
} |
|
|
/**************************************************************/ |
|
|
Reloc *relocs = NULL; |
|
|
void addReloc(int segment, RelocRecord *relRec, Symbol **symMap) { |
Reloc *rel; |
|
rel = allocateMemory(sizeof(Reloc)); |
rel->segment = segment; |
rel->offset = relRec->offset + segPtr[segment]; |
rel->method = relRec->method; |
rel->value = relRec->value; |
if ((relRec->base & MSB) == 0) { |
/* relocation is relative to a segment */ |
rel->type = 0; |
rel->base.segment = relRec->base; |
rel->value += segPtr[relRec->base]; |
} else { |
/* relocation is relative to a symbol */ |
rel->type = 1; |
rel->base.symbol = symMap[relRec->base & ~MSB]; |
} |
rel->next = relocs; |
relocs = rel; |
} |
|
|
void linkSymbol(Reloc *rel) { |
Symbol *sym; |
|
/* check if this is a reference to a symbol */ |
if (rel->type != 1) { |
/* no: nothing to do here */ |
return; |
} |
/* get information from the symbol table record */ |
sym = rel->base.symbol; |
if (sym->type & MSB) { |
error("undefined symbol '%s'", sym->name); |
} |
/* output debugging info */ |
if (debugLink) { |
printf("DEBUG: link '%s' (s:%s, v:%08X)\n", |
sym->name, segName[sym->type], sym->value); |
printf(" (s:%s, o:%08X, m:%s, v:%08X --> %08X, b:%s)\n", |
segName[rel->segment], rel->offset, methodName[rel->method], |
rel->value, rel->value + sym->value, segName[sym->type]); |
} |
/* update relocation information */ |
rel->value += sym->value; |
rel->type = 0; |
rel->base.segment = sym->type; |
} |
|
|
void linkSymbols(void) { |
Reloc *rel; |
|
rel = relocs; |
while (rel != NULL) { |
linkSymbol(rel); |
rel = rel->next; |
} |
} |
|
|
void fixupRef(Reloc *rel) { |
FILE *file; |
unsigned int value; |
unsigned int final; |
|
/* determine the segment in which to do fixup */ |
switch (rel->segment) { |
case SEGMENT_ABS: |
/* this should never happen */ |
error("cannot do fixup in ABS"); |
break; |
case SEGMENT_CODE: |
file = codeFile; |
break; |
case SEGMENT_DATA: |
file = dataFile; |
break; |
case SEGMENT_BSS: |
/* this should never happen */ |
error("cannot do fixup in BSS"); |
break; |
default: |
/* this should never happen */ |
error("illegal segment in doFixup()"); |
break; |
} |
/* check that the base is indeed a segment */ |
if (rel->type != 0) { |
/* this should never happen */ |
error("fixup cannot handle reference to symbol"); |
} |
/* now patch according to method */ |
switch (rel->method) { |
case METHOD_H16: |
value = rel->value + segStart[rel->base.segment]; |
final = (value >> 16) & 0x0000FFFF; |
fseek(file, rel->offset + 2, SEEK_SET); |
fputc((final >> 8) & 0xFF, file); |
fputc((final >> 0) & 0xFF, file); |
break; |
case METHOD_L16: |
value = rel->value + segStart[rel->base.segment]; |
final = value & 0x0000FFFF; |
fseek(file, rel->offset + 2, SEEK_SET); |
fputc((final >> 8) & 0xFF, file); |
fputc((final >> 0) & 0xFF, file); |
break; |
case METHOD_R16: |
value = (rel->value - (rel->offset + 4)) / 4; |
final = value & 0x0000FFFF; |
fseek(file, rel->offset + 2, SEEK_SET); |
fputc((final >> 8) & 0xFF, file); |
fputc((final >> 0) & 0xFF, file); |
break; |
case METHOD_R26: |
value = (rel->value - (rel->offset + 4)) / 4; |
fseek(file, rel->offset, SEEK_SET); |
final = (fgetc(file) << 24) & 0xFC000000; |
final |= value & 0x03FFFFFF; |
fseek(file, -1, SEEK_CUR); |
fputc((final >> 24) & 0xFF, file); |
fputc((final >> 16) & 0xFF, file); |
fputc((final >> 8) & 0xFF, file); |
fputc((final >> 0) & 0xFF, file); |
break; |
case METHOD_W32: |
value = rel->value + segStart[rel->base.segment]; |
final = value; |
fseek(file, rel->offset, SEEK_SET); |
fputc((final >> 24) & 0xFF, file); |
fputc((final >> 16) & 0xFF, file); |
fputc((final >> 8) & 0xFF, file); |
fputc((final >> 0) & 0xFF, file); |
break; |
default: |
/* this should never happen */ |
error("illegal method in doFixup()"); |
break; |
} |
/* output debugging info */ |
if (debugFixup) { |
printf("DEBUG: fixup (s:%s, o:%08X, m:%s, v:%08X), %08X --> %08X\n", |
segName[rel->segment], rel->offset, methodName[rel->method], |
rel->value, value, final); |
} |
} |
|
|
void relocateSegments(void) { |
Reloc *rel; |
|
/* determine start of segments */ |
if (!segStartDefined[SEGMENT_CODE]) { |
segStart[SEGMENT_CODE] = 0; |
segStartDefined[SEGMENT_CODE] = 1; |
} |
if (!segStartDefined[SEGMENT_DATA]) { |
segStart[SEGMENT_DATA] = segStart[SEGMENT_CODE] + |
PAGE_ROUND(segPtr[SEGMENT_CODE]); |
segStartDefined[SEGMENT_DATA] = 1; |
} |
if (!segStartDefined[SEGMENT_BSS]) { |
segStart[SEGMENT_BSS] = segStart[SEGMENT_DATA] + |
segPtr[SEGMENT_DATA]; |
segStartDefined[SEGMENT_BSS] = 1; |
} |
/* fixup all references (which now are only relative to segments) */ |
while (relocs != NULL) { |
rel = relocs; |
relocs = rel->next; |
fixupRef(rel); |
freeMemory(rel); |
} |
} |
|
|
/**************************************************************/ |
|
|
Symbol *symbolTable = NULL; |
|
|
Symbol *newSymbol(char *name) { |
Symbol *p; |
|
p = allocateMemory(sizeof(Symbol)); |
p->name = allocateMemory(strlen(name) + 1); |
strcpy(p->name, name); |
p->type = MSB; |
p->value = 0; |
p->left = NULL; |
p->right = NULL; |
return p; |
} |
|
|
Symbol *lookupEnter(char *name) { |
Symbol *p, *q, *r; |
int cmp; |
|
p = symbolTable; |
if (p == NULL) { |
r = newSymbol(name); |
symbolTable = r; |
return r; |
} |
while (1) { |
q = p; |
cmp = strcmp(name, q->name); |
if (cmp == 0) { |
return q; |
} |
if (cmp < 0) { |
p = q->left; |
} else { |
p = q->right; |
} |
if (p == NULL) { |
r = newSymbol(name); |
if (cmp < 0) { |
q->left = r; |
} else { |
q->right = r; |
} |
return r; |
} |
} |
} |
|
|
void walkTree(Symbol *s, void (*fp)(Symbol *sp)) { |
if (s == NULL) { |
return; |
} |
walkTree(s->left, fp); |
(*fp)(s); |
walkTree(s->right, fp); |
} |
|
|
void walkSymbols(void (*fp)(Symbol *sym)) { |
walkTree(symbolTable, fp); |
} |
|
|
/**************************************************************/ |
|
|
unsigned int read4FromEco(unsigned char *p) { |
return (unsigned int) p[0] << 24 | |
(unsigned int) p[1] << 16 | |
(unsigned int) p[2] << 8 | |
(unsigned int) p[3] << 0; |
} |
|
|
void write4ToEco(unsigned char *p, unsigned int data) { |
p[0] = data >> 24; |
p[1] = data >> 16; |
p[2] = data >> 8; |
p[3] = data >> 0; |
} |
|
|
void conv4FromEcoToNative(unsigned char *p) { |
unsigned int data; |
|
data = read4FromEco(p); |
* (unsigned int *) p = data; |
} |
|
|
void conv4FromNativeToEco(unsigned char *p) { |
unsigned int data; |
|
data = * (unsigned int *) p; |
write4ToEco(p, data); |
} |
|
|
/**************************************************************/ |
|
|
#define CODE_START(h) (sizeof(ExecHeader)) |
#define DATA_START(h) (CODE_START(h) + (h).csize) |
#define CRELOC_START(h) (DATA_START(h) + (h).dsize) |
#define DRELOC_START(h) (CRELOC_START(h) + (h).crsize) |
#define SYMTBL_START(h) (DRELOC_START(h) + (h).drsize) |
#define STRING_START(h) (SYMTBL_START(h) + (h).symsize) |
|
|
ExecHeader inHeader; |
Symbol **symMap; |
|
|
void readHeader(void) { |
if (fseek(inFile, 0, SEEK_SET) < 0) { |
error("cannot seek to exec header"); |
} |
if (fread(&inHeader, sizeof(ExecHeader), 1, inFile) != 1) { |
error("cannot read exec header"); |
} |
conv4FromEcoToNative((unsigned char *) &inHeader.magic); |
conv4FromEcoToNative((unsigned char *) &inHeader.csize); |
conv4FromEcoToNative((unsigned char *) &inHeader.dsize); |
conv4FromEcoToNative((unsigned char *) &inHeader.bsize); |
conv4FromEcoToNative((unsigned char *) &inHeader.crsize); |
conv4FromEcoToNative((unsigned char *) &inHeader.drsize); |
conv4FromEcoToNative((unsigned char *) &inHeader.symsize); |
conv4FromEcoToNative((unsigned char *) &inHeader.strsize); |
if (inHeader.magic != EXEC_MAGIC) { |
error("wrong magic number in exec header"); |
} |
} |
|
|
void readCode(void) { |
unsigned char *buffer; |
|
if (fseek(inFile, CODE_START(inHeader), SEEK_SET) < 0) { |
error("cannot seek to code section"); |
} |
buffer = allocateMemory(inHeader.csize); |
if (fread(buffer, 1, inHeader.csize, inFile) != inHeader.csize) { |
error("cannot read code segment"); |
} |
if (fwrite(buffer, 1, inHeader.csize, codeFile) != inHeader.csize) { |
error("cannot write code segment"); |
} |
freeMemory(buffer); |
} |
|
|
void readData(void) { |
unsigned char *buffer; |
|
if (fseek(inFile, DATA_START(inHeader), SEEK_SET) < 0) { |
error("cannot seek to data section"); |
} |
buffer = allocateMemory(inHeader.dsize); |
if (fread(buffer, 1, inHeader.dsize, inFile) != inHeader.dsize) { |
error("cannot read data segment"); |
} |
if (fwrite(buffer, 1, inHeader.dsize, dataFile) != inHeader.dsize) { |
error("cannot write data segment"); |
} |
freeMemory(buffer); |
} |
|
|
void readCodeRelocs(void) { |
int n, i; |
RelocRecord relRec; |
|
if (fseek(inFile, CRELOC_START(inHeader), SEEK_SET) < 0) { |
error("cannot seek to code relocation section"); |
} |
n = inHeader.crsize / sizeof(RelocRecord); |
for (i = 0; i < n; i++) { |
if (fread(&relRec, sizeof(RelocRecord), 1, inFile) != 1) { |
error("cannot read code relocation records"); |
} |
conv4FromEcoToNative((unsigned char *) &relRec.offset); |
conv4FromEcoToNative((unsigned char *) &relRec.method); |
conv4FromEcoToNative((unsigned char *) &relRec.value); |
conv4FromEcoToNative((unsigned char *) &relRec.base); |
addReloc(SEGMENT_CODE, &relRec, symMap); |
} |
} |
|
|
void readDataRelocs(void) { |
int n, i; |
RelocRecord relRec; |
|
if (fseek(inFile, DRELOC_START(inHeader), SEEK_SET) < 0) { |
error("cannot seek to data relocation section"); |
} |
n = inHeader.drsize / sizeof(RelocRecord); |
for (i = 0; i < n; i++) { |
if (fread(&relRec, sizeof(RelocRecord), 1, inFile) != 1) { |
error("cannot read data relocation records"); |
} |
conv4FromEcoToNative((unsigned char *) &relRec.offset); |
conv4FromEcoToNative((unsigned char *) &relRec.method); |
conv4FromEcoToNative((unsigned char *) &relRec.value); |
conv4FromEcoToNative((unsigned char *) &relRec.base); |
addReloc(SEGMENT_DATA, &relRec, symMap); |
} |
} |
|
|
void readString(unsigned int offset, char *buffer, int size) { |
long pos; |
int c; |
|
pos = ftell(inFile); |
if (fseek(inFile, STRING_START(inHeader) + offset, SEEK_SET) < 0) { |
error("cannot seek to string"); |
} |
do { |
c = fgetc(inFile); |
if (c == EOF) { |
error("unexpected end of file"); |
} |
*buffer++ = c; |
if (--size == 0) { |
error("string buffer overflow"); |
} |
} while (c != 0); |
fseek(inFile, pos, SEEK_SET); |
} |
|
|
void readSymbols(void) { |
int n, i; |
SymbolRecord symRec; |
char strBuf[MAX_STRLEN]; |
Symbol *sym; |
|
if (fseek(inFile, SYMTBL_START(inHeader), SEEK_SET) < 0) { |
error("cannot seek to symbol table section"); |
} |
n = inHeader.symsize / sizeof(SymbolRecord); |
symMap = allocateMemory(n * sizeof(Symbol *)); |
for (i = 0; i < n; i++) { |
if (fread(&symRec, sizeof(SymbolRecord), 1, inFile) != 1) { |
error("cannot read symbol table"); |
} |
conv4FromEcoToNative((unsigned char *) &symRec.name); |
conv4FromEcoToNative((unsigned char *) &symRec.type); |
conv4FromEcoToNative((unsigned char *) &symRec.value); |
readString(symRec.name, strBuf, MAX_STRLEN); |
sym = lookupEnter(strBuf); |
if ((symRec.type & MSB) == 0) { |
/* the symbol is defined in this symbol record */ |
if ((sym->type & MSB) == 0) { |
/* the symbol was already defined in the table */ |
error("symbol '%s' multiply defined", sym->name); |
} else { |
/* the symbol was not yet defined in the table, so define it now */ |
/* the segment is copied directly from 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 */ |
sym->type = symRec.type; |
sym->value = symRec.value + segPtr[symRec.type]; |
} |
} else { |
/* the symbol is undefined in this symbol record */ |
/* nothing to do here: lookupEnter already entered */ |
/* the symbol into the symbol table, if necessary */ |
} |
/* in any case remember the symbol table entry, so that */ |
/* a symbol index in a relocation record can be resolved */ |
symMap[i] = sym; |
} |
} |
|
|
void readModule(void) { |
/* read the file header to determine the sizes */ |
readHeader(); |
/* read and transfer the code and data segments */ |
readCode(); |
readData(); |
/* read and build the symbol table and a symbol map */ |
readSymbols(); |
/* read and build a list of relocation records */ |
readCodeRelocs(); |
readDataRelocs(); |
/* free the symbol map, it is no longer needed */ |
freeMemory(symMap); |
/* update accumulated segment sizes */ |
segPtr[SEGMENT_CODE] += inHeader.csize; |
segPtr[SEGMENT_DATA] += inHeader.dsize; |
segPtr[SEGMENT_BSS] += inHeader.bsize; |
} |
|
|
/**************************************************************/ |
|
|
void printSymbol(Symbol *s) { |
fprintf(mapFile, "%-32s", s->name); |
if (s->type & MSB) { |
/* symbol is undefined */ |
fprintf(mapFile, "%-15s", "UNDEFINED"); |
} else { |
/* symbol is defined */ |
switch (s->type) { |
case SEGMENT_ABS: |
fprintf(mapFile, "%-15s", "ABS"); |
break; |
case SEGMENT_CODE: |
fprintf(mapFile, "%-15s", "CODE"); |
break; |
case SEGMENT_DATA: |
fprintf(mapFile, "%-15s", "DATA"); |
break; |
case SEGMENT_BSS: |
fprintf(mapFile, "%-15s", "BSS"); |
break; |
default: |
error("illegal symbol segment in printToMap()"); |
} |
} |
fprintf(mapFile, "0x%08X", s->value); |
fprintf(mapFile, "\n"); |
} |
|
|
void printToMapFile(void) { |
walkSymbols(printSymbol); |
fprintf(mapFile, "\n"); |
fprintf(mapFile, "CODE start 0x%08X size 0x%08X\n", |
segStart[SEGMENT_CODE], segPtr[SEGMENT_CODE]); |
fprintf(mapFile, "DATA start 0x%08X size 0x%08X\n", |
segStart[SEGMENT_DATA], segPtr[SEGMENT_DATA]); |
fprintf(mapFile, "BSS start 0x%08X size 0x%08X\n", |
segStart[SEGMENT_BSS], segPtr[SEGMENT_BSS]); |
} |
|
|
/**************************************************************/ |
|
|
void writeHeader(void) { |
ExecHeader outHeader; |
|
if (withHeader) { |
outHeader.magic = EXEC_MAGIC; |
outHeader.csize = segPtr[SEGMENT_CODE]; |
outHeader.dsize = segPtr[SEGMENT_DATA]; |
outHeader.bsize = segPtr[SEGMENT_BSS]; |
outHeader.crsize = 0; |
outHeader.drsize = 0; |
outHeader.symsize = 0; |
outHeader.strsize = 0; |
conv4FromNativeToEco((unsigned char *) &outHeader.magic); |
conv4FromNativeToEco((unsigned char *) &outHeader.csize); |
conv4FromNativeToEco((unsigned char *) &outHeader.dsize); |
conv4FromNativeToEco((unsigned char *) &outHeader.bsize); |
conv4FromNativeToEco((unsigned char *) &outHeader.crsize); |
conv4FromNativeToEco((unsigned char *) &outHeader.drsize); |
conv4FromNativeToEco((unsigned char *) &outHeader.symsize); |
conv4FromNativeToEco((unsigned char *) &outHeader.strsize); |
fwrite(&outHeader, sizeof(ExecHeader), 1, outFile); |
} |
} |
|
|
void writeCode(void) { |
int data; |
|
rewind(codeFile); |
while (1) { |
data = fgetc(codeFile); |
if (data == EOF) { |
break; |
} |
fputc(data, outFile); |
} |
} |
|
|
void writeData(void) { |
int data; |
|
rewind(dataFile); |
while (1) { |
data = fgetc(dataFile); |
if (data == EOF) { |
break; |
} |
fputc(data, outFile); |
} |
} |
|
|
/**************************************************************/ |
|
|
int readNumber(char *str, unsigned int *np) { |
int base; |
int value; |
int digit; |
|
base = 10; |
value = 0; |
if (*str == '0') { |
str++; |
if (*str == 'x' || *str == 'X') { |
base = 16; |
str++; |
} else |
if (isdigit((int) *str)) { |
base = 8; |
} else |
if (*str == '\0') { |
*np = value; |
return 1; |
} else { |
return 0; |
} |
} |
while (isxdigit((int) *str)) { |
digit = *str++ - '0'; |
if (digit >= 'A' - '0') { |
if (digit >= 'a' - '0') { |
digit += '0' - 'a' + 10; |
} else { |
digit += '0' - 'A' + 10; |
} |
} |
if (digit >= base) { |
return 0; |
} |
value *= base; |
value += digit; |
} |
if (*str == '\0') { |
*np = value; |
return 1; |
} else { |
return 0; |
} |
} |
|
|
void usage(char *myself) { |
fprintf(stderr, "Usage: %s\n", myself); |
fprintf(stderr, " [-h] do not write object header\n"); |
fprintf(stderr, " [-o objfile] set output file name\n"); |
fprintf(stderr, " [-m mapfile] produce map file\n"); |
fprintf(stderr, " [-rc addr] relocate code segment\n"); |
fprintf(stderr, " [-rd addr] relocate data segment\n"); |
fprintf(stderr, " [-rb addr] relocate bss segment\n"); |
fprintf(stderr, " file object file name\n"); |
fprintf(stderr, " [files...] additional object files\n"); |
exit(1); |
} |
|
|
int main(int argc, char *argv[]) { |
int i; |
char *argp; |
unsigned int *ssp; |
int *ssdp; |
|
tmpnam(codeName); |
tmpnam(dataName); |
outName = "a.out"; |
for (i = 1; i < argc; i++) { |
argp = argv[i]; |
if (*argp != '-') { |
break; |
} |
argp++; |
switch (*argp) { |
case 'h': |
withHeader = 0; |
break; |
case 'o': |
if (i == argc - 1) { |
usage(argv[0]); |
} |
outName = argv[++i]; |
break; |
case 'm': |
if (i == argc - 1) { |
usage(argv[0]); |
} |
mapName = argv[++i]; |
break; |
case 'r': |
if (argp[1] == 'c') { |
ssp = &segStart[SEGMENT_CODE]; |
ssdp = &segStartDefined[SEGMENT_CODE]; |
} else |
if (argp[1] == 'd') { |
ssp = &segStart[SEGMENT_DATA]; |
ssdp = &segStartDefined[SEGMENT_DATA]; |
} else |
if (argp[1] == 'b') { |
ssp = &segStart[SEGMENT_BSS]; |
ssdp = &segStartDefined[SEGMENT_BSS]; |
} else { |
usage(argv[0]); |
} |
if (i == argc - 1) { |
usage(argv[0]); |
} |
if (!readNumber(argv[++i], ssp)) { |
error("cannot read number given with option '-%s'", argp); |
} |
*ssdp = 1; |
break; |
default: |
usage(argv[0]); |
} |
} |
if (i == argc) { |
usage(argv[0]); |
} |
codeFile = fopen(codeName, "w+b"); |
if (codeFile == NULL) { |
error("cannot create temporary code file '%s'", codeName); |
} |
dataFile = fopen(dataName, "w+b"); |
if (dataFile == NULL) { |
error("cannot create temporary data file '%s'", dataName); |
} |
outFile = fopen(outName, "wb"); |
if (outFile == NULL) { |
error("cannot open output file '%s'", outName); |
} |
if (mapName != NULL) { |
mapFile = fopen(mapName, "wt"); |
if (mapFile == NULL) { |
error("cannot open map file '%s'", mapName); |
} |
} |
do { |
inName = argv[i]; |
if (*inName == '-') { |
usage(argv[0]); |
} |
inFile = fopen(inName, "rb"); |
if (inFile == NULL) { |
error("cannot open input file '%s'", inName); |
} |
fprintf(stderr, "Reading module '%s'...\n", inName); |
readModule(); |
if (inFile != NULL) { |
fclose(inFile); |
inFile = NULL; |
} |
} while (++i < argc); |
fprintf(stderr, "Linking modules...\n"); |
linkSymbols(); |
fprintf(stderr, "Relocating segments...\n"); |
relocateSegments(); |
writeHeader(); |
writeCode(); |
writeData(); |
if (mapFile != NULL) { |
printToMapFile(); |
} |
if (codeFile != NULL) { |
fclose(codeFile); |
codeFile = NULL; |
} |
if (dataFile != NULL) { |
fclose(dataFile); |
dataFile = NULL; |
} |
if (outFile != NULL) { |
fclose(outFile); |
outFile = NULL; |
} |
if (mapFile != NULL) { |
fclose(mapFile); |
mapFile = NULL; |
} |
if (codeName != NULL) { |
unlink(codeName); |
} |
if (dataName != NULL) { |
unlink(dataName); |
} |
return 0; |
} |
/binutils/ld/Makefile
0,0 → 1,36
# |
# Makefile for ECO32 linking loader |
# |
|
BUILD = ../../build |
|
CC = gcc -m32 |
CFLAGS = -g -Wall |
LDFLAGS = -g |
LDLIBS = -lm |
|
SRCS = ld.c |
OBJS = $(patsubst %.c,%.o,$(SRCS)) |
BIN = ld |
|
.PHONY: all install clean |
|
all: $(BIN) |
|
install: $(BIN) |
mkdir -p $(BUILD)/bin |
cp $(BIN) $(BUILD)/bin |
|
$(BIN): $(OBJS) |
$(CC) $(LDFLAGS) -o $(BIN) $(OBJS) $(LDLIBS) |
|
%.o: %.c |
$(CC) $(CFLAGS) -o $@ -c $< |
|
depend.mak: |
$(CC) -MM -MG $(CFLAGS) $(SRCS) > depend.mak |
|
-include depend.mak |
|
clean: |
rm -f *~ $(OBJS) $(BIN) depend.mak |
/binutils/tests-1/L16/test0.s
0,0 → 1,20
.nosyn |
|
.code |
|
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
|
.data |
|
.word 0x55AA55AA |
.word 0x55AA55AA |
.word 0x55AA55AA |
|
.bss |
|
.space 0x100 |
/binutils/tests-1/L16/test1.s
0,0 → 1,56
.nosyn |
|
.export C_global |
.import C_extern |
.export D_global |
.import D_extern |
.export B_global |
.import B_extern |
|
.code |
|
add $3,$2,$1 |
add $3,$2,$1 |
xnor $3,$1,C_local+10 |
xnor $3,$1,C_global+20 |
xnor $3,$1,C_extern+30 |
xnor $3,$1,D_local+40 |
xnor $3,$1,D_global+50 |
xnor $3,$1,D_extern+60 |
xnor $3,$1,B_local+70 |
xnor $3,$1,B_global+80 |
xnor $3,$1,B_extern+90 |
add $3,$2,$1 |
add $3,$2,$1 |
C_local: |
add $3,$2,$1 |
C_global: |
add $3,$2,$1 |
|
.data |
|
.word 0x55AA55AA |
.word 0x55AA55AA |
xnor $3,$1,C_local+10 |
xnor $3,$1,C_global+20 |
xnor $3,$1,C_extern+30 |
xnor $3,$1,D_local+40 |
xnor $3,$1,D_global+50 |
xnor $3,$1,D_extern+60 |
xnor $3,$1,B_local+70 |
xnor $3,$1,B_global+80 |
xnor $3,$1,B_extern+90 |
.word 0x55AA55AA |
.word 0x55AA55AA |
D_local: |
.word 0x55AA55AA |
D_global: |
.word 0x55AA55AA |
|
.bss |
|
.space 0x100 |
B_local: |
.space 0x100 |
B_global: |
.space 0x100 |
/binutils/tests-1/L16/test2.s
0,0 → 1,30
.nosyn |
|
.export C_extern |
.export D_extern |
.export B_extern |
|
.code |
|
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
C_extern: |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
|
.data |
|
.word 0x55AA55AA |
.word 0x55AA55AA |
.word 0x55AA55AA |
D_extern: |
.word 0x55AA55AA |
.word 0x55AA55AA |
.word 0x55AA55AA |
|
.bss |
.space 0x100 |
B_extern: |
.space 0x100 |
/binutils/tests-1/L16/Makefile
0,0 → 1,15
# |
# Makefile for as/ld test |
# |
|
BUILD = ../../../build |
|
all: |
$(BUILD)/bin/as -o test0.o test0.s |
$(BUILD)/bin/as -o test1.o test1.s |
$(BUILD)/bin/as -o test2.o test2.s |
$(BUILD)/bin/ld -h -o test -m test.map test0.o test1.o test2.o |
$(BUILD)/bin/dof -a test1.o >test1.dump |
|
clean: |
rm -f *~ test0.o test1.o test2.o test test.map test1.dump |
/binutils/tests-1/R16/test0.s
0,0 → 1,20
.nosyn |
|
.code |
|
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
|
.data |
|
.word 0x55AA55AA |
.word 0x55AA55AA |
.word 0x55AA55AA |
|
.bss |
|
.space 0x100 |
/binutils/tests-1/R16/test1.s
0,0 → 1,56
.nosyn |
|
.export C_global |
.import C_extern |
.export D_global |
.import D_extern |
.export B_global |
.import B_extern |
|
.code |
|
add $3,$2,$1 |
add $3,$2,$1 |
beq $2,$1,C_local+10 |
beq $2,$1,C_global+20 |
beq $2,$1,C_extern+30 |
beq $2,$1,D_local+40 |
beq $2,$1,D_global+50 |
beq $2,$1,D_extern+60 |
beq $2,$1,B_local+70 |
beq $2,$1,B_global+80 |
beq $2,$1,B_extern+90 |
add $3,$2,$1 |
add $3,$2,$1 |
C_local: |
add $3,$2,$1 |
C_global: |
add $3,$2,$1 |
|
.data |
|
.word 0x55AA55AA |
.word 0x55AA55AA |
beq $2,$1,C_local+10 |
beq $2,$1,C_global+20 |
beq $2,$1,C_extern+30 |
beq $2,$1,D_local+40 |
beq $2,$1,D_global+50 |
beq $2,$1,D_extern+60 |
beq $2,$1,B_local+70 |
beq $2,$1,B_global+80 |
beq $2,$1,B_extern+90 |
.word 0x55AA55AA |
.word 0x55AA55AA |
D_local: |
.word 0x55AA55AA |
D_global: |
.word 0x55AA55AA |
|
.bss |
|
.space 0x100 |
B_local: |
.space 0x100 |
B_global: |
.space 0x100 |
/binutils/tests-1/R16/test2.s
0,0 → 1,30
.nosyn |
|
.export C_extern |
.export D_extern |
.export B_extern |
|
.code |
|
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
C_extern: |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
|
.data |
|
.word 0x55AA55AA |
.word 0x55AA55AA |
.word 0x55AA55AA |
D_extern: |
.word 0x55AA55AA |
.word 0x55AA55AA |
.word 0x55AA55AA |
|
.bss |
.space 0x100 |
B_extern: |
.space 0x100 |
/binutils/tests-1/R16/Makefile
0,0 → 1,15
# |
# Makefile for as/ld test |
# |
|
BUILD = ../../../build |
|
all: |
$(BUILD)/bin/as -o test0.o test0.s |
$(BUILD)/bin/as -o test1.o test1.s |
$(BUILD)/bin/as -o test2.o test2.s |
$(BUILD)/bin/ld -h -o test -m test.map test0.o test1.o test2.o |
$(BUILD)/bin/dof -a test1.o >test1.dump |
|
clean: |
rm -f *~ test0.o test1.o test2.o test test.map test1.dump |
/binutils/tests-1/R26/test0.s
0,0 → 1,20
.nosyn |
|
.code |
|
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
|
.data |
|
.word 0x55AA55AA |
.word 0x55AA55AA |
.word 0x55AA55AA |
|
.bss |
|
.space 0x100 |
/binutils/tests-1/R26/test1.s
0,0 → 1,56
.nosyn |
|
.export C_global |
.import C_extern |
.export D_global |
.import D_extern |
.export B_global |
.import B_extern |
|
.code |
|
add $3,$2,$1 |
add $3,$2,$1 |
j C_local+10 |
j C_global+20 |
j C_extern+30 |
j D_local+40 |
j D_global+50 |
j D_extern+60 |
j B_local+70 |
j B_global+80 |
j B_extern+90 |
add $3,$2,$1 |
add $3,$2,$1 |
C_local: |
add $3,$2,$1 |
C_global: |
add $3,$2,$1 |
|
.data |
|
.word 0x55AA55AA |
.word 0x55AA55AA |
j C_local+10 |
j C_global+20 |
j C_extern+30 |
j D_local+40 |
j D_global+50 |
j D_extern+60 |
j B_local+70 |
j B_global+80 |
j B_extern+90 |
.word 0x55AA55AA |
.word 0x55AA55AA |
D_local: |
.word 0x55AA55AA |
D_global: |
.word 0x55AA55AA |
|
.bss |
|
.space 0x100 |
B_local: |
.space 0x100 |
B_global: |
.space 0x100 |
/binutils/tests-1/R26/test2.s
0,0 → 1,30
.nosyn |
|
.export C_extern |
.export D_extern |
.export B_extern |
|
.code |
|
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
C_extern: |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
|
.data |
|
.word 0x55AA55AA |
.word 0x55AA55AA |
.word 0x55AA55AA |
D_extern: |
.word 0x55AA55AA |
.word 0x55AA55AA |
.word 0x55AA55AA |
|
.bss |
.space 0x100 |
B_extern: |
.space 0x100 |
/binutils/tests-1/R26/Makefile
0,0 → 1,15
# |
# Makefile for as/ld test |
# |
|
BUILD = ../../../build |
|
all: |
$(BUILD)/bin/as -o test0.o test0.s |
$(BUILD)/bin/as -o test1.o test1.s |
$(BUILD)/bin/as -o test2.o test2.s |
$(BUILD)/bin/ld -h -o test -m test.map test0.o test1.o test2.o |
$(BUILD)/bin/dof -a test1.o >test1.dump |
|
clean: |
rm -f *~ test0.o test1.o test2.o test test.map test1.dump |
/binutils/tests-1/W32/test0.s
0,0 → 1,20
.nosyn |
|
.code |
|
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
|
.data |
|
.word 0x55AA55AA |
.word 0x55AA55AA |
.word 0x55AA55AA |
|
.bss |
|
.space 0x100 |
/binutils/tests-1/W32/test1.s
0,0 → 1,56
.nosyn |
|
.export C_global |
.import C_extern |
.export D_global |
.import D_extern |
.export B_global |
.import B_extern |
|
.code |
|
add $3,$2,$1 |
add $3,$2,$1 |
.word C_local+10 |
.word C_global+20 |
.word C_extern+30 |
.word D_local+40 |
.word D_global+50 |
.word D_extern+60 |
.word B_local+70 |
.word B_global+80 |
.word B_extern+90 |
add $3,$2,$1 |
add $3,$2,$1 |
C_local: |
add $3,$2,$1 |
C_global: |
add $3,$2,$1 |
|
.data |
|
.word 0x55AA55AA |
.word 0x55AA55AA |
.word C_local+10 |
.word C_global+20 |
.word C_extern+30 |
.word D_local+40 |
.word D_global+50 |
.word D_extern+60 |
.word B_local+70 |
.word B_global+80 |
.word B_extern+90 |
.word 0x55AA55AA |
.word 0x55AA55AA |
D_local: |
.word 0x55AA55AA |
D_global: |
.word 0x55AA55AA |
|
.bss |
|
.space 0x100 |
B_local: |
.space 0x100 |
B_global: |
.space 0x100 |
/binutils/tests-1/W32/test2.s
0,0 → 1,30
.nosyn |
|
.export C_extern |
.export D_extern |
.export B_extern |
|
.code |
|
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
C_extern: |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
|
.data |
|
.word 0x55AA55AA |
.word 0x55AA55AA |
.word 0x55AA55AA |
D_extern: |
.word 0x55AA55AA |
.word 0x55AA55AA |
.word 0x55AA55AA |
|
.bss |
.space 0x100 |
B_extern: |
.space 0x100 |
/binutils/tests-1/W32/Makefile
0,0 → 1,15
# |
# Makefile for as/ld test |
# |
|
BUILD = ../../../build |
|
all: |
$(BUILD)/bin/as -o test0.o test0.s |
$(BUILD)/bin/as -o test1.o test1.s |
$(BUILD)/bin/as -o test2.o test2.s |
$(BUILD)/bin/ld -h -o test -m test.map test0.o test1.o test2.o |
$(BUILD)/bin/dof -a test1.o >test1.dump |
|
clean: |
rm -f *~ test0.o test1.o test2.o test test.map test1.dump |
/binutils/tests-1/Makefile
0,0 → 1,20
# |
# Makefile for as/ld tests |
# |
|
BUILD = ../../build |
|
DIRS = H16 L16 R16 R26 W32 |
|
.PHONY: all clean |
|
all: |
for i in $(DIRS) ; do \ |
$(MAKE) -C $$i all ; \ |
done |
|
clean: |
for i in $(DIRS) ; do \ |
$(MAKE) -C $$i clean ; \ |
done |
rm -f *~ |
/binutils/tests-1/H16/test0.s
0,0 → 1,20
.nosyn |
|
.code |
|
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
|
.data |
|
.word 0x55AA55AA |
.word 0x55AA55AA |
.word 0x55AA55AA |
|
.bss |
|
.space 0x100 |
/binutils/tests-1/H16/test1.s
0,0 → 1,56
.nosyn |
|
.export C_global |
.import C_extern |
.export D_global |
.import D_extern |
.export B_global |
.import B_extern |
|
.code |
|
add $3,$2,$1 |
add $3,$2,$1 |
ldhi $3,C_local+10 |
ldhi $3,C_global+20 |
ldhi $3,C_extern+30 |
ldhi $3,D_local+40 |
ldhi $3,D_global+50 |
ldhi $3,D_extern+60 |
ldhi $3,B_local+70 |
ldhi $3,B_global+80 |
ldhi $3,B_extern+90 |
add $3,$2,$1 |
add $3,$2,$1 |
C_local: |
add $3,$2,$1 |
C_global: |
add $3,$2,$1 |
|
.data |
|
.word 0x55AA55AA |
.word 0x55AA55AA |
ldhi $3,C_local+10 |
ldhi $3,C_global+20 |
ldhi $3,C_extern+30 |
ldhi $3,D_local+40 |
ldhi $3,D_global+50 |
ldhi $3,D_extern+60 |
ldhi $3,B_local+70 |
ldhi $3,B_global+80 |
ldhi $3,B_extern+90 |
.word 0x55AA55AA |
.word 0x55AA55AA |
D_local: |
.word 0x55AA55AA |
D_global: |
.word 0x55AA55AA |
|
.bss |
|
.space 0x100 |
B_local: |
.space 0x100 |
B_global: |
.space 0x100 |
/binutils/tests-1/H16/test2.s
0,0 → 1,30
.nosyn |
|
.export C_extern |
.export D_extern |
.export B_extern |
|
.code |
|
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
C_extern: |
add $3,$2,$1 |
add $3,$2,$1 |
add $3,$2,$1 |
|
.data |
|
.word 0x55AA55AA |
.word 0x55AA55AA |
.word 0x55AA55AA |
D_extern: |
.word 0x55AA55AA |
.word 0x55AA55AA |
.word 0x55AA55AA |
|
.bss |
.space 0x100 |
B_extern: |
.space 0x100 |
/binutils/tests-1/H16/Makefile
0,0 → 1,15
# |
# Makefile for as/ld test |
# |
|
BUILD = ../../../build |
|
all: |
$(BUILD)/bin/as -o test0.o test0.s |
$(BUILD)/bin/as -o test1.o test1.s |
$(BUILD)/bin/as -o test2.o test2.s |
$(BUILD)/bin/ld -h -o test -m test.map test0.o test1.o test2.o |
$(BUILD)/bin/dof -a test1.o >test1.dump |
|
clean: |
rm -f *~ test0.o test1.o test2.o test test.map test1.dump |
/binutils/tests-2/intrpt/intrpt.s
0,0 → 1,229
; |
; intrpt.s -- a first attempt to utilize interrupts |
; |
|
.set stack,0xC0010000 ; stack |
.set timerbase,0xF0000000 ; timer base address |
.set termbase,0xF0300000 ; terminal base address |
|
reset: |
j start ; reset arrives here |
|
intrpt: |
j isr ; interrupts arrive here |
|
userMiss: |
j userMiss ; user TLB miss exceptions arrive here |
|
isr: |
mvfs $26,0 ; determine cause |
slr $26,$26,14 ; $26 = 4 * IRQ number |
and $26,$26,0x1F << 2 |
ldw $26,$26,irqsrv ; get addr of service routine |
jr $26 ; jump to service routine |
|
start: |
add $29,$0,stack ; set sp |
add $4,$0,runmsg ; pointer to string |
jal msg ; show string |
add $8,$0,timerbase ; program timer |
add $9,$0,1000 ; divisor = 1000 |
stw $9,$8,4 |
add $9,$0,2 ; enable timer interrupts |
stw $9,$8,0 |
mvfs $8,0 |
or $8,$8,1 << 14 ; open timer IRQ mask bit |
or $8,$8,1 << 23 ; enable processor interrupts |
or $8,$8,1 << 27 ; let vector point to RAM |
mvts $8,0 |
start1: |
j start1 ; loop |
|
tmrisr: |
add $8,$0,0x02 ; ien = 1, int = 0 |
stw $8,$0,timerbase |
j shmsg |
|
shmsg: |
mvfs $8,0 |
slr $8,$8,14 ; $8 = 4 * IRQ number |
and $8,$8,0x1F << 2 |
ldw $4,$8,msgtbl ; get addr of message |
jal msg ; show message |
rfx ; return from exception |
|
msg: |
sub $29,$29,8 ; save registers |
stw $31,$29,4 |
stw $16,$29,0 |
add $16,$4,$0 ; get pointer |
msg1: |
ldbu $4,$16,0 ; get char |
beq $4,$0,msg2 ; null - finished |
jal out ; output char |
add $16,$16,1 ; bump pointer |
j msg1 ; next char |
msg2: |
ldw $16,$29,0 ; restore registers |
ldw $31,$29,4 |
add $29,$29,8 |
jr $31 ; return |
|
out: |
add $8,$0,termbase ; set I/O base address |
out1: |
ldw $9,$8,8 ; get status |
and $9,$9,1 ; xmtr ready? |
beq $9,$0,out1 ; no - wait |
stw $4,$8,12 ; send char |
jr $31 ; return |
|
; service routine table |
|
irqsrv: |
.word shmsg ; 00: terminal 0 transmitter interrupt |
.word shmsg ; 01: terminal 0 receiver interrupt |
.word shmsg ; 02: terminal 1 transmitter interrupt |
.word shmsg ; 03: terminal 1 receiver interrupt |
.word shmsg ; 04: keyboard interrupt |
.word shmsg ; 05: unused |
.word shmsg ; 06: unused |
.word shmsg ; 07: unused |
.word shmsg ; 08: disk interrupt |
.word shmsg ; 09: unused |
.word shmsg ; 10: unused |
.word shmsg ; 11: unused |
.word shmsg ; 12: unused |
.word shmsg ; 13: unused |
.word tmrisr ; 14: timer interrupt |
.word shmsg ; 15: unused |
.word shmsg ; 16: bus timeout exception |
.word shmsg ; 17: illegal instruction exception |
.word shmsg ; 18: privileged instruction exception |
.word shmsg ; 19: divide instruction exception |
.word shmsg ; 20: trap instruction exception |
.word shmsg ; 21: TLB miss exception |
.word shmsg ; 22: TLB write exception |
.word shmsg ; 23: TLB invalid exception |
.word shmsg ; 24: illegal address exception |
.word shmsg ; 25: privileged address exception |
.word shmsg ; 26: unused |
.word shmsg ; 27: unused |
.word shmsg ; 28: unused |
.word shmsg ; 29: unused |
.word shmsg ; 30: unused |
.word shmsg ; 31: unused |
|
; message table |
|
msgtbl: |
.word xmtmsg ; 00: terminal 0 transmitter interrupt |
.word rcvmsg ; 01: terminal 0 receiver interrupt |
.word xmtmsg ; 02: terminal 1 transmitter interrupt |
.word rcvmsg ; 03: terminal 1 receiver interrupt |
.word kbdmsg ; 04: keyboard interrupt |
.word uimsg ; 05: unused |
.word uimsg ; 06: unused |
.word uimsg ; 07: unused |
.word dskmsg ; 08: disk interrupt |
.word uimsg ; 09: unused |
.word uimsg ; 10: unused |
.word uimsg ; 11: unused |
.word uimsg ; 12: unused |
.word uimsg ; 13: unused |
.word tmrmsg ; 14: timer interrupt |
.word uimsg ; 15: unused |
.word btmsg ; 16: bus timeout exception |
.word iimsg ; 17: illegal instruction exception |
.word pimsg ; 18: privileged instruction exception |
.word dimsg ; 19: divide instruction exception |
.word timsg ; 20: trap instruction exception |
.word msmsg ; 21: TLB miss exception |
.word wrmsg ; 22: TLB write exception |
.word ivmsg ; 23: TLB invalid exception |
.word iamsg ; 24: illegal address exception |
.word pamsg ; 25: privileged address exception |
.word uemsg ; 26: unused |
.word uemsg ; 27: unused |
.word uemsg ; 28: unused |
.word uemsg ; 29: unused |
.word uemsg ; 30: unused |
.word uemsg ; 31: unused |
|
; sign-on message |
|
runmsg: |
.byte "system running..." |
.byte 0x0D, 0x0A, 0 |
|
; interrupt messages |
|
uimsg: |
.byte "unknown interrupt" |
.byte 0x0D, 0x0A, 0 |
|
xmtmsg: |
.byte "terminal transmitter interrupt" |
.byte 0x0D, 0x0A, 0 |
|
rcvmsg: |
.byte "terminal receiver interrupt" |
.byte 0x0D, 0x0A, 0 |
|
kbdmsg: |
.byte "keyboard interrupt" |
.byte 0x0D, 0x0A, 0 |
|
dskmsg: |
.byte "disk interrupt" |
.byte 0x0D, 0x0A, 0 |
|
tmrmsg: |
.byte "timer interrupt" |
.byte 0x0D, 0x0A, 0 |
|
; exception messages |
|
uemsg: |
.byte "unknown exception" |
.byte 0x0D, 0x0A, 0 |
|
btmsg: |
.byte "bus timeout exception" |
.byte 0x0D, 0x0A, 0 |
|
iimsg: |
.byte "illegal instruction exception" |
.byte 0x0D, 0x0A, 0 |
|
pimsg: |
.byte "privileged instruction exception" |
.byte 0x0D, 0x0A, 0 |
|
dimsg: |
.byte "divide instruction exception" |
.byte 0x0D, 0x0A, 0 |
|
timsg: |
.byte "trap instruction exception" |
.byte 0x0D, 0x0A, 0 |
|
msmsg: |
.byte "TLB miss exception" |
.byte 0x0D, 0x0A, 0 |
|
wrmsg: |
.byte "TLB write exception" |
.byte 0x0D, 0x0A, 0 |
|
ivmsg: |
.byte "TLB invalid exception" |
.byte 0x0D, 0x0A, 0 |
|
iamsg: |
.byte "illegal address exception" |
.byte 0x0D, 0x0A, 0 |
|
pamsg: |
.byte "privileged address exception" |
.byte 0x0D, 0x0A, 0 |
/binutils/tests-2/intrpt/Makefile
0,0 → 1,15
BUILD = ../../../build |
|
all: intrpt.bin |
|
intrpt.bin: intrpt.o |
$(BUILD)/bin/ld -h -rc 0xC0000000 -o intrpt.bin intrpt.o |
|
intrpt.o: intrpt.s |
$(BUILD)/bin/as -o intrpt.o intrpt.s |
|
run: intrpt.bin |
$(BUILD)/bin/sim -t 1 -l intrpt.bin |
|
clean: |
rm -f *~ intrpt.bin intrpt.o |
/binutils/tests-2/permute/src1.s
0,0 → 1,5
.code |
.import fptr |
.export call |
.word 0x11111111 |
call: .word fptr |
/binutils/tests-2/permute/src2.s
0,0 → 1,6
.data |
.import func |
.export fptr |
.word 0x11111111 |
.word 0x22222222 |
fptr: .word func |
/binutils/tests-2/permute/src3.s
0,0 → 1,7
.code |
.export func |
.import call |
.word 0x11111111 |
.word 0x22222222 |
.word 0x33333333 |
func: .word call |
/binutils/tests-2/permute/Makefile
0,0 → 1,34
BUILD = ../../../build |
|
all: all123 all132 all213 all231 all312 all321 |
|
all123: src1.o src2.o src3.o |
$(BUILD)/bin/ld -o all123 src1.o src2.o src3.o |
|
all132: src1.o src2.o src3.o |
$(BUILD)/bin/ld -o all132 src1.o src3.o src2.o |
|
all213: src1.o src2.o src3.o |
$(BUILD)/bin/ld -o all213 src2.o src1.o src3.o |
|
all231: src1.o src2.o src3.o |
$(BUILD)/bin/ld -o all231 src2.o src3.o src1.o |
|
all312: src1.o src2.o src3.o |
$(BUILD)/bin/ld -o all312 src3.o src1.o src2.o |
|
all321: src1.o src2.o src3.o |
$(BUILD)/bin/ld -o all321 src3.o src2.o src1.o |
|
src1.o: src1.s |
$(BUILD)/bin/as -o src1.o src1.s |
|
src2.o: src2.s |
$(BUILD)/bin/as -o src2.o src2.s |
|
src3.o: src3.s |
$(BUILD)/bin/as -o src3.o src3.s |
|
clean: |
rm -f *~ src1.o src2.o src3.o |
rm -f all123 all132 all213 all231 all312 all321 |
/binutils/tests-2/hello/hello.s
0,0 → 1,39
; |
; hello.s -- Hello, world! |
; |
|
; $11 I/O base address |
; $12 temporary value |
; $13 character |
; $14 pointer to string |
; $29 stack pointer |
; $31 return address |
|
.set tba,0xF0300000 |
|
reset: add $29,$0,0xC0010000 |
jal start |
reset1: j reset1 |
|
start: sub $29,$29,4 ; save return register |
stw $31,$29,0 |
add $11,$0,tba ; set I/O base address |
add $14,$0,hello ; pointer to string |
or $14,$14,hello |
loop: ldbu $13,$14,0 ; get char |
beq $13,$0,stop ; null - finished |
jal out ; output char |
add $14,$14,1 ; bump pointer |
j loop ; next char |
stop: ldw $31,$29,0 ; restore return register |
add $29,$29,4 |
jr $31 ; return |
|
out: ldw $12,$11,8 ; get status |
and $12,$12,1 ; xmtr ready? |
beq $12,$0,out ; no - wait |
stw $13,$11,12 ; send char |
jr $31 ; return |
|
hello: .byte "Hello, world!" |
.byte 0x0D, 0x0A, 0 |
/binutils/tests-2/hello/Makefile
0,0 → 1,15
BUILD = ../../../build |
|
all: hello.bin |
|
hello.bin: hello.o |
$(BUILD)/bin/ld -h -rc 0xC0000000 -o hello.bin hello.o |
|
hello.o: hello.s |
$(BUILD)/bin/as -o hello.o hello.s |
|
run: hello.bin |
$(BUILD)/bin/sim -t 1 -l hello.bin |
|
clean: |
rm -f *~ hello.bin hello.o |
/binutils/tests-2/abs/abs1.s
0,0 → 1,3
.code |
.export absval |
.set absval,0xdeadbeef |
/binutils/tests-2/abs/abs2.s
0,0 → 1,4
.code |
.import absval |
ldhi $4,absval |
or $4,$4,absval |
/binutils/tests-2/abs/Makefile
0,0 → 1,15
BUILD = ../../../build |
|
all: |
$(BUILD)/bin/as -o abs1.o abs1.s |
$(BUILD)/bin/as -o abs2.o abs2.s |
$(BUILD)/bin/ld -o abs12 abs1.o abs2.o |
$(BUILD)/bin/ld -o abs21 abs2.o abs1.o |
@echo -n "Comparing abs12 and abs21: " |
@if cmp abs12 abs21 ; \ |
then echo "Files are equal." ; \ |
else echo "Error found!" ; \ |
fi |
|
clean: |
rm -f *~ abs1.o abs2.o abs12 abs21 |
/binutils/tests-2/format/format.s
0,0 → 1,32
|
.export label |
|
.code |
|
; formatN |
trap |
|
; formatRH |
mvfs $23,1 |
|
; formatRHH |
ldhi $23,0x12345678 |
ldhi $23,label+4 |
|
; formatRRX |
and $23,$24,$25 |
and $23,$24,0x00005678 |
and $23,$24,0x12340000 |
and $23,$24,0x12345678 |
and $23,$24,label+4 |
|
; formatRRY |
add $23,$24,$25 |
add $23,$24,0x00005678 |
add $23,$24,0x12340000 |
add $23,$24,0x12345678 |
add $23,$24,label+4 |
|
.bss |
.space 0x1234 |
label: .word 0 |
/binutils/tests-2/format/Makefile
0,0 → 1,16
BUILD = ../../../build |
|
all: format.bin |
|
format.bin: format.o |
$(BUILD)/bin/ld -h -rc 0xC0000000 -o format.bin \ |
-m format.map format.o |
|
format.o: format.s |
$(BUILD)/bin/as -o format.o format.s |
|
run: format.bin |
$(BUILD)/bin/sim -i -l format.bin |
|
clean: |
rm -f *~ format.map format.bin format.o |
/binutils/tests-2/jump/jump1.s
0,0 → 1,10
.code |
|
.import lbl2 |
.export lbl1 |
|
add $1,$2,$3 |
add $4,$5,$6 |
lbl1: j lbl2 |
add $7,$8,$9 |
add $10,$11,$12 |
/binutils/tests-2/jump/Makefile
0,0 → 1,10
BUILD = ../../../build |
|
all: |
$(BUILD)/bin/as -o jump1.o jump1.s |
$(BUILD)/bin/as -o jump2.o jump2.s |
$(BUILD)/bin/ld -rc 0x12345678 -o jump jump1.o jump2.o |
hexdump jump |
|
clean: |
rm -f *~ jump1.o jump2.o jump |
/binutils/tests-2/jump/jump2.s
0,0 → 1,10
.code |
|
.import lbl1 |
.export lbl2 |
|
add $13,$14,$15 |
add $16,$17,$18 |
lbl2: j lbl1 |
add $19,$20,$21 |
add $22,$23,$24 |
/binutils/tests-2/set/set.s
0,0 → 1,6
.set s1,11 |
.set s2,s1+22 |
.set s3,s2-s1 |
|
.data |
.word s3 |
/binutils/tests-2/set/Makefile
0,0 → 1,9
BUILD = ../../../build |
|
all: |
$(BUILD)/bin/as -o set.o set.s |
$(BUILD)/bin/ld -o set set.o |
hexdump set |
|
clean: |
rm -f *~ set set.o |
/binutils/tests-2/link/link1.s
0,0 → 1,7
.data |
|
.import func |
|
.word 0x12345678 |
.word 0xDEADBEEF |
.word func+2 |
/binutils/tests-2/link/link2.s
0,0 → 1,10
.code |
|
.export func |
|
.word 0x87654321 |
.word 0xBEEFDEAD |
|
func: |
.word 0x11223344 |
.word 0x55667788 |
/binutils/tests-2/link/Makefile
0,0 → 1,15
BUILD = ../../../build |
|
all: |
$(BUILD)/bin/as -o link1.o link1.s |
$(BUILD)/bin/as -o link2.o link2.s |
$(BUILD)/bin/ld -o link12 link1.o link2.o |
$(BUILD)/bin/ld -o link21 link2.o link1.o |
@echo -n "Comparing link12 and link21: " |
@if cmp link12 link21 ; \ |
then echo "Files are equal." ; \ |
else echo "Error found!" ; \ |
fi |
|
clean: |
rm -f *~ link1.o link2.o link12 link21 |
/binutils/tests-2/src123/src1.s
0,0 → 1,5
.code |
.import fptr |
.export call |
.word 0x11111111 |
call: .word fptr |
/binutils/tests-2/src123/src2.s
0,0 → 1,6
.data |
.import func |
.export fptr |
.word 0x11111111 |
.word 0x22222222 |
fptr: .word func |
/binutils/tests-2/src123/src3.s
0,0 → 1,7
.code |
.export func |
.import call |
.word 0x11111111 |
.word 0x22222222 |
.word 0x33333333 |
func: .word call |
/binutils/tests-2/src123/Makefile
0,0 → 1,11
BUILD = ../../../build |
|
all: |
$(BUILD)/bin/as -o src1.o src1.s |
$(BUILD)/bin/as -o src2.o src2.s |
$(BUILD)/bin/as -o src3.o src3.s |
$(BUILD)/bin/ld -o src123 src1.o src2.o src3.o |
hexdump src123 |
|
clean: |
rm -f *~ src123 src1.o src2.o src3.o |
/binutils/ar/endian.c
0,0 → 1,38
/* |
* endian.c -- endianness conversions |
*/ |
|
|
#include "endian.h" |
|
|
unsigned int read4FromEco(unsigned char *p) { |
return (unsigned int) p[0] << 24 | |
(unsigned int) p[1] << 16 | |
(unsigned int) p[2] << 8 | |
(unsigned int) p[3] << 0; |
} |
|
|
void write4ToEco(unsigned char *p, unsigned int data) { |
p[0] = data >> 24; |
p[1] = data >> 16; |
p[2] = data >> 8; |
p[3] = data >> 0; |
} |
|
|
void conv4FromEcoToNative(unsigned char *p) { |
unsigned int data; |
|
data = read4FromEco(p); |
* (unsigned int *) p = data; |
} |
|
|
void conv4FromNativeToEco(unsigned char *p) { |
unsigned int data; |
|
data = * (unsigned int *) p; |
write4ToEco(p, data); |
} |
/binutils/ar/test1/text
0,0 → 1,38
This is a well-defined text. |
/binutils/ar/test2/ttt.s
0,0 → 1,5
.code |
.export L12345 |
|
L12345: |
add $1,$2,$3 |
/binutils/ar/ar.c
0,0 → 1,865
/* |
* ar.c -- archiver |
*/ |
|
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <signal.h> |
#include <unistd.h> |
#include <sys/stat.h> |
#include <fcntl.h> |
#include <time.h> |
|
#include "endian.h" |
#include "ranlib.h" |
#include "../include/ar.h" |
|
|
/**************************************************************/ |
|
|
#define BUFSIZE 512 |
|
#define SKIP 0x01 |
#define IODD 0x02 |
#define OODD 0x04 |
#define HEAD 0x08 |
|
|
char *com = "drqtpmx"; |
char *opt = "vuabcls"; |
|
int signums[] = { SIGHUP, SIGINT, SIGQUIT, 0 }; |
|
void (*comfun)(void); |
int flg[26]; |
|
char *arnam; |
int af; |
|
char **namv; |
int namc; |
|
int baState; |
char *posName; |
|
char tmp0nam[20]; |
char tmp1nam[20]; |
char tmp2nam[20]; |
char *tf0nam; |
char *tf1nam; |
char *tf2nam; |
int tf0; |
int tf1; |
int tf2; |
int qf; |
|
char *file; |
char name[MAX_NAME]; |
|
struct stat stbuf; |
ArHeader arbuf; |
unsigned char buf[BUFSIZE]; |
|
|
/**************************************************************/ |
|
|
#define IFMT 070000 |
#define SUID 004000 |
#define SGID 002000 |
#define STXT 001000 |
#define ROWN 000400 |
#define WOWN 000200 |
#define XOWN 000100 |
#define RGRP 000040 |
#define WGRP 000020 |
#define XGRP 000010 |
#define ROTH 000004 |
#define WOTH 000002 |
#define XOTH 000001 |
|
|
int m1[] = { 1, ROWN, 'r', '-' }; |
int m2[] = { 1, WOWN, 'w', '-' }; |
int m3[] = { 2, SUID, 's', XOWN, 'x', '-' }; |
int m4[] = { 1, RGRP, 'r', '-' }; |
int m5[] = { 1, WGRP, 'w', '-' }; |
int m6[] = { 2, SGID, 's', XGRP, 'x', '-' }; |
int m7[] = { 1, ROTH, 'r', '-' }; |
int m8[] = { 1, WOTH, 'w', '-' }; |
int m9[] = { 2, STXT, 't', XOTH, 'x', '-' }; |
|
int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9 }; |
|
|
void selectChar(int *pairp) { |
int *ap; |
int n; |
|
ap = pairp; |
n = *ap++; |
while (--n >= 0 && (arbuf.mode & *ap++) == 0) { |
ap++; |
} |
putchar(*ap); |
} |
|
|
void printMode(void) { |
int **mp; |
|
for (mp = &m[0]; mp < &m[9]; mp++) { |
selectChar(*mp); |
} |
} |
|
|
void showAttributes(void) { |
char *cp; |
|
printMode(); |
printf("%4d/%4d", arbuf.uid, arbuf.gid); |
printf("%8ld", arbuf.size); |
cp = ctime(&arbuf.date); |
printf(" %-12.12s %-4.4s ", cp + 4, cp + 20); |
} |
|
|
/**************************************************************/ |
|
|
void mesg(int c) { |
if (flg['v' - 'a']) { |
printf("%c - %s\n", c, file); |
} |
} |
|
|
char *trim(char *s) { |
char *p1; |
char *p2; |
|
for (p1 = s; *p1 != '\0'; p1++) ; |
while (p1 > s) { |
if (*--p1 != '/') { |
break; |
} |
*p1 = '\0'; |
} |
p2 = s; |
for (p1 = s; *p1 != '\0'; p1++) { |
if (*p1 == '/') { |
p2 = p1 + 1; |
} |
} |
return p2; |
} |
|
|
int notFound(void) { |
int n; |
int i; |
|
n = 0; |
for (i = 0; i < namc; i++) { |
if (namv[i] != NULL) { |
fprintf(stderr, "ar: %s not found\n", namv[i]); |
n++; |
} |
} |
return n; |
} |
|
|
int moreFiles(void) { |
int n; |
int i; |
|
n = 0; |
for (i = 0; i < namc; i++) { |
if (namv[i] != NULL) { |
n++; |
} |
} |
return n; |
} |
|
|
void unlinkTempFiles(void) { |
if (tf0nam != NULL) { |
unlink(tf0nam); |
} |
if (tf1nam != NULL) { |
unlink(tf1nam); |
} |
if (tf2nam != NULL) { |
unlink(tf2nam); |
} |
} |
|
|
void done(int c) { |
unlinkTempFiles(); |
exit(c); |
} |
|
|
void sigDone(int signum) { |
done(100); |
} |
|
|
void noArchive(void) { |
fprintf(stderr, "ar: %s does not exist\n", arnam); |
done(1); |
} |
|
|
void writeError(void) { |
perror("ar write error"); |
done(1); |
} |
|
|
void phaseError(void) { |
fprintf(stderr, "ar: phase error on %s\n", file); |
} |
|
|
int stats(void) { |
int f; |
|
f = open(file, O_RDONLY); |
if (f < 0) { |
return f; |
} |
if (fstat(f, &stbuf) < 0) { |
close(f); |
return -1; |
} |
return f; |
} |
|
|
int match(void) { |
int i; |
|
for (i = 0; i < namc; i++) { |
if (namv[i] == NULL) { |
continue; |
} |
if (strcmp(trim(namv[i]), file) == 0) { |
file = namv[i]; |
namv[i] = NULL; |
return 1; |
} |
} |
return 0; |
} |
|
|
void baMatch(void) { |
int f; |
|
if (baState == 1) { |
if (strcmp(file, posName) != 0) { |
return; |
} |
baState = 2; |
if (flg['a' - 'a']) { |
return; |
} |
} |
if (baState == 2) { |
baState = 0; |
tf1nam = mktemp(tmp1nam); |
close(creat(tf1nam, 0600)); |
f = open(tf1nam, O_RDWR); |
if (f < 0) { |
fprintf(stderr, "ar: cannot create second temp file\n"); |
return; |
} |
tf1 = tf0; |
tf0 = f; |
} |
} |
|
|
/**************************************************************/ |
|
|
void init(void) { |
unsigned int mbuf; |
|
write4ToEco((unsigned char *) &mbuf, AR_MAGIC); |
tf0nam = mktemp(tmp0nam); |
close(creat(tf0nam, 0600)); |
tf0 = open(tf0nam, O_RDWR); |
if (tf0 < 0) { |
fprintf(stderr, "ar: cannot create temp file\n"); |
done(1); |
} |
if (write(tf0, &mbuf, sizeof(mbuf)) != sizeof(mbuf)) { |
writeError(); |
} |
} |
|
|
int getArchive(void) { |
unsigned int mbuf; |
|
af = open(arnam, O_RDONLY); |
if (af < 0) { |
return 1; |
} |
if (read(af, &mbuf, sizeof(mbuf)) != sizeof(mbuf) || |
read4FromEco((unsigned char *) &mbuf) != AR_MAGIC) { |
fprintf(stderr, "ar: %s not in archive format\n", arnam); |
done(1); |
} |
return 0; |
} |
|
|
void getQuick(void) { |
unsigned int mbuf; |
|
qf = open(arnam, O_RDWR); |
if (qf < 0) { |
if (!flg['c' - 'a']) { |
fprintf(stderr, "ar: creating %s\n", arnam); |
} |
close(creat(arnam, 0666)); |
qf = open(arnam, O_RDWR); |
if (qf < 0) { |
fprintf(stderr, "ar: cannot create %s\n", arnam); |
done(1); |
} |
write4ToEco((unsigned char *) &mbuf, AR_MAGIC); |
if (write(qf, &mbuf, sizeof(mbuf)) != sizeof(mbuf)) { |
writeError(); |
} |
} else |
if (read(qf, &mbuf, sizeof(mbuf)) != sizeof(mbuf) || |
read4FromEco((unsigned char *) &mbuf) != AR_MAGIC) { |
fprintf(stderr, "ar: %s not in archive format\n", arnam); |
done(1); |
} |
} |
|
|
int getMember(void) { |
int i; |
|
i = read(af, &arbuf, sizeof(arbuf)); |
if (i != sizeof(arbuf)) { |
if (tf1nam != NULL) { |
i = tf0; |
tf0 = tf1; |
tf1 = i; |
} |
return 1; |
} |
conv4FromEcoToNative((unsigned char *) &arbuf.date); |
conv4FromEcoToNative((unsigned char *) &arbuf.uid); |
conv4FromEcoToNative((unsigned char *) &arbuf.gid); |
conv4FromEcoToNative((unsigned char *) &arbuf.mode); |
conv4FromEcoToNative((unsigned char *) &arbuf.size); |
for (i = 0; i < MAX_NAME; i++) { |
name[i] = arbuf.name[i]; |
} |
file = name; |
return 0; |
} |
|
|
void copyFile(int fi, int fo, int flags) { |
int pe; |
int icount, ocount; |
int pad; |
|
if (flags & HEAD) { |
conv4FromNativeToEco((unsigned char *) &arbuf.date); |
conv4FromNativeToEco((unsigned char *) &arbuf.uid); |
conv4FromNativeToEco((unsigned char *) &arbuf.gid); |
conv4FromNativeToEco((unsigned char *) &arbuf.mode); |
conv4FromNativeToEco((unsigned char *) &arbuf.size); |
if (write(fo, &arbuf, sizeof(arbuf)) != sizeof(arbuf)) { |
writeError(); |
} |
conv4FromEcoToNative((unsigned char *) &arbuf.date); |
conv4FromEcoToNative((unsigned char *) &arbuf.uid); |
conv4FromEcoToNative((unsigned char *) &arbuf.gid); |
conv4FromEcoToNative((unsigned char *) &arbuf.mode); |
conv4FromEcoToNative((unsigned char *) &arbuf.size); |
} |
pe = 0; |
while (arbuf.size > 0) { |
icount = ocount = BUFSIZE; |
if (arbuf.size < icount) { |
icount = ocount = arbuf.size; |
pad = -icount & 0x03; |
if (flags & IODD) { |
icount += pad; |
} |
if (flags & OODD) { |
ocount += pad; |
} |
} |
if (read(fi, buf, icount) != icount) { |
pe++; |
} |
if ((flags & SKIP) == 0) { |
if (write(fo, buf, ocount) != ocount) { |
writeError(); |
} |
} |
arbuf.size -= BUFSIZE; |
} |
if (pe != 0) { |
phaseError(); |
} |
} |
|
|
void moveFile(int f) { |
char *cp; |
int i; |
|
cp = trim(file); |
for (i = 0; i < MAX_NAME; i++) { |
if ((arbuf.name[i] = *cp) != '\0') { |
cp++; |
} |
} |
arbuf.size = stbuf.st_size; |
arbuf.date = stbuf.st_mtime; |
arbuf.uid = stbuf.st_uid; |
arbuf.gid = stbuf.st_gid; |
arbuf.mode = stbuf.st_mode; |
copyFile(f, tf0, OODD | HEAD); |
close(f); |
} |
|
|
void install(void) { |
int i; |
|
for (i = 0; signums[i] != 0; i++) { |
signal(signums[i], SIG_IGN); |
} |
if (af < 0) { |
if (!flg['c' - 'a']) { |
fprintf(stderr, "ar: creating %s\n", arnam); |
} |
} |
close(af); |
af = creat(arnam, 0666); |
if (af < 0) { |
fprintf(stderr, "ar: cannot create %s\n", arnam); |
done(1); |
} |
if (tf0nam != NULL) { |
lseek(tf0, 0, SEEK_SET); |
while ((i = read(tf0, buf, BUFSIZE)) > 0) { |
if (write(af, buf, i) != i) { |
writeError(); |
} |
} |
} |
if (tf2nam != NULL) { |
lseek(tf2, 0, SEEK_SET); |
while ((i = read(tf2, buf, BUFSIZE)) > 0) { |
if (write(af, buf, i) != i) { |
writeError(); |
} |
} |
} |
if (tf1nam != NULL) { |
lseek(tf1, 0, SEEK_SET); |
while ((i = read(tf1, buf, BUFSIZE)) > 0) { |
if (write(af, buf, i) != i) { |
writeError(); |
} |
} |
} |
} |
|
|
void cleanup(void) { |
int i; |
int f; |
|
for (i = 0; i < namc; i++) { |
file = namv[i]; |
if (file == NULL) { |
continue; |
} |
namv[i] = NULL; |
mesg('a'); |
f = stats(); |
if (f < 0) { |
fprintf(stderr, "ar: cannot open %s\n", file); |
continue; |
} |
moveFile(f); |
} |
} |
|
|
/**************************************************************/ |
|
|
void dCmd(void) { |
init(); |
if (getArchive()) { |
noArchive(); |
} |
while (!getMember()) { |
if (match()) { |
mesg('d'); |
copyFile(af, -1, IODD | SKIP); |
continue; |
} |
mesg('c'); |
copyFile(af, tf0, IODD | OODD | HEAD); |
} |
install(); |
} |
|
|
void rCmd(void) { |
int f; |
|
init(); |
getArchive(); |
while (!getMember()) { |
baMatch(); |
if (namc == 0 || match()) { |
f = stats(); |
if (f < 0) { |
if (namc != 0) { |
fprintf(stderr, "ar: cannot open %s\n", file); |
} |
goto cp; |
} |
if (flg['u' - 'a']) { |
if (stbuf.st_mtime <= arbuf.date) { |
close(f); |
goto cp; |
} |
} |
mesg('r'); |
copyFile(af, -1, IODD | SKIP); |
moveFile(f); |
continue; |
} |
cp: |
mesg('c'); |
copyFile(af, tf0, IODD | OODD | HEAD); |
} |
cleanup(); |
install(); |
} |
|
|
void qCmd(void) { |
int i; |
int f; |
|
if (flg['a' - 'a'] || flg['b' - 'a']) { |
fprintf(stderr, "ar: [ab] not allowed with -q\n"); |
done(1); |
} |
getQuick(); |
for (i = 0; signums[i] != 0; i++) { |
signal(signums[i], SIG_IGN); |
} |
lseek(qf, 0, SEEK_END); |
for (i = 0; i < namc; i++) { |
file = namv[i]; |
if (file == NULL) { |
continue; |
} |
namv[i] = NULL; |
mesg('q'); |
f = stats(); |
if (f < 0) { |
fprintf(stderr, "ar: cannot open %s\n", file); |
continue; |
} |
tf0 = qf; |
moveFile(f); |
qf = tf0; |
} |
} |
|
|
void tCmd(void) { |
if (getArchive()) { |
noArchive(); |
} |
while (!getMember()) { |
if (namc == 0 || match()) { |
if (flg['v' - 'a']) { |
showAttributes(); |
} |
printf("%s\n", trim(file)); |
} |
copyFile(af, -1, IODD | SKIP); |
} |
} |
|
|
void pCmd(void) { |
if (getArchive()) { |
noArchive(); |
} |
while (!getMember()) { |
if (namc == 0 || match()) { |
if (flg['v' - 'a']) { |
printf("\n<%s>\n\n", file); |
fflush(stdout); |
} |
copyFile(af, 1, IODD); |
continue; |
} |
copyFile(af, -1, IODD | SKIP); |
} |
} |
|
|
void mCmd(void) { |
init(); |
if (getArchive()) { |
noArchive(); |
} |
tf2nam = mktemp(tmp2nam); |
close(creat(tf2nam, 0600)); |
tf2 = open(tf2nam, O_RDWR); |
if (tf2 < 0) { |
fprintf(stderr, "ar: cannot create third temp file\n"); |
done(1); |
} |
while (!getMember()) { |
baMatch(); |
if (match()) { |
mesg('m'); |
copyFile(af, tf2, IODD | OODD | HEAD); |
continue; |
} |
mesg('c'); |
copyFile(af, tf0, IODD | OODD | HEAD); |
} |
install(); |
} |
|
|
void xCmd(void) { |
int f; |
|
if (getArchive()) { |
noArchive(); |
} |
while (!getMember()) { |
if (namc == 0 || match()) { |
f = creat(file, arbuf.mode & 0777); |
if (f < 0) { |
fprintf(stderr, "ar: cannot create %s\n", file); |
goto sk; |
} |
mesg('x'); |
copyFile(af, f, IODD); |
close(f); |
continue; |
} |
sk: |
mesg('c'); |
copyFile(af, -1, IODD | SKIP); |
if (namc > 0 && !moreFiles()) { |
done(0); |
} |
} |
} |
|
|
/**************************************************************/ |
|
/* specialized r command for updating symbols */ |
|
|
int exec_rCmd(int create, char *args[]) { |
int i; |
int res; |
|
/* reset all global variables */ |
comfun = NULL; |
for (i = 0; i < 26; i++) { |
flg[i] = 0; |
} |
arnam = NULL; |
af = 0; |
namv = NULL; |
namc = 0; |
baState = 0; |
posName = NULL; |
for (i = 0; i < 20; i++) { |
tmp0nam[i] = '\0'; |
tmp1nam[i] = '\0'; |
tmp2nam[i] = '\0'; |
} |
tf0nam = NULL; |
tf1nam = NULL; |
tf2nam = NULL; |
tf0 = 0; |
tf1 = 0; |
tf2 = 0; |
qf = 0; |
file = NULL; |
for (i = 0; i < MAX_NAME; i++) { |
name[i] = '\0'; |
} |
/* prepare arguments, call r command, cleanup */ |
comfun = rCmd; |
flg['l' - 'a'] = 1; |
strcpy(tmp0nam, "v0XXXXXX"); |
strcpy(tmp1nam, "v1XXXXXX"); |
strcpy(tmp2nam, "v2XXXXXX"); |
if (create) { |
/* ar -rlb firstName archive TEMP_NAME */ |
flg['b' - 'a'] = 1; |
baState = 1; |
posName = trim(args[0]); |
arnam = args[1]; |
namv = &args[2]; |
namc = 1; |
} else { |
/* ar -rl archive TEMP_NAME */ |
arnam = args[0]; |
namv = &args[1]; |
namc = 1; |
} |
(*comfun)(); |
res = notFound(); |
unlinkTempFiles(); |
return res; |
} |
|
|
/**************************************************************/ |
|
|
void usage(void) { |
printf("usage: ar -[%s][%s] archive files ...\n", com, opt); |
done(1); |
} |
|
|
void setcom(void (*fun)(void)) { |
if (comfun != NULL) { |
fprintf(stderr, "ar: only one of [%s] allowed\n", com); |
done(1); |
} |
comfun = fun; |
} |
|
|
int cmdCanChangeSymbols(void) { |
return comfun == dCmd || |
comfun == rCmd || |
comfun == mCmd; |
} |
|
|
int main(int argc, char *argv[]) { |
int i; |
char *cp; |
int res; |
|
for (i = 0; signums[i] != 0; i++) { |
if (signal(signums[i], SIG_IGN) != SIG_IGN) { |
signal(signums[i], sigDone); |
} |
} |
strcpy(tmp0nam, "/tmp/v0XXXXXX"); |
strcpy(tmp1nam, "/tmp/v1XXXXXX"); |
strcpy(tmp2nam, "/tmp/v2XXXXXX"); |
if (argc < 3 || *argv[1] != '-') { |
usage(); |
} |
for (cp = argv[1] + 1; *cp != '\0'; cp++) { |
switch (*cp) { |
case 'd': |
setcom(dCmd); |
break; |
case 'r': |
setcom(rCmd); |
break; |
case 'q': |
setcom(qCmd); |
break; |
case 't': |
setcom(tCmd); |
break; |
case 'p': |
setcom(pCmd); |
break; |
case 'm': |
setcom(mCmd); |
break; |
case 'x': |
setcom(xCmd); |
break; |
case 'v': |
case 'u': |
case 'a': |
case 'b': |
case 'c': |
case 'l': |
case 's': |
flg[*cp - 'a'] = 1; |
break; |
default: |
fprintf(stderr, "ar: bad option '%c'\n", *cp); |
done(1); |
} |
} |
if (flg['l' - 'a']) { |
strcpy(tmp0nam, "v0XXXXXX"); |
strcpy(tmp1nam, "v1XXXXXX"); |
strcpy(tmp2nam, "v2XXXXXX"); |
} |
if (flg['a' - 'a'] || flg['b' - 'a']) { |
baState = 1; |
posName = trim(argv[2]); |
argv++; |
argc--; |
if (argc < 3) { |
usage(); |
} |
} |
arnam = argv[2]; |
namv = argv + 3; |
namc = argc - 3; |
if (comfun == NULL && !flg['s' - 'a']) { |
fprintf(stderr, "ar: one of [%ss] must be specified\n", com); |
done(1); |
} |
res = 0; |
if (comfun != NULL) { |
(*comfun)(); |
res = notFound(); |
unlinkTempFiles(); |
if (res != 0) { |
return res; |
} |
} |
if (flg['s' - 'a'] || |
(cmdCanChangeSymbols() && hasSymbols(arnam))) { |
res = updateSymbols(arnam, flg['v' - 'a']); |
} |
return res; |
} |
/binutils/ar/endian.h
0,0 → 1,16
/* |
* endian.h -- endianness conversions |
*/ |
|
|
#ifndef _ENDIAN_H_ |
#define _ENDIAN_H_ |
|
|
unsigned int read4FromEco(unsigned char *p); |
void write4ToEco(unsigned char *p, unsigned int data); |
void conv4FromEcoToNative(unsigned char *p); |
void conv4FromNativeToEco(unsigned char *p); |
|
|
#endif /* _ENDIAN_H_ */ |
/binutils/ar/ranlib.c
0,0 → 1,367
/* |
* ranlib.c -- archive index generator |
*/ |
|
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <unistd.h> |
#include <time.h> |
#include <fcntl.h> |
|
#include "endian.h" |
#include "ranlib.h" |
#include "../include/ar.h" |
#include "../include/a.out.h" |
|
|
#define TEMP_NAME "__.SYMDEF" |
|
#define STRING_SIZE_INIT 1024 |
#define STRING_SIZE_GROW 2 |
|
#define MAX_SYM_ENTRIES 1000 |
|
#define MSB ((unsigned int) 1 << (sizeof(unsigned int) * 8 - 1)) |
|
|
typedef struct { |
unsigned int name; /* name of symbol (as offset into string space) */ |
off_t position; /* position of member which defines the symbol */ |
/* (as file offset to the member's ArHeader) */ |
} Entry; |
|
|
FILE *fi; |
FILE *fo; |
|
off_t nxtOff; /* file offset to next member */ |
off_t curOff; |
|
Entry table[MAX_SYM_ENTRIES]; |
int numEntries; |
|
int createIndex; |
char firstName[MAX_NAME]; |
|
ArHeader arhdr; |
ExecHeader exhdr; |
|
|
/**************************************************************/ |
|
|
char *stringArea = NULL; |
unsigned int sizeAllocated = 0; |
unsigned int sizeUsed = 0; |
|
|
unsigned int getStringPos(void) { |
return sizeUsed; |
} |
|
|
void storeCharacter(char c) { |
unsigned int newSize; |
char *newArea; |
|
if (sizeUsed + 1 > sizeAllocated) { |
if (sizeAllocated == 0) { |
newSize = STRING_SIZE_INIT; |
} else { |
newSize = STRING_SIZE_GROW * sizeAllocated; |
} |
newArea = malloc(newSize); |
if (newArea == NULL) { |
fprintf(stderr, "ar: cannot allocate string area\n"); |
exit(1); |
} |
if (stringArea != NULL) { |
memcpy(newArea, stringArea, sizeUsed); |
free(stringArea); |
} |
stringArea = newArea; |
sizeAllocated = newSize; |
} |
stringArea[sizeUsed++] = c; |
} |
|
|
/**************************************************************/ |
|
|
int nextMember(void) { |
int pad; |
|
curOff = nxtOff; |
fseek(fi, nxtOff, SEEK_SET); |
if (fread(&arhdr, sizeof(arhdr), 1, fi) != 1) { |
return 0; |
} |
conv4FromEcoToNative((unsigned char *) &arhdr.date); |
conv4FromEcoToNative((unsigned char *) &arhdr.uid); |
conv4FromEcoToNative((unsigned char *) &arhdr.gid); |
conv4FromEcoToNative((unsigned char *) &arhdr.mode); |
conv4FromEcoToNative((unsigned char *) &arhdr.size); |
pad = -arhdr.size & 0x03; |
arhdr.size += pad; |
nxtOff = ftell(fi) + arhdr.size; |
return 1; |
} |
|
|
void addSymbol(unsigned int nameOffset) { |
off_t curPos; |
int c; |
|
if (numEntries >= MAX_SYM_ENTRIES) { |
fprintf(stderr, "ar: symbol table overflow\n"); |
exit(1); |
} |
table[numEntries].name = getStringPos(); |
table[numEntries].position = curOff; |
numEntries++; |
curPos = ftell(fi); |
fseek(fi, curOff + sizeof(arhdr) + nameOffset, SEEK_SET); |
do { |
c = fgetc(fi); |
storeCharacter(c); |
} while (c != 0) ; |
fseek(fi, curPos, SEEK_SET); |
} |
|
|
void fixSize(void) { |
off_t deltaOff; |
int pad; |
int i; |
|
deltaOff = sizeof(arhdr) + sizeof(int) + |
numEntries * sizeof(Entry) + getStringPos(); |
pad = -deltaOff & 0x03; |
deltaOff += pad; |
nxtOff = sizeof(unsigned int); |
nextMember(); |
if(strncmp(arhdr.name, TEMP_NAME, MAX_NAME) == 0) { |
/* there is an index already present */ |
createIndex = 0; |
deltaOff -= sizeof(arhdr) + arhdr.size; |
} else { |
/* no index yet present, create new one */ |
createIndex = 1; |
strncpy(firstName, arhdr.name, MAX_NAME); |
} |
for (i = 0; i < numEntries; i++) { |
table[i].position += deltaOff; |
} |
} |
|
|
/**************************************************************/ |
|
|
void showSymdefs(char *symdefs) { |
FILE *in; |
int numSymbols; |
int i; |
Entry e; |
off_t curPos; |
off_t pos; |
int c; |
|
in = fopen(symdefs, "r"); |
if (in == NULL) { |
printf("error: cannot open symdef file '%s'\n", symdefs); |
exit(1); |
} |
if (fread(&numSymbols, sizeof(int), 1, in) != 1) { |
printf("cannot read symdef file\n"); |
exit(1); |
} |
conv4FromEcoToNative((unsigned char *) &numSymbols); |
printf("%d symbols\n", numSymbols); |
for (i = 0; i < numSymbols; i++) { |
if (fread(&e, sizeof(e), 1, in) != 1) { |
printf("cannot read symdef file\n"); |
exit(1); |
} |
conv4FromEcoToNative((unsigned char *) &e.name); |
conv4FromEcoToNative((unsigned char *) &e.position); |
printf("%4d: name = 0x%08X, position = 0x%08lX, string = '", |
i, e.name, e.position); |
curPos = ftell(in); |
pos = sizeof(int) + numSymbols * sizeof(Entry) + e.name; |
fseek(in, pos, SEEK_SET); |
while (1) { |
c = fgetc(in); |
if (c == EOF) { |
printf("\nerror: unexpected end of file\n"); |
exit(1); |
} |
if (c == 0) { |
break; |
} |
printf("%c", c); |
} |
printf("'\n"); |
fseek(in, curPos, SEEK_SET); |
} |
fclose(in); |
} |
|
|
/**************************************************************/ |
|
|
int hasSymbols(char *archive) { |
unsigned int arMagic; |
int res; |
|
fi = fopen(archive, "r"); |
if (fi == NULL) { |
return 0; |
} |
nxtOff = sizeof(unsigned int); |
if (fread(&arMagic, sizeof(arMagic), 1, fi) != 1 || |
read4FromEco((unsigned char *) &arMagic) != AR_MAGIC) { |
fclose(fi); |
return 0; |
} |
fseek(fi, 0, SEEK_SET); |
if (nextMember() == 0) { |
fclose(fi); |
return 0; |
} |
fclose(fi); |
res = (strncmp(arhdr.name, TEMP_NAME, MAX_NAME) == 0); |
return res; |
} |
|
|
int updateSymbols(char *archive, int verbose) { |
unsigned int arMagic; |
unsigned int skip; |
int numSymbols; |
unsigned int stringStart; |
SymbolRecord symbol; |
int i; |
char *args[3]; |
int res; |
|
if (verbose) { |
printf("ar: updating symbols in %s\n", archive); |
} |
fi = fopen(archive, "r"); |
if (fi == NULL) { |
fprintf(stderr, "ar: cannot re-open %s\n", archive); |
return 1; |
} |
nxtOff = sizeof(unsigned int); |
if (fread(&arMagic, sizeof(arMagic), 1, fi) != 1 || |
read4FromEco((unsigned char *) &arMagic) != AR_MAGIC) { |
fprintf(stderr, "ar: %s not in archive format\n", archive); |
fclose(fi); |
return 1; |
} |
fseek(fi, 0, SEEK_SET); |
numEntries = 0; |
if (nextMember() == 0) { |
fclose(fi); |
return 0; |
} |
/* iterate over archive members */ |
do { |
if (fread(&exhdr, sizeof(exhdr), 1, fi) != 1 || |
read4FromEco((unsigned char *) &exhdr.magic) != EXEC_MAGIC) { |
/* archive member not in proper format - skip */ |
continue; |
} |
conv4FromEcoToNative((unsigned char *) &exhdr.magic); |
conv4FromEcoToNative((unsigned char *) &exhdr.csize); |
conv4FromEcoToNative((unsigned char *) &exhdr.dsize); |
conv4FromEcoToNative((unsigned char *) &exhdr.bsize); |
conv4FromEcoToNative((unsigned char *) &exhdr.crsize); |
conv4FromEcoToNative((unsigned char *) &exhdr.drsize); |
conv4FromEcoToNative((unsigned char *) &exhdr.symsize); |
conv4FromEcoToNative((unsigned char *) &exhdr.strsize); |
skip = exhdr.csize + exhdr.dsize + exhdr.crsize + exhdr.drsize; |
fseek(fi, skip, SEEK_CUR); |
numSymbols = exhdr.symsize / sizeof(SymbolRecord); |
if (numSymbols == 0) { |
fprintf(stderr, |
"ar: symbol table of %s is empty\n", |
arhdr.name); |
continue; |
} |
stringStart = sizeof(exhdr) + skip + exhdr.symsize; |
/* iterate over symbols */ |
while (--numSymbols >= 0) { |
if (fread(&symbol, sizeof(symbol), 1, fi) != 1) { |
fprintf(stderr, "ar: cannot read archive\n"); |
break; |
} |
conv4FromEcoToNative((unsigned char *) &symbol.name); |
conv4FromEcoToNative((unsigned char *) &symbol.type); |
conv4FromEcoToNative((unsigned char *) &symbol.value); |
if ((symbol.type & MSB) == 0) { |
/* this is an exported symbol */ |
addSymbol(stringStart + symbol.name); |
} |
} |
} while (nextMember() != 0) ; |
fixSize(); |
fclose(fi); |
fo = fopen(TEMP_NAME, "w"); |
if (fo == NULL) { |
fprintf(stderr, "ar: can't create temporary file\n"); |
return 1; |
} |
conv4FromNativeToEco((unsigned char *) &numEntries); |
if (fwrite(&numEntries, sizeof(numEntries), 1, fo) != 1) { |
fprintf(stderr, "ar: can't write temporary file\n"); |
fclose(fo); |
unlink(TEMP_NAME); |
return 1; |
} |
conv4FromEcoToNative((unsigned char *) &numEntries); |
for (i = 0; i < numEntries; i++) { |
conv4FromNativeToEco((unsigned char *) &table[i].name); |
conv4FromNativeToEco((unsigned char *) &table[i].position); |
} |
if (fwrite(table, sizeof(Entry), numEntries, fo) != numEntries) { |
fprintf(stderr, "ar: can't write temporary file\n"); |
fclose(fo); |
unlink(TEMP_NAME); |
return 1; |
} |
for (i = 0; i < numEntries; i++) { |
conv4FromEcoToNative((unsigned char *) &table[i].name); |
conv4FromEcoToNative((unsigned char *) &table[i].position); |
} |
if (fwrite(stringArea, 1, getStringPos(), fo) != getStringPos()) { |
fprintf(stderr, "ar: can't write temporary file\n"); |
fclose(fo); |
unlink(TEMP_NAME); |
return 1; |
} |
fclose(fo); |
if (verbose) { |
showSymdefs(TEMP_NAME); |
} |
if (createIndex) { |
/* ar -rlb firstName archive TEMP_NAME */ |
args[0] = firstName; |
args[1] = archive; |
args[2] = TEMP_NAME; |
res = exec_rCmd(1, args); |
} else { |
/* ar -rl archive TEMP_NAME */ |
args[0] = archive; |
args[1] = TEMP_NAME; |
args[2] = NULL; |
res = exec_rCmd(0, args); |
} |
unlink(TEMP_NAME); |
return res; |
} |
/binutils/ar/ranlib.h
0,0 → 1,16
/* |
* ranlib.c - archive index generator |
*/ |
|
|
#ifndef _RANLIB_H_ |
#define _RANLIB_H_ |
|
|
int hasSymbols(char *archive); |
int updateSymbols(char *archive, int verbose); |
|
int exec_rCmd(int create, char *args[]); |
|
|
#endif /* _RANLIB_H_ */ |
/binutils/ar/Makefile
0,0 → 1,36
# |
# Makefile for ECO32 archiver |
# |
|
BUILD = ../../build |
|
CC = gcc -m32 |
CFLAGS = -g -Wall |
LDFLAGS = -g |
LDLIBS = -lm |
|
SRCS = ar.c ranlib.c endian.c |
OBJS = $(patsubst %.c,%.o,$(SRCS)) |
BIN = ar |
|
.PHONY: all install clean |
|
all: $(BIN) |
|
install: $(BIN) |
mkdir -p $(BUILD)/bin |
cp $(BIN) $(BUILD)/bin |
|
$(BIN): $(OBJS) |
$(CC) $(LDFLAGS) -o $(BIN) $(OBJS) $(LDLIBS) |
|
%.o: %.c |
$(CC) $(CFLAGS) -o $@ -c $< |
|
depend.mak: |
$(CC) -MM -MG $(CFLAGS) $(SRCS) > depend.mak |
|
-include depend.mak |
|
clean: |
rm -f *~ $(OBJS) $(BIN) depend.mak |
/binutils/as/as.c
0,0 → 1,2175
/* |
* as.c -- ECO32 assembler |
*/ |
|
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <stdarg.h> |
#include <ctype.h> |
#include <unistd.h> |
|
#include "../include/a.out.h" |
|
|
/**************************************************************/ |
|
|
#define NUM_REGS 32 |
#define AUX_REG 1 |
|
#define LINE_SIZE 200 |
|
#define TOK_EOL 0 |
#define TOK_LABEL 1 |
#define TOK_IDENT 2 |
#define TOK_STRING 3 |
#define TOK_NUMBER 4 |
#define TOK_REGISTER 5 |
#define TOK_PLUS 6 |
#define TOK_MINUS 7 |
#define TOK_STAR 8 |
#define TOK_SLASH 9 |
#define TOK_PERCENT 10 |
#define TOK_LSHIFT 11 |
#define TOK_RSHIFT 12 |
#define TOK_LPAREN 13 |
#define TOK_RPAREN 14 |
#define TOK_COMMA 15 |
#define TOK_TILDE 16 |
#define TOK_AMPER 17 |
#define TOK_BAR 18 |
#define TOK_CARET 19 |
|
#define STATUS_UNKNOWN 0 /* symbol is not yet defined */ |
#define STATUS_DEFINED 1 /* symbol is defined */ |
#define STATUS_GLOBREF 2 /* local entry refers to a global one */ |
|
#define GLOBAL_TABLE 0 /* global symbol table identifier */ |
#define LOCAL_TABLE 1 /* local symbol table identifier */ |
|
#define MSB ((unsigned int) 1 << (sizeof(unsigned int) * 8 - 1)) |
|
|
/**************************************************************/ |
|
|
#define OP_ADD 0x00 |
#define OP_ADDI 0x01 |
#define OP_SUB 0x02 |
#define OP_SUBI 0x03 |
|
#define OP_MUL 0x04 |
#define OP_MULI 0x05 |
#define OP_MULU 0x06 |
#define OP_MULUI 0x07 |
#define OP_DIV 0x08 |
#define OP_DIVI 0x09 |
#define OP_DIVU 0x0A |
#define OP_DIVUI 0x0B |
#define OP_REM 0x0C |
#define OP_REMI 0x0D |
#define OP_REMU 0x0E |
#define OP_REMUI 0x0F |
|
#define OP_AND 0x10 |
#define OP_ANDI 0x11 |
#define OP_OR 0x12 |
#define OP_ORI 0x13 |
#define OP_XOR 0x14 |
#define OP_XORI 0x15 |
#define OP_XNOR 0x16 |
#define OP_XNORI 0x17 |
|
#define OP_SLL 0x18 |
#define OP_SLLI 0x19 |
#define OP_SLR 0x1A |
#define OP_SLRI 0x1B |
#define OP_SAR 0x1C |
#define OP_SARI 0x1D |
|
#define OP_LDHI 0x1F |
|
#define OP_BEQ 0x20 |
#define OP_BNE 0x21 |
#define OP_BLE 0x22 |
#define OP_BLEU 0x23 |
#define OP_BLT 0x24 |
#define OP_BLTU 0x25 |
#define OP_BGE 0x26 |
#define OP_BGEU 0x27 |
#define OP_BGT 0x28 |
#define OP_BGTU 0x29 |
|
#define OP_J 0x2A |
#define OP_JR 0x2B |
#define OP_JAL 0x2C |
#define OP_JALR 0x2D |
|
#define OP_TRAP 0x2E |
#define OP_RFX 0x2F |
|
#define OP_LDW 0x30 |
#define OP_LDH 0x31 |
#define OP_LDHU 0x32 |
#define OP_LDB 0x33 |
#define OP_LDBU 0x34 |
|
#define OP_STW 0x35 |
#define OP_STH 0x36 |
#define OP_STB 0x37 |
|
#define OP_MVFS 0x38 |
#define OP_MVTS 0x39 |
#define OP_TBS 0x3A |
#define OP_TBWR 0x3B |
#define OP_TBRI 0x3C |
#define OP_TBWI 0x3D |
|
|
/**************************************************************/ |
|
|
int debugToken = 0; |
int debugCode = 0; |
int debugFixup = 0; |
|
char codeName[L_tmpnam]; |
char dataName[L_tmpnam]; |
char *outName = NULL; |
char *inName = NULL; |
|
FILE *codeFile = NULL; |
FILE *dataFile = NULL; |
FILE *outFile = NULL; |
FILE *inFile = NULL; |
|
char line[LINE_SIZE]; |
char *lineptr; |
int lineno; |
|
int token; |
int tokenvalNumber; |
char tokenvalString[LINE_SIZE]; |
|
int allowSyn = 1; |
int currSeg = SEGMENT_CODE; |
unsigned int segPtr[4] = { 0, 0, 0, 0 }; |
char *segName[4] = { "ABS", "CODE", "DATA", "BSS" }; |
char *methodName[5] = { "H16", "L16", "R16", "R26", "W32" }; |
|
|
typedef struct fixup { |
int segment; /* in which segment */ |
unsigned int offset; /* at which offset */ |
int method; /* what kind of coding method is to be used */ |
int value; /* known part of value */ |
int base; /* segment which this ref is relative to */ |
/* valid only when used for relocation */ |
struct fixup *next; /* next fixup */ |
} Fixup; |
|
|
typedef struct symbol { |
char *name; /* name of symbol */ |
int status; /* status of symbol */ |
int segment; /* the symbol's segment */ |
int value; /* the symbol's value */ |
Fixup *fixups; /* list of locations to fix */ |
struct symbol *globref; /* set if this local refers to a global */ |
struct symbol *left; /* left son in binary search tree */ |
struct symbol *right; /* right son in binary search tree */ |
int skip; /* this symbol is not defined here nor is */ |
/* it used here: don't write to object file */ |
} Symbol; |
|
|
/**************************************************************/ |
|
|
void error(char *fmt, ...) { |
va_list ap; |
|
va_start(ap, fmt); |
fprintf(stderr, "Error: "); |
vfprintf(stderr, fmt, ap); |
fprintf(stderr, "\n"); |
va_end(ap); |
if (codeFile != NULL) { |
fclose(codeFile); |
codeFile = NULL; |
} |
if (dataFile != NULL) { |
fclose(dataFile); |
dataFile = NULL; |
} |
if (outFile != NULL) { |
fclose(outFile); |
outFile = NULL; |
} |
if (inFile != NULL) { |
fclose(inFile); |
inFile = NULL; |
} |
if (codeName != NULL) { |
unlink(codeName); |
} |
if (dataName != NULL) { |
unlink(dataName); |
} |
if (outName != NULL) { |
unlink(outName); |
} |
exit(1); |
} |
|
|
void *allocateMemory(unsigned int size) { |
void *p; |
|
p = malloc(size); |
if (p == NULL) { |
error("out of memory"); |
} |
return p; |
} |
|
|
void freeMemory(void *p) { |
free(p); |
} |
|
|
/**************************************************************/ |
|
|
int getNextToken(void) { |
char *p; |
int base; |
int digit; |
|
while (*lineptr == ' ' || *lineptr == '\t') { |
lineptr++; |
} |
if (*lineptr == '\n' || *lineptr == '\0' || *lineptr == ';') { |
return TOK_EOL; |
} |
if (isalpha((int) *lineptr) || *lineptr == '_' || *lineptr == '.') { |
p = tokenvalString; |
while (isalnum((int) *lineptr) || *lineptr == '_' || *lineptr == '.') { |
*p++ = *lineptr++; |
} |
*p = '\0'; |
if (*lineptr == ':') { |
lineptr++; |
return TOK_LABEL; |
} else { |
return TOK_IDENT; |
} |
} |
if (isdigit((int) *lineptr)) { |
base = 10; |
tokenvalNumber = 0; |
if (*lineptr == '0') { |
lineptr++; |
if (*lineptr == 'x' || *lineptr == 'X') { |
base = 16; |
lineptr++; |
} else |
if (isdigit((int) *lineptr)) { |
base = 8; |
} else { |
return TOK_NUMBER; |
} |
} |
while (isxdigit((int) *lineptr)) { |
digit = *lineptr++ - '0'; |
if (digit >= 'A' - '0') { |
if (digit >= 'a' - '0') { |
digit += '0' - 'a' + 10; |
} else { |
digit += '0' - 'A' + 10; |
} |
} |
if (digit >= base) { |
error("illegal digit value %d in line %d", digit, lineno); |
} |
tokenvalNumber *= base; |
tokenvalNumber += digit; |
} |
return TOK_NUMBER; |
} |
if (*lineptr == '\'') { |
lineptr++; |
if (!isprint((int) *lineptr)) { |
error("cannot quote character 0x%02X in line %d", *lineptr, lineno); |
} |
tokenvalNumber = *lineptr; |
lineptr++; |
if (*lineptr != '\'') { |
error("unbalanced quote in line %d", lineno); |
} |
lineptr++; |
return TOK_NUMBER; |
} |
if (*lineptr == '\"') { |
lineptr++; |
p = tokenvalString; |
while (1) { |
if (*lineptr == '\n' || *lineptr == '\0') { |
error("unterminated string constant in line %d", lineno); |
} |
if (!isprint((int) *lineptr)) { |
error("string contains illegal character 0x%02X in line %d", |
*lineptr, lineno); |
} |
if (*lineptr == '\"') { |
break; |
} |
*p++ = *lineptr++; |
} |
lineptr++; |
*p = '\0'; |
return TOK_STRING; |
} |
if (*lineptr == '$') { |
lineptr++; |
if (!isdigit((int) *lineptr)) { |
error("register number expected after '$' in line %d", lineno); |
} |
tokenvalNumber = 0; |
while (isdigit((int) *lineptr)) { |
digit = *lineptr++ - '0'; |
tokenvalNumber *= 10; |
tokenvalNumber += digit; |
} |
if (tokenvalNumber < 0 || tokenvalNumber >= NUM_REGS) { |
error("illegal register number %d in line %d", tokenvalNumber, lineno); |
} |
return TOK_REGISTER; |
} |
if (*lineptr == '+') { |
lineptr++; |
return TOK_PLUS; |
} |
if (*lineptr == '-') { |
lineptr++; |
return TOK_MINUS; |
} |
if (*lineptr == '*') { |
lineptr++; |
return TOK_STAR; |
} |
if (*lineptr == '/') { |
lineptr++; |
return TOK_SLASH; |
} |
if (*lineptr == '%') { |
lineptr++; |
return TOK_PERCENT; |
} |
if (*lineptr == '<' && *(lineptr + 1) == '<') { |
lineptr += 2; |
return TOK_LSHIFT; |
} |
if (*lineptr == '>' && *(lineptr + 1) == '>') { |
lineptr += 2; |
return TOK_RSHIFT; |
} |
if (*lineptr == '(') { |
lineptr++; |
return TOK_LPAREN; |
} |
if (*lineptr == ')') { |
lineptr++; |
return TOK_RPAREN; |
} |
if (*lineptr == ',') { |
lineptr++; |
return TOK_COMMA; |
} |
if (*lineptr == '~') { |
lineptr++; |
return TOK_TILDE; |
} |
if (*lineptr == '&') { |
lineptr++; |
return TOK_AMPER; |
} |
if (*lineptr == '|') { |
lineptr++; |
return TOK_BAR; |
} |
if (*lineptr == '^') { |
lineptr++; |
return TOK_CARET; |
} |
error("illegal character 0x%02X in line %d", *lineptr, lineno); |
return 0; |
} |
|
|
void showToken(void) { |
printf("DEBUG: "); |
switch (token) { |
case TOK_EOL: |
printf("token = TOK_EOL\n"); |
break; |
case TOK_LABEL: |
printf("token = TOK_LABEL, value = %s\n", tokenvalString); |
break; |
case TOK_IDENT: |
printf("token = TOK_IDENT, value = %s\n", tokenvalString); |
break; |
case TOK_STRING: |
printf("token = TOK_STRING, value = %s\n", tokenvalString); |
break; |
case TOK_NUMBER: |
printf("token = TOK_NUMBER, value = 0x%x\n", tokenvalNumber); |
break; |
case TOK_REGISTER: |
printf("token = TOK_REGISTER, value = %d\n", tokenvalNumber); |
break; |
case TOK_PLUS: |
printf("token = TOK_PLUS\n"); |
break; |
case TOK_MINUS: |
printf("token = TOK_MINUS\n"); |
break; |
case TOK_STAR: |
printf("token = TOK_STAR\n"); |
break; |
case TOK_SLASH: |
printf("token = TOK_SLASH\n"); |
break; |
case TOK_PERCENT: |
printf("token = TOK_PERCENT\n"); |
break; |
case TOK_LSHIFT: |
printf("token = TOK_LSHIFT\n"); |
break; |
case TOK_RSHIFT: |
printf("token = TOK_RSHIFT\n"); |
break; |
case TOK_LPAREN: |
printf("token = TOK_LPAREN\n"); |
break; |
case TOK_RPAREN: |
printf("token = TOK_RPAREN\n"); |
break; |
case TOK_COMMA: |
printf("token = TOK_COMMA\n"); |
break; |
case TOK_TILDE: |
printf("token = TOK_TILDE\n"); |
break; |
case TOK_AMPER: |
printf("token = TOK_AMPER\n"); |
break; |
case TOK_BAR: |
printf("token = TOK_BAR\n"); |
break; |
case TOK_CARET: |
printf("token = TOK_CARET\n"); |
break; |
default: |
error("illegal token %d in showToken()", token); |
} |
} |
|
|
void getToken(void) { |
token = getNextToken(); |
if (debugToken) { |
showToken(); |
} |
} |
|
|
static char *tok2str[] = { |
"end-of-line", |
"label", |
"identifier", |
"string", |
"number", |
"register", |
"+", |
"-", |
"*", |
"/", |
"%", |
"<<", |
">>", |
"(", |
")", |
",", |
"~", |
"&", |
"|", |
"^" |
}; |
|
|
void expect(int expected) { |
if (token != expected) { |
error("'%s' expected, got '%s' in line %d", |
tok2str[expected], tok2str[token], lineno); |
} |
} |
|
|
/**************************************************************/ |
|
|
Fixup *fixupList = NULL; |
|
|
Fixup *newFixup(int segment, unsigned int offset, int method, int value) { |
Fixup *f; |
|
f = allocateMemory(sizeof(Fixup)); |
f->segment = segment; |
f->offset = offset; |
f->method = method; |
f->value = value; |
f->base = 0; |
f->next = NULL; |
return f; |
} |
|
|
void addFixup(Symbol *s, |
int segment, unsigned int offset, int method, int value) { |
Fixup *f; |
|
if (debugFixup) { |
printf("DEBUG: fixup (s:%s, o:%08X, m:%s, v:%08X) added to '%s'\n", |
segName[segment], offset, methodName[method], value, s->name); |
} |
f = newFixup(segment, offset, method, value); |
f->next = s->fixups; |
s->fixups = f; |
} |
|
|
/**************************************************************/ |
|
|
Symbol *globalTable = NULL; |
Symbol *localTable = NULL; |
|
|
Symbol *deref(Symbol *s) { |
if (s->status == STATUS_GLOBREF) { |
return s->globref; |
} else { |
return s; |
} |
} |
|
|
Symbol *newSymbol(char *name) { |
Symbol *p; |
|
p = allocateMemory(sizeof(Symbol)); |
p->name = allocateMemory(strlen(name) + 1); |
strcpy(p->name, name); |
p->status = STATUS_UNKNOWN; |
p->segment = 0; |
p->value = 0; |
p->fixups = NULL; |
p->globref = NULL; |
p->left = NULL; |
p->right = NULL; |
return p; |
} |
|
|
Symbol *lookupEnter(char *name, int whichTable) { |
Symbol *p, *q, *r; |
int cmp; |
|
if (whichTable == GLOBAL_TABLE) { |
p = globalTable; |
} else { |
p = localTable; |
} |
if (p == NULL) { |
r = newSymbol(name); |
if (whichTable == GLOBAL_TABLE) { |
globalTable = r; |
} else { |
localTable = r; |
} |
return r; |
} |
while (1) { |
q = p; |
cmp = strcmp(name, q->name); |
if (cmp == 0) { |
return q; |
} |
if (cmp < 0) { |
p = q->left; |
} else { |
p = q->right; |
} |
if (p == NULL) { |
r = newSymbol(name); |
if (cmp < 0) { |
q->left = r; |
} else { |
q->right = r; |
} |
return r; |
} |
} |
} |
|
|
static void linkSymbol(Symbol *s) { |
Fixup *f; |
|
if (s->status == STATUS_UNKNOWN) { |
error("undefined symbol '%s'", s->name); |
} |
if (s->status == STATUS_GLOBREF) { |
if (s->fixups != NULL) { |
error("local fixups detected with global symbol '%s'", s->name); |
} |
} else { |
if (debugFixup) { |
printf("DEBUG: link '%s' (s:%s, v:%08X)\n", |
s->name, segName[s->segment], s->value); |
} |
while (s->fixups != NULL) { |
/* get next fixup record */ |
f = s->fixups; |
s->fixups = f->next; |
/* add the symbol's value to the value in the record */ |
/* and remember the symbol's segment */ |
if (debugFixup) { |
printf(" (s:%s, o:%08X, m:%s, v:%08X --> %08X, b:%s)\n", |
segName[f->segment], f->offset, methodName[f->method], |
f->value, f->value + s->value, segName[s->segment]); |
} |
f->value += s->value; |
f->base = s->segment; |
/* transfer the record to the fixup list */ |
f->next = fixupList; |
fixupList = f; |
} |
} |
} |
|
|
static void linkTree(Symbol *s) { |
if (s == NULL) { |
return; |
} |
linkTree(s->left); |
linkSymbol(s); |
linkTree(s->right); |
freeMemory(s->name); |
freeMemory(s); |
} |
|
|
void linkLocals(void) { |
linkTree(localTable); |
localTable = NULL; |
fseek(codeFile, 0, SEEK_END); |
fseek(dataFile, 0, SEEK_END); |
} |
|
|
/**************************************************************/ |
|
|
void emitByte(unsigned int byte) { |
byte &= 0x000000FF; |
if (debugCode) { |
printf("DEBUG: byte @ segment = %s, offset = %08X", |
segName[currSeg], segPtr[currSeg]); |
printf(", value = %02X\n", byte); |
} |
switch (currSeg) { |
case SEGMENT_ABS: |
error("illegal segment in emitByte()"); |
break; |
case SEGMENT_CODE: |
fputc(byte, codeFile); |
break; |
case SEGMENT_DATA: |
fputc(byte, dataFile); |
break; |
case SEGMENT_BSS: |
break; |
} |
segPtr[currSeg] += 1; |
} |
|
|
void emitHalf(unsigned int half) { |
half &= 0x0000FFFF; |
if (debugCode) { |
printf("DEBUG: half @ segment = %s, offset = %08X", |
segName[currSeg], segPtr[currSeg]); |
printf(", value = %02X%02X\n", |
(half >> 8) & 0xFF, half & 0xFF); |
} |
switch (currSeg) { |
case SEGMENT_ABS: |
error("illegal segment in emitHalf()"); |
break; |
case SEGMENT_CODE: |
fputc((half >> 8) & 0xFF, codeFile); |
fputc(half & 0xFF, codeFile); |
break; |
case SEGMENT_DATA: |
fputc((half >> 8) & 0xFF, dataFile); |
fputc(half & 0xFF, dataFile); |
break; |
case SEGMENT_BSS: |
break; |
} |
segPtr[currSeg] += 2; |
} |
|
|
void emitWord(unsigned int word) { |
if (debugCode) { |
printf("DEBUG: word @ segment = %s, offset = %08X", |
segName[currSeg], segPtr[currSeg]); |
printf(", value = %02X%02X%02X%02X\n", |
(word >> 24) & 0xFF, (word >> 16) & 0xFF, |
(word >> 8) & 0xFF, word & 0xFF); |
} |
switch (currSeg) { |
case SEGMENT_ABS: |
error("illegal segment in emitWord()"); |
break; |
case SEGMENT_CODE: |
fputc((word >> 24) & 0xFF, codeFile); |
fputc((word >> 16) & 0xFF, codeFile); |
fputc((word >> 8) & 0xFF, codeFile); |
fputc(word & 0xFF, codeFile); |
break; |
case SEGMENT_DATA: |
fputc((word >> 24) & 0xFF, dataFile); |
fputc((word >> 16) & 0xFF, dataFile); |
fputc((word >> 8) & 0xFF, dataFile); |
fputc(word & 0xFF, dataFile); |
break; |
case SEGMENT_BSS: |
break; |
} |
segPtr[currSeg] += 4; |
} |
|
|
/**************************************************************/ |
|
|
typedef struct { |
int con; |
Symbol *sym; |
} Value; |
|
|
Value parseExpression(void); |
|
|
Value parsePrimaryExpression(void) { |
Value v; |
Symbol *s; |
|
if (token == TOK_NUMBER) { |
v.con = tokenvalNumber; |
v.sym = NULL; |
getToken(); |
} else |
if (token == TOK_IDENT) { |
s = deref(lookupEnter(tokenvalString, LOCAL_TABLE)); |
if (s->status == STATUS_DEFINED && s->segment == SEGMENT_ABS) { |
v.con = s->value; |
v.sym = NULL; |
} else { |
v.con = 0; |
v.sym = s; |
} |
getToken(); |
} else |
if (token == TOK_LPAREN) { |
getToken(); |
v = parseExpression(); |
expect(TOK_RPAREN); |
getToken(); |
} else { |
error("illegal primary expression, line %d", lineno); |
} |
return v; |
} |
|
|
Value parseUnaryExpression(void) { |
Value v; |
|
if (token == TOK_PLUS) { |
getToken(); |
v = parseUnaryExpression(); |
} else |
if (token == TOK_MINUS) { |
getToken(); |
v = parseUnaryExpression(); |
if (v.sym != NULL) { |
error("cannot negate symbol '%s' in line %d", v.sym->name, lineno); |
} |
v.con = -v.con; |
} else |
if (token == TOK_TILDE) { |
getToken(); |
v = parseUnaryExpression(); |
if (v.sym != NULL) { |
error("cannot complement symbol '%s' in line %d", v.sym->name, lineno); |
} |
v.con = ~v.con; |
} else { |
v = parsePrimaryExpression(); |
} |
return v; |
} |
|
|
Value parseMultiplicativeExpression(void) { |
Value v1, v2; |
|
v1 = parseUnaryExpression(); |
while (token == TOK_STAR || token == TOK_SLASH || token == TOK_PERCENT) { |
if (token == TOK_STAR) { |
getToken(); |
v2 = parseUnaryExpression(); |
if (v1.sym != NULL || v2.sym != NULL) { |
error("multiplication of symbols not supported, line %d", lineno); |
} |
v1.con *= v2.con; |
} else |
if (token == TOK_SLASH) { |
getToken(); |
v2 = parseUnaryExpression(); |
if (v1.sym != NULL || v2.sym != NULL) { |
error("division of symbols not supported, line %d", lineno); |
} |
if (v2.con == 0) { |
error("division by zero, line %d", lineno); |
} |
v1.con /= v2.con; |
} else |
if (token == TOK_PERCENT) { |
getToken(); |
v2 = parseUnaryExpression(); |
if (v1.sym != NULL || v2.sym != NULL) { |
error("division of symbols not supported, line %d", lineno); |
} |
if (v2.con == 0) { |
error("division by zero, line %d", lineno); |
} |
v1.con %= v2.con; |
} |
} |
return v1; |
} |
|
|
Value parseAdditiveExpression(void) { |
Value v1, v2; |
|
v1 = parseMultiplicativeExpression(); |
while (token == TOK_PLUS || token == TOK_MINUS) { |
if (token == TOK_PLUS) { |
getToken(); |
v2 = parseMultiplicativeExpression(); |
if (v1.sym != NULL && v2.sym != NULL) { |
error("addition of symbols not supported, line %d", lineno); |
} |
if (v2.sym != NULL) { |
v1.sym = v2.sym; |
} |
v1.con += v2.con; |
} else |
if (token == TOK_MINUS) { |
getToken(); |
v2 = parseMultiplicativeExpression(); |
if (v2.sym != NULL) { |
error("subtraction of symbols not supported, line %d", lineno); |
} |
v1.con -= v2.con; |
} |
} |
return v1; |
} |
|
|
Value parseShiftExpression(void) { |
Value v1, v2; |
|
v1 = parseAdditiveExpression(); |
while (token == TOK_LSHIFT || token == TOK_RSHIFT) { |
if (token == TOK_LSHIFT) { |
getToken(); |
v2 = parseAdditiveExpression(); |
if (v1.sym != NULL || v2.sym != NULL) { |
error("shifting of symbols not supported, line %d", lineno); |
} |
v1.con <<= v2.con; |
} else |
if (token == TOK_RSHIFT) { |
getToken(); |
v2 = parseAdditiveExpression(); |
if (v1.sym != NULL || v2.sym != NULL) { |
error("shifting of symbols not supported, line %d", lineno); |
} |
v1.con >>= v2.con; |
} |
} |
return v1; |
} |
|
|
Value parseAndExpression(void) { |
Value v1, v2; |
|
v1 = parseShiftExpression(); |
while (token == TOK_AMPER) { |
getToken(); |
v2 = parseShiftExpression(); |
if (v2.sym != NULL) { |
error("bitwise 'and' of symbols not supported, line %d", lineno); |
} |
v1.con &= v2.con; |
} |
return v1; |
} |
|
|
Value parseExclusiveOrExpression(void) { |
Value v1, v2; |
|
v1 = parseAndExpression(); |
while (token == TOK_CARET) { |
getToken(); |
v2 = parseAndExpression(); |
if (v2.sym != NULL) { |
error("bitwise 'xor' of symbols not supported, line %d", lineno); |
} |
v1.con ^= v2.con; |
} |
return v1; |
} |
|
|
Value parseInclusiveOrExpression(void) { |
Value v1, v2; |
|
v1 = parseExclusiveOrExpression(); |
while (token == TOK_BAR) { |
getToken(); |
v2 = parseExclusiveOrExpression(); |
if (v2.sym != NULL) { |
error("bitwise 'or' of symbols not supported, line %d", lineno); |
} |
v1.con |= v2.con; |
} |
return v1; |
} |
|
|
Value parseExpression(void) { |
Value v; |
|
v = parseInclusiveOrExpression(); |
return v; |
} |
|
|
/**************************************************************/ |
|
|
void dotSyn(unsigned int code) { |
allowSyn = 1; |
} |
|
|
void dotNosyn(unsigned int code) { |
allowSyn = 0; |
} |
|
|
void dotCode(unsigned int code) { |
currSeg = SEGMENT_CODE; |
} |
|
|
void dotData(unsigned int code) { |
currSeg = SEGMENT_DATA; |
} |
|
|
void dotBss(unsigned int code) { |
currSeg = SEGMENT_BSS; |
} |
|
|
void dotExport(unsigned int code) { |
Symbol *global; |
Symbol *local; |
Fixup *f; |
|
while (1) { |
expect(TOK_IDENT); |
global = lookupEnter(tokenvalString, GLOBAL_TABLE); |
if (global->status != STATUS_UNKNOWN) { |
error("exported symbol '%s' multiply defined in line %d", |
global->name, lineno); |
} |
local = lookupEnter(tokenvalString, LOCAL_TABLE); |
if (local->status == STATUS_GLOBREF) { |
error("exported symbol '%s' multiply exported in line %d", |
local->name, lineno); |
} |
global->status = local->status; |
global->segment = local->segment; |
global->value = local->value; |
while (local->fixups != NULL) { |
f = local->fixups; |
local->fixups = f->next; |
f->next = global->fixups; |
global->fixups = f; |
} |
local->status = STATUS_GLOBREF; |
local->globref = global; |
getToken(); |
if (token != TOK_COMMA) { |
break; |
} |
getToken(); |
} |
} |
|
|
void dotImport(unsigned int code) { |
Symbol *global; |
Symbol *local; |
Fixup *f; |
|
while (1) { |
expect(TOK_IDENT); |
global = lookupEnter(tokenvalString, GLOBAL_TABLE); |
local = lookupEnter(tokenvalString, LOCAL_TABLE); |
if (local->status != STATUS_UNKNOWN) { |
error("imported symbol '%s' multiply defined in line %d", |
local->name, lineno); |
} |
while (local->fixups != NULL) { |
f = local->fixups; |
local->fixups = f->next; |
f->next = global->fixups; |
global->fixups = f; |
} |
local->status = STATUS_GLOBREF; |
local->globref = global; |
getToken(); |
if (token != TOK_COMMA) { |
break; |
} |
getToken(); |
} |
} |
|
|
int countBits(unsigned int x) { |
int n; |
|
n = 0; |
while (x != 0) { |
x &= x - 1; |
n++; |
} |
return n; |
} |
|
|
void dotAlign(unsigned int code) { |
Value v; |
unsigned int mask; |
|
v = parseExpression(); |
if (v.sym != NULL) { |
error("absolute expression expected in line %d", lineno); |
} |
if (countBits(v.con) != 1) { |
error("argument must be a power of 2 in line %d", lineno); |
} |
mask = v.con - 1; |
while ((segPtr[currSeg] & mask) != 0) { |
emitByte(0); |
} |
} |
|
|
void dotSpace(unsigned int code) { |
Value v; |
int i; |
|
v = parseExpression(); |
if (v.sym != NULL) { |
error("absolute expression expected in line %d", lineno); |
} |
for (i = 0; i < v.con; i++) { |
emitByte(0); |
} |
} |
|
|
void dotLocate(unsigned int code) { |
Value v; |
|
v = parseExpression(); |
if (v.sym != NULL) { |
error("absolute expression expected in line %d", lineno); |
} |
while (segPtr[currSeg] != v.con) { |
emitByte(0); |
} |
} |
|
|
void dotByte(unsigned int code) { |
Value v; |
char *p; |
|
while (1) { |
if (token == TOK_STRING) { |
p = tokenvalString; |
while (*p != '\0') { |
emitByte(*p); |
p++; |
} |
getToken(); |
} else { |
v = parseExpression(); |
if (v.sym != NULL) { |
error("absolute expression expected in line %d", lineno); |
} |
emitByte(v.con); |
} |
if (token != TOK_COMMA) { |
break; |
} |
getToken(); |
} |
} |
|
|
void dotHalf(unsigned int code) { |
Value v; |
|
while (1) { |
v = parseExpression(); |
if (v.sym != NULL) { |
error("absolute expression expected in line %d", lineno); |
} |
emitHalf(v.con); |
if (token != TOK_COMMA) { |
break; |
} |
getToken(); |
} |
} |
|
|
void dotWord(unsigned int code) { |
Value v; |
|
while (1) { |
v = parseExpression(); |
if (v.sym == NULL) { |
emitWord(v.con); |
} else { |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_W32, v.con); |
emitWord(0); |
} |
if (token != TOK_COMMA) { |
break; |
} |
getToken(); |
} |
} |
|
|
void dotSet(unsigned int code) { |
Value v; |
Symbol *symbol; |
|
expect(TOK_IDENT); |
symbol = deref(lookupEnter(tokenvalString, LOCAL_TABLE)); |
if (symbol->status != STATUS_UNKNOWN) { |
error("symbol '%s' multiply defined in line %d", |
symbol->name, lineno); |
} |
getToken(); |
expect(TOK_COMMA); |
getToken(); |
v = parseExpression(); |
if (v.sym == NULL) { |
symbol->status = STATUS_DEFINED; |
symbol->segment = SEGMENT_ABS; |
symbol->value = v.con; |
} else { |
error("illegal type of symbol '%s' in expression, line %d", |
v.sym->name, lineno); |
} |
} |
|
|
void formatN(unsigned int code) { |
Value v; |
unsigned int immed; |
|
/* opcode with no operands */ |
if (token != TOK_EOL) { |
/* in exceptional cases (trap) there may be one constant operand */ |
v = parseExpression(); |
if (v.sym != NULL) { |
error("operand must be a constant, line %d", lineno); |
} |
immed = v.con; |
} else { |
immed = 0; |
} |
emitWord(code << 26 | (immed & 0x03FFFFFF)); |
} |
|
|
void formatRH(unsigned int code) { |
int reg; |
Value v; |
|
/* opcode with one register and a half operand */ |
expect(TOK_REGISTER); |
reg = tokenvalNumber; |
getToken(); |
expect(TOK_COMMA); |
getToken(); |
v = parseExpression(); |
if (v.sym == NULL) { |
emitHalf(code << 10 | reg); |
emitHalf(v.con); |
} else { |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con); |
emitHalf(code << 10 | reg); |
emitHalf(0); |
} |
} |
|
|
void formatRHH(unsigned int code) { |
int reg; |
Value v; |
|
/* opcode with one register and a half operand */ |
/* ATTENTION: high order 16 bits encoded in instruction */ |
expect(TOK_REGISTER); |
reg = tokenvalNumber; |
getToken(); |
expect(TOK_COMMA); |
getToken(); |
v = parseExpression(); |
if (v.sym == NULL) { |
emitHalf(code << 10 | reg); |
emitHalf(v.con >> 16); |
} else { |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_H16, v.con); |
emitHalf(code << 10 | reg); |
emitHalf(0); |
} |
} |
|
|
void formatRRH(unsigned int code) { |
int dst, src; |
Value v; |
|
/* opcode with two registers and a half operand */ |
expect(TOK_REGISTER); |
dst = tokenvalNumber; |
getToken(); |
expect(TOK_COMMA); |
getToken(); |
expect(TOK_REGISTER); |
src = tokenvalNumber; |
getToken(); |
expect(TOK_COMMA); |
getToken(); |
v = parseExpression(); |
if (allowSyn) { |
if (v.sym == NULL) { |
if ((v.con & 0xFFFF0000) == 0) { |
/* code: op dst,src,con */ |
emitHalf(code << 10 | src << 5 | dst); |
emitHalf(v.con); |
} else { |
/* code: ldhi $1,con; or $1,$1,con; add $1,$1,src; op dst,$1,0 */ |
emitHalf(OP_LDHI << 10 | AUX_REG); |
emitHalf(v.con >> 16); |
emitHalf((OP_OR + 1) << 10 | AUX_REG << 5 | AUX_REG); |
emitHalf(v.con); |
emitHalf(OP_ADD << 10 | AUX_REG << 5 | src); |
emitHalf(AUX_REG << 11); |
emitHalf(code << 10 | AUX_REG << 5 | dst); |
emitHalf(0); |
} |
} else { |
/* code: ldhi $1,con; or $1,$1,con; add $1,$1,src; op dst,$1,0 */ |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_H16, v.con); |
emitHalf(OP_LDHI << 10 | AUX_REG); |
emitHalf(0); |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con); |
emitHalf((OP_OR + 1) << 10 | AUX_REG << 5 | AUX_REG); |
emitHalf(0); |
emitHalf(OP_ADD << 10 | AUX_REG << 5 | src); |
emitHalf(AUX_REG << 11); |
emitHalf(code << 10 | AUX_REG << 5 | dst); |
emitHalf(0); |
} |
} else { |
if (v.sym == NULL) { |
emitHalf(code << 10 | src << 5 | dst); |
emitHalf(v.con); |
} else { |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con); |
emitHalf(code << 10 | src << 5 | dst); |
emitHalf(0); |
} |
} |
} |
|
|
void formatRRS(unsigned int code) { |
int dst, src; |
Value v; |
|
/* opcode with two registers and a signed half operand */ |
expect(TOK_REGISTER); |
dst = tokenvalNumber; |
getToken(); |
expect(TOK_COMMA); |
getToken(); |
expect(TOK_REGISTER); |
src = tokenvalNumber; |
getToken(); |
expect(TOK_COMMA); |
getToken(); |
v = parseExpression(); |
if (allowSyn) { |
if (v.sym == NULL) { |
if ((v.con & 0xFFFF8000) == 0x00000000 || |
(v.con & 0xFFFF8000) == 0xFFFF8000) { |
/* code: op dst,src,con */ |
emitHalf(code << 10 | src << 5 | dst); |
emitHalf(v.con); |
} else { |
/* code: ldhi $1,con; or $1,$1,con; add $1,$1,src; op dst,$1,0 */ |
emitHalf(OP_LDHI << 10 | AUX_REG); |
emitHalf(v.con >> 16); |
emitHalf((OP_OR + 1) << 10 | AUX_REG << 5 | AUX_REG); |
emitHalf(v.con); |
emitHalf(OP_ADD << 10 | AUX_REG << 5 | src); |
emitHalf(AUX_REG << 11); |
emitHalf(code << 10 | AUX_REG << 5 | dst); |
emitHalf(0); |
} |
} else { |
/* code: ldhi $1,con; or $1,$1,con; add $1,$1,src; op dst,$1,0 */ |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_H16, v.con); |
emitHalf(OP_LDHI << 10 | AUX_REG); |
emitHalf(0); |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con); |
emitHalf((OP_OR + 1) << 10 | AUX_REG << 5 | AUX_REG); |
emitHalf(0); |
emitHalf(OP_ADD << 10 | AUX_REG << 5 | src); |
emitHalf(AUX_REG << 11); |
emitHalf(code << 10 | AUX_REG << 5 | dst); |
emitHalf(0); |
} |
} else { |
if (v.sym == NULL) { |
emitHalf(code << 10 | src << 5 | dst); |
emitHalf(v.con); |
} else { |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con); |
emitHalf(code << 10 | src << 5 | dst); |
emitHalf(0); |
} |
} |
} |
|
|
void formatRRR(unsigned int code) { |
int dst, src1, src2; |
|
/* opcode with three register operands */ |
expect(TOK_REGISTER); |
dst = tokenvalNumber; |
getToken(); |
expect(TOK_COMMA); |
getToken(); |
expect(TOK_REGISTER); |
src1 = tokenvalNumber; |
getToken(); |
expect(TOK_COMMA); |
getToken(); |
expect(TOK_REGISTER); |
src2 = tokenvalNumber; |
getToken(); |
emitHalf(code << 10 | src1 << 5 | src2); |
emitHalf(dst << 11); |
} |
|
|
void formatRRX(unsigned int code) { |
int dst, src1, src2; |
Value v; |
|
/* opcode with three register operands |
or two registers and a half operand */ |
expect(TOK_REGISTER); |
dst = tokenvalNumber; |
getToken(); |
expect(TOK_COMMA); |
getToken(); |
expect(TOK_REGISTER); |
src1 = tokenvalNumber; |
getToken(); |
expect(TOK_COMMA); |
getToken(); |
if (token == TOK_REGISTER) { |
src2 = tokenvalNumber; |
getToken(); |
emitHalf(code << 10 | src1 << 5 | src2); |
emitHalf(dst << 11); |
} else { |
v = parseExpression(); |
if (allowSyn) { |
if (v.sym == NULL) { |
if ((v.con & 0xFFFF0000) == 0) { |
/* code: op dst,src,con */ |
emitHalf((code + 1) << 10 | src1 << 5 | dst); |
emitHalf(v.con); |
} else { |
if ((v.con & 0x0000FFFF) == 0) { |
/* code: ldhi $1,con; op dst,src,$1 */ |
emitHalf(OP_LDHI << 10 | AUX_REG); |
emitHalf(v.con >> 16); |
emitHalf(code << 10 | src1 << 5 | AUX_REG); |
emitHalf(dst << 11); |
} else { |
/* code: ldhi $1,con; or $1,$1,con; op dst,src,$1 */ |
emitHalf(OP_LDHI << 10 | AUX_REG); |
emitHalf(v.con >> 16); |
emitHalf((OP_OR + 1) << 10 | AUX_REG << 5 | AUX_REG); |
emitHalf(v.con); |
emitHalf(code << 10 | src1 << 5 | AUX_REG); |
emitHalf(dst << 11); |
} |
} |
} else { |
/* code: ldhi $1,con; or $1,$1,con; op dst,src,$1 */ |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_H16, v.con); |
emitHalf(OP_LDHI << 10 | AUX_REG); |
emitHalf(0); |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con); |
emitHalf((OP_OR + 1) << 10 | AUX_REG << 5 | AUX_REG); |
emitHalf(0); |
emitHalf(code << 10 | src1 << 5 | AUX_REG); |
emitHalf(dst << 11); |
} |
} else { |
if (v.sym == NULL) { |
emitHalf((code + 1) << 10 | src1 << 5 | dst); |
emitHalf(v.con); |
} else { |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con); |
emitHalf((code + 1) << 10 | src1 << 5 | dst); |
emitHalf(0); |
} |
} |
} |
} |
|
|
void formatRRY(unsigned int code) { |
int dst, src1, src2; |
Value v; |
|
/* opcode with three register operands |
or two registers and a signed half operand */ |
expect(TOK_REGISTER); |
dst = tokenvalNumber; |
getToken(); |
expect(TOK_COMMA); |
getToken(); |
expect(TOK_REGISTER); |
src1 = tokenvalNumber; |
getToken(); |
expect(TOK_COMMA); |
getToken(); |
if (token == TOK_REGISTER) { |
src2 = tokenvalNumber; |
getToken(); |
emitHalf(code << 10 | src1 << 5 | src2); |
emitHalf(dst << 11); |
} else { |
v = parseExpression(); |
if (allowSyn) { |
if (v.sym == NULL) { |
if ((v.con & 0xFFFF8000) == 0x00000000 || |
(v.con & 0xFFFF8000) == 0xFFFF8000) { |
/* code: op dst,src,con */ |
emitHalf((code + 1) << 10 | src1 << 5 | dst); |
emitHalf(v.con); |
} else { |
if ((v.con & 0x0000FFFF) == 0) { |
/* code: ldhi $1,con; op dst,src,$1 */ |
emitHalf(OP_LDHI << 10 | AUX_REG); |
emitHalf(v.con >> 16); |
emitHalf(code << 10 | src1 << 5 | AUX_REG); |
emitHalf(dst << 11); |
} else { |
/* code: ldhi $1,con; or $1,$1,con; op dst,src,$1 */ |
emitHalf(OP_LDHI << 10 | AUX_REG); |
emitHalf(v.con >> 16); |
emitHalf((OP_OR + 1) << 10 | AUX_REG << 5 | AUX_REG); |
emitHalf(v.con); |
emitHalf(code << 10 | src1 << 5 | AUX_REG); |
emitHalf(dst << 11); |
} |
} |
} else { |
/* code: ldhi $1,con; or $1,$1,con; op dst,src,$1 */ |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_H16, v.con); |
emitHalf(OP_LDHI << 10 | AUX_REG); |
emitHalf(0); |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con); |
emitHalf((OP_OR + 1) << 10 | AUX_REG << 5 | AUX_REG); |
emitHalf(0); |
emitHalf(code << 10 | src1 << 5 | AUX_REG); |
emitHalf(dst << 11); |
} |
} else { |
if (v.sym == NULL) { |
emitHalf((code + 1) << 10 | src1 << 5 | dst); |
emitHalf(v.con); |
} else { |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_L16, v.con); |
emitHalf((code + 1) << 10 | src1 << 5 | dst); |
emitHalf(0); |
} |
} |
} |
} |
|
|
void formatRRB(unsigned int code) { |
int src1, src2; |
Value v; |
unsigned int immed; |
|
/* opcode with two registers and a 16 bit signed offset operand */ |
expect(TOK_REGISTER); |
src1 = tokenvalNumber; |
getToken(); |
expect(TOK_COMMA); |
getToken(); |
expect(TOK_REGISTER); |
src2 = tokenvalNumber; |
getToken(); |
expect(TOK_COMMA); |
getToken(); |
v = parseExpression(); |
if (v.sym == NULL) { |
immed = (v.con - ((signed) segPtr[currSeg] + 4)) / 4; |
} else { |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_R16, v.con); |
immed = 0; |
} |
emitHalf(code << 10 | src1 << 5 | src2); |
emitHalf(immed); |
} |
|
|
void formatJ(unsigned int code) { |
Value v; |
unsigned int immed; |
int target; |
|
/* opcode with no registers and a 26 bit signed offset operand or |
opcode with a single register */ |
if (token == TOK_REGISTER) { |
target = tokenvalNumber; |
getToken(); |
emitWord((code + 1) << 26 | target << 21); |
} else { |
v = parseExpression(); |
if (v.sym == NULL) { |
immed = (v.con - ((signed) segPtr[currSeg] + 4)) / 4; |
} else { |
addFixup(v.sym, currSeg, segPtr[currSeg], METHOD_R26, v.con); |
immed = 0; |
} |
emitWord(code << 26 | (immed & 0x03FFFFFF)); |
} |
} |
|
|
void formatJR(unsigned int code) { |
int target; |
|
/* opcode with one register operand */ |
expect(TOK_REGISTER); |
target = tokenvalNumber; |
getToken(); |
emitWord(code << 26 | target << 21); |
} |
|
|
typedef struct instr { |
char *name; |
void (*func)(unsigned int code); |
unsigned int code; |
} Instr; |
|
|
Instr instrTable[] = { |
|
/* pseudo instructions */ |
{ ".syn", dotSyn, 0 }, |
{ ".nosyn", dotNosyn, 0 }, |
{ ".code", dotCode, 0 }, |
{ ".data", dotData, 0 }, |
{ ".bss", dotBss, 0 }, |
{ ".export", dotExport, 0 }, |
{ ".import", dotImport, 0 }, |
{ ".align", dotAlign, 0 }, |
{ ".space", dotSpace, 0 }, |
{ ".locate", dotLocate, 0 }, |
{ ".byte", dotByte, 0 }, |
{ ".half", dotHalf, 0 }, |
{ ".word", dotWord, 0 }, |
{ ".set", dotSet, 0 }, |
|
/* arithmetical instructions */ |
{ "add", formatRRY, OP_ADD }, |
{ "sub", formatRRY, OP_SUB }, |
|
{ "mul", formatRRY, OP_MUL }, |
{ "mulu", formatRRX, OP_MULU }, |
{ "div", formatRRY, OP_DIV }, |
{ "divu", formatRRX, OP_DIVU }, |
{ "rem", formatRRY, OP_REM }, |
{ "remu", formatRRX, OP_REMU }, |
|
/* logical instructions */ |
{ "and", formatRRX, OP_AND }, |
{ "or", formatRRX, OP_OR }, |
{ "xor", formatRRX, OP_XOR }, |
{ "xnor", formatRRX, OP_XNOR }, |
|
/* shift instructions */ |
{ "sll", formatRRX, OP_SLL }, |
{ "slr", formatRRX, OP_SLR }, |
{ "sar", formatRRX, OP_SAR }, |
|
/* load immediate instructions */ |
{ "ldhi", formatRHH, OP_LDHI }, |
|
/* branch instructions */ |
{ "beq", formatRRB, OP_BEQ }, |
{ "bne", formatRRB, OP_BNE }, |
{ "ble", formatRRB, OP_BLE }, |
{ "bleu", formatRRB, OP_BLEU }, |
{ "blt", formatRRB, OP_BLT }, |
{ "bltu", formatRRB, OP_BLTU }, |
{ "bge", formatRRB, OP_BGE }, |
{ "bgeu", formatRRB, OP_BGEU }, |
{ "bgt", formatRRB, OP_BGT }, |
{ "bgtu", formatRRB, OP_BGTU }, |
|
/* jump, call & return instructions */ |
{ "j", formatJ, OP_J }, |
{ "jr", formatJR, OP_JR }, |
{ "jal", formatJ, OP_JAL }, |
{ "jalr", formatJR, OP_JALR }, |
|
/* interrupt related instructions */ |
{ "trap", formatN, OP_TRAP }, |
{ "rfx", formatN, OP_RFX }, |
|
/* load instructions */ |
{ "ldw", formatRRS, OP_LDW }, |
{ "ldh", formatRRS, OP_LDH }, |
{ "ldhu", formatRRS, OP_LDHU }, |
{ "ldb", formatRRS, OP_LDB }, |
{ "ldbu", formatRRS, OP_LDBU }, |
|
/* store instructions */ |
{ "stw", formatRRS, OP_STW }, |
{ "sth", formatRRS, OP_STH }, |
{ "stb", formatRRS, OP_STB }, |
|
/* processor control instructions */ |
{ "mvfs", formatRH, OP_MVFS }, |
{ "mvts", formatRH, OP_MVTS }, |
{ "tbs", formatN, OP_TBS }, |
{ "tbwr", formatN, OP_TBWR }, |
{ "tbri", formatN, OP_TBRI }, |
{ "tbwi", formatN, OP_TBWI } |
|
}; |
|
|
static int cmpInstr(const void *instr1, const void *instr2) { |
return strcmp(((Instr *) instr1)->name, ((Instr *) instr2)->name); |
} |
|
|
void sortInstrTable(void) { |
qsort(instrTable, sizeof(instrTable)/sizeof(instrTable[0]), |
sizeof(instrTable[0]), cmpInstr); |
} |
|
|
Instr *lookupInstr(char *name) { |
int lo, hi, tst; |
int res; |
|
lo = 0; |
hi = sizeof(instrTable) / sizeof(instrTable[0]) - 1; |
while (lo <= hi) { |
tst = (lo + hi) / 2; |
res = strcmp(instrTable[tst].name, name); |
if (res == 0) { |
return &instrTable[tst]; |
} |
if (res < 0) { |
lo = tst + 1; |
} else { |
hi = tst - 1; |
} |
} |
return NULL; |
} |
|
|
/**************************************************************/ |
|
|
void roundupSegments(void) { |
while (segPtr[SEGMENT_CODE] & 3) { |
fputc(0, codeFile); |
segPtr[SEGMENT_CODE] += 1; |
} |
while (segPtr[SEGMENT_DATA] & 3) { |
fputc(0, dataFile); |
segPtr[SEGMENT_DATA] += 1; |
} |
while (segPtr[SEGMENT_BSS] & 3) { |
segPtr[SEGMENT_BSS] += 1; |
} |
} |
|
|
void asmModule(void) { |
Symbol *label; |
Instr *instr; |
|
allowSyn = 1; |
currSeg = SEGMENT_CODE; |
lineno = 0; |
while (fgets(line, LINE_SIZE, inFile) != NULL) { |
lineno++; |
lineptr = line; |
getToken(); |
while (token == TOK_LABEL) { |
label = deref(lookupEnter(tokenvalString, LOCAL_TABLE)); |
if (label->status != STATUS_UNKNOWN) { |
error("label '%s' multiply defined in line %d", |
label->name, lineno); |
} |
label->status = STATUS_DEFINED; |
label->segment = currSeg; |
label->value = segPtr[currSeg]; |
getToken(); |
} |
if (token == TOK_IDENT) { |
instr = lookupInstr(tokenvalString); |
if (instr == NULL) { |
error("unknown instruction '%s' in line %d", |
tokenvalString, lineno); |
} |
getToken(); |
(*instr->func)(instr->code); |
} |
if (token != TOK_EOL) { |
error("garbage in line %d", lineno); |
} |
} |
roundupSegments(); |
} |
|
|
/**************************************************************/ |
|
|
unsigned int read4FromEco(unsigned char *p) { |
return (unsigned int) p[0] << 24 | |
(unsigned int) p[1] << 16 | |
(unsigned int) p[2] << 8 | |
(unsigned int) p[3] << 0; |
} |
|
|
void write4ToEco(unsigned char *p, unsigned int data) { |
p[0] = data >> 24; |
p[1] = data >> 16; |
p[2] = data >> 8; |
p[3] = data >> 0; |
} |
|
|
void conv4FromEcoToNative(unsigned char *p) { |
unsigned int data; |
|
data = read4FromEco(p); |
* (unsigned int *) p = data; |
} |
|
|
void conv4FromNativeToEco(unsigned char *p) { |
unsigned int data; |
|
data = * (unsigned int *) p; |
write4ToEco(p, data); |
} |
|
|
/**************************************************************/ |
|
|
static ExecHeader execHeader; |
static int numSymbols; |
static int crelSize; |
static int drelSize; |
static int symtblSize; |
static int stringSize; |
|
|
static void walkTree(Symbol *s, void (*fp)(Symbol *sp)) { |
if (s == NULL) { |
return; |
} |
walkTree(s->left, fp); |
(*fp)(s); |
walkTree(s->right, fp); |
} |
|
|
void writeDummyHeader(void) { |
fwrite(&execHeader, sizeof(ExecHeader), 1, outFile); |
} |
|
|
void writeRealHeader(void) { |
rewind(outFile); |
execHeader.magic = EXEC_MAGIC; |
execHeader.csize = segPtr[SEGMENT_CODE]; |
execHeader.dsize = segPtr[SEGMENT_DATA]; |
execHeader.bsize = segPtr[SEGMENT_BSS]; |
execHeader.crsize = crelSize; |
execHeader.drsize = drelSize; |
execHeader.symsize = symtblSize; |
execHeader.strsize = stringSize; |
conv4FromNativeToEco((unsigned char *) &execHeader.magic); |
conv4FromNativeToEco((unsigned char *) &execHeader.csize); |
conv4FromNativeToEco((unsigned char *) &execHeader.dsize); |
conv4FromNativeToEco((unsigned char *) &execHeader.bsize); |
conv4FromNativeToEco((unsigned char *) &execHeader.crsize); |
conv4FromNativeToEco((unsigned char *) &execHeader.drsize); |
conv4FromNativeToEco((unsigned char *) &execHeader.symsize); |
conv4FromNativeToEco((unsigned char *) &execHeader.strsize); |
fwrite(&execHeader, sizeof(ExecHeader), 1, outFile); |
} |
|
|
void writeCode(void) { |
int data; |
|
rewind(codeFile); |
while (1) { |
data = fgetc(codeFile); |
if (data == EOF) { |
break; |
} |
fputc(data, outFile); |
} |
} |
|
|
void writeData(void) { |
int data; |
|
rewind(dataFile); |
while (1) { |
data = fgetc(dataFile); |
if (data == EOF) { |
break; |
} |
fputc(data, outFile); |
} |
} |
|
|
void transferFixupsForSymbol(Symbol *s) { |
Fixup *f; |
|
if (s->status != STATUS_UNKNOWN && s->status != STATUS_DEFINED) { |
/* this should never happen */ |
error("global symbol is neither unknown nor defined"); |
} |
if (s->status == STATUS_UNKNOWN && s->fixups == NULL) { |
/* this symbol is neither defined here nor referenced here: skip */ |
s->skip = 1; |
return; |
} |
s->skip = 0; |
while (s->fixups != NULL) { |
/* get next fixup record */ |
f = s->fixups; |
s->fixups = f->next; |
/* use the 'base' component to store the current symbol number */ |
f->base = MSB | numSymbols; |
/* transfer the record to the fixup list */ |
f->next = fixupList; |
fixupList = f; |
} |
numSymbols++; |
} |
|
|
void transferFixups(void) { |
numSymbols = 0; |
walkTree(globalTable, transferFixupsForSymbol); |
} |
|
|
void writeCodeRelocs(void) { |
Fixup *f; |
RelocRecord relRec; |
|
crelSize = 0; |
f = fixupList; |
while (f != NULL) { |
if (f->segment != SEGMENT_CODE && f->segment != SEGMENT_DATA) { |
/* this should never happan */ |
error("fixup found in a segment other than code or data"); |
} |
if (f->segment == SEGMENT_CODE) { |
relRec.offset = f->offset; |
relRec.method = f->method; |
relRec.value = f->value; |
relRec.base = f->base; |
conv4FromNativeToEco((unsigned char *) &relRec.offset); |
conv4FromNativeToEco((unsigned char *) &relRec.method); |
conv4FromNativeToEco((unsigned char *) &relRec.value); |
conv4FromNativeToEco((unsigned char *) &relRec.base); |
fwrite(&relRec, sizeof(RelocRecord), 1, outFile); |
crelSize += sizeof(RelocRecord); |
} |
f = f->next; |
} |
} |
|
|
void writeDataRelocs(void) { |
Fixup *f; |
RelocRecord relRec; |
|
drelSize = 0; |
f = fixupList; |
while (f != NULL) { |
if (f->segment != SEGMENT_CODE && f->segment != SEGMENT_DATA) { |
/* this should never happan */ |
error("fixup found in a segment other than code or data"); |
} |
if (f->segment == SEGMENT_DATA) { |
relRec.offset = f->offset; |
relRec.method = f->method; |
relRec.value = f->value; |
relRec.base = f->base; |
conv4FromNativeToEco((unsigned char *) &relRec.offset); |
conv4FromNativeToEco((unsigned char *) &relRec.method); |
conv4FromNativeToEco((unsigned char *) &relRec.value); |
conv4FromNativeToEco((unsigned char *) &relRec.base); |
fwrite(&relRec, sizeof(RelocRecord), 1, outFile); |
drelSize += sizeof(RelocRecord); |
} |
f = f->next; |
} |
} |
|
|
void writeSymbol(Symbol *s) { |
SymbolRecord symRec; |
|
if (s->skip) { |
/* this symbol is neither defined here nor referenced here: skip */ |
return; |
} |
symRec.name = stringSize; |
if (s->status == STATUS_UNKNOWN) { |
symRec.type = MSB; |
symRec.value = 0; |
} else { |
symRec.type = s->segment; |
symRec.value = s->value; |
} |
conv4FromNativeToEco((unsigned char *) &symRec.name); |
conv4FromNativeToEco((unsigned char *) &symRec.type); |
conv4FromNativeToEco((unsigned char *) &symRec.value); |
fwrite(&symRec, sizeof(SymbolRecord), 1, outFile); |
symtblSize += sizeof(SymbolRecord); |
stringSize += strlen(s->name) + 1; |
} |
|
|
void writeSymbols(void) { |
symtblSize = 0; |
stringSize = 0; |
walkTree(globalTable, writeSymbol); |
} |
|
|
void writeString(Symbol *s) { |
if (s->skip) { |
/* this symbol is neither defined here nor referenced here: skip */ |
return; |
} |
fputs(s->name, outFile); |
fputc('\0', outFile); |
} |
|
|
void writeStrings(void) { |
walkTree(globalTable, writeString); |
} |
|
|
/**************************************************************/ |
|
|
void usage(char *myself) { |
fprintf(stderr, "Usage: %s\n", myself); |
fprintf(stderr, " [-o objfile] set object file name\n"); |
fprintf(stderr, " file source file name\n"); |
fprintf(stderr, " [files...] additional source files\n"); |
exit(1); |
} |
|
|
int main(int argc, char *argv[]) { |
int i; |
char *argp; |
|
sortInstrTable(); |
tmpnam(codeName); |
tmpnam(dataName); |
outName = "a.out"; |
for (i = 1; i < argc; i++) { |
argp = argv[i]; |
if (*argp != '-') { |
break; |
} |
argp++; |
switch (*argp) { |
case 'o': |
if (i == argc - 1) { |
usage(argv[0]); |
} |
outName = argv[++i]; |
break; |
default: |
usage(argv[0]); |
} |
} |
if (i == argc) { |
usage(argv[0]); |
} |
codeFile = fopen(codeName, "w+b"); |
if (codeFile == NULL) { |
error("cannot create temporary code file '%s'", codeName); |
} |
dataFile = fopen(dataName, "w+b"); |
if (dataFile == NULL) { |
error("cannot create temporary data file '%s'", dataName); |
} |
outFile = fopen(outName, "wb"); |
if (outFile == NULL) { |
error("cannot open output file '%s'", outName); |
} |
do { |
inName = argv[i]; |
if (*inName == '-') { |
usage(argv[0]); |
} |
inFile = fopen(inName, "rt"); |
if (inFile == NULL) { |
error("cannot open input file '%s'", inName); |
} |
fprintf(stderr, "Assembling module '%s'...\n", inName); |
asmModule(); |
if (inFile != NULL) { |
fclose(inFile); |
inFile = NULL; |
} |
linkLocals(); |
} while (++i < argc); |
writeDummyHeader(); |
writeCode(); |
writeData(); |
transferFixups(); |
writeCodeRelocs(); |
writeDataRelocs(); |
writeSymbols(); |
writeStrings(); |
writeRealHeader(); |
if (codeFile != NULL) { |
fclose(codeFile); |
codeFile = NULL; |
} |
if (dataFile != NULL) { |
fclose(dataFile); |
dataFile = NULL; |
} |
if (outFile != NULL) { |
fclose(outFile); |
outFile = NULL; |
} |
if (codeName != NULL) { |
unlink(codeName); |
} |
if (dataName != NULL) { |
unlink(dataName); |
} |
return 0; |
} |
/binutils/as/Makefile
0,0 → 1,36
# |
# Makefile for ECO32 assembler |
# |
|
BUILD = ../../build |
|
CC = gcc -m32 |
CFLAGS = -g -Wall |
LDFLAGS = -g |
LDLIBS = -lm |
|
SRCS = as.c |
OBJS = $(patsubst %.c,%.o,$(SRCS)) |
BIN = as |
|
.PHONY: all install clean |
|
all: $(BIN) |
|
install: $(BIN) |
mkdir -p $(BUILD)/bin |
cp $(BIN) $(BUILD)/bin |
|
$(BIN): $(OBJS) |
$(CC) $(LDFLAGS) -o $(BIN) $(OBJS) $(LDLIBS) |
|
%.o: %.c |
$(CC) $(CFLAGS) -o $@ -c $< |
|
depend.mak: |
$(CC) -MM -MG $(CFLAGS) $(SRCS) > depend.mak |
|
-include depend.mak |
|
clean: |
rm -f *~ $(OBJS) $(BIN) depend.mak |
/binutils/include/ar.h
0,0 → 1,28
/* |
* ar.h -- structure of archives (object libraries) |
*/ |
|
|
#ifndef _AR_H_ |
#define _AR_H_ |
|
|
#define AR_MAGIC 0x0412CF03 /* archive file magic number */ |
#define MAX_NAME 60 /* max length of member name */ |
|
|
/* |
* The following structure is stored once per archive member. |
*/ |
|
typedef struct { |
char name[MAX_NAME]; |
time_t date; |
int uid; |
int gid; |
int mode; |
off_t size; |
} ArHeader; |
|
|
#endif /* _AR_H_ */ |
/binutils/include/a.out.h
0,0 → 1,52
/* |
* a.out.h -- structure of linkable object and executable files |
*/ |
|
|
#ifndef _A_OUT_H_ |
#define _A_OUT_H_ |
|
|
#define EXEC_MAGIC 0x1AA09232 |
|
#define METHOD_H16 0 /* write 16 bits with high part of value */ |
#define METHOD_L16 1 /* write 16 bits with low part of value */ |
#define METHOD_R16 2 /* write 16 bits with value relative to PC */ |
#define METHOD_R26 3 /* write 26 bits with value relative to PC */ |
#define METHOD_W32 4 /* write full 32 bit word with value */ |
|
#define SEGMENT_ABS 0 /* absolute values */ |
#define SEGMENT_CODE 1 /* code segment */ |
#define SEGMENT_DATA 2 /* initialized data segment */ |
#define SEGMENT_BSS 3 /* uninitialized data segment */ |
|
|
typedef struct { |
unsigned int magic; /* must be EXEC_MAGIC */ |
unsigned int csize; /* size of code in bytes */ |
unsigned int dsize; /* size of initialized data in bytes */ |
unsigned int bsize; /* size of uninitialized data in bytes */ |
unsigned int crsize; /* size of code relocation info in bytes */ |
unsigned int drsize; /* size of data relocation info in bytes */ |
unsigned int symsize; /* size of symbol table in bytes */ |
unsigned int strsize; /* size of string space in bytes */ |
} ExecHeader; |
|
typedef struct { |
unsigned int offset; /* where to relocate */ |
int method; /* how to relocate */ |
int value; /* additive part of value */ |
int base; /* if MSB = 0: segment number */ |
/* if MSB = 1: symbol table index */ |
} RelocRecord; |
|
typedef struct { |
unsigned int name; /* offset in string space */ |
int type; /* if MSB = 0: the symbol's segment */ |
/* if MSB = 1: the symbol is undefined */ |
int value; /* if symbol defined: the symbol's value */ |
/* if symbol not defined: meaningless */ |
} SymbolRecord; |
|
|
#endif /* _A_OUT_H_ */ |
/binutils/include/README
0,0 → 1,162
|
Format of Object and Executable Files |
------------------------------------- |
|
0) General |
|
The "a.out" file format is used as format for assembler output |
("object files") as well as for linker output ("executable files"). |
The difference of these two is the size of certain sections of |
the file being zero in case of executable files. |
|
The file consists of a header and up to 6 sections: |
- code |
- initialized data |
- code relocation records |
- data relocation records |
- symbol table records |
- symbol string storage |
|
|
1) Header |
|
The header specifies the sizes of all following sections, |
but has itself a fixed length (and is always present): |
|
typedef struct { |
unsigned int magic; /* must be EXEC_MAGIC */ |
unsigned int csize; /* size of code in bytes */ |
unsigned int dsize; /* size of initialized data in bytes */ |
unsigned int bsize; /* size of uninitialized data in bytes */ |
unsigned int crsize; /* size of code relocation info in bytes */ |
unsigned int drsize; /* size of data relocation info in bytes */ |
unsigned int symsize; /* size of symbol table in bytes */ |
unsigned int strsize; /* size of string space in bytes */ |
} ExecHeader; |
|
The magic number is used to distinguish executable files from |
other file types. This field must have the value EXEC_MAGIC. |
|
The code size is given in bytes, but is always a multiple of 4. |
This is the exact size of the code section in the executable file. |
For the code size in memory see "executing an executable" below. |
|
The initialized data size is given in bytes, but is always a |
multiple of 4. This is the exact size of the initialized data |
section in the executable file. For the data size in memory see |
"executing an executable" below. |
|
The uninitialized data size is given in bytes, but is always a |
multiple of 4. There is no corresponding section to this value |
contained within the executable. See "executing an executable" |
below for the semantics of this value. |
|
The code relocation info size is given in bytes, but is always |
a multiple of sizeof(RelocRecord). These records describe the |
changes to be applied to the code section during the link step. |
This size is zero if the file is an executable. |
|
The data relocation info size is given in bytes, but is always |
a multiple of sizeof(RelocRecord). These records describe the |
changes to be applied to the data section during the link step. |
This size is zero if the file is an executable. |
|
The size of the symbol table is given in bytes, but is always |
a multiple of sizeof(SymbolRecord). The symbol table contains |
information about symbols which are exported from or imported |
into this object file. It is mainly used during the link step |
and may not be present (size = 0) if the file is an executable. |
|
The string space is used to store the names of the symbols in |
the symbol table. |
|
|
2) Code/Initialized Data |
|
These sections contain the instructions and the initialized data |
of the program, respectively. |
|
|
3) Code/Data Relocation Records |
|
The relocation records have the following structure: |
|
typedef struct { |
unsigned int offset; /* where to relocate */ |
int method; /* how to relocate */ |
int value; /* additive part of value */ |
int base; /* if MSB = 0: segment number */ |
/* if MSB = 1: symbol table index */ |
} RelocRecord; |
|
The offset gives the position where the relocation has to be done, |
in the form of a byte offset from the beginning of the section. |
|
The method determines how the relocation is performed, and must |
be one of the following constants: |
METHOD_H16 /* write 16 bits with high part of value */ |
METHOD_L16 /* write 16 bits with low part of value */ |
METHOD_R16 /* write 16 bits with value relative to PC */ |
METHOD_R26 /* write 26 bits with value relative to PC */ |
METHOD_W32 /* write full 32 bit word with value */ |
|
"Value" and "base" together are used to compute the final value of |
the relocated code or data item. The value is added to the value of |
the base. The base is either the start address of a segment in memory, |
or the value of an imported symbol. In the former case, which is marked |
by an MSB of 0, the base is specified as one of the following constants: |
SEGMENT_ABS /* absolute values */ |
SEGMENT_CODE /* code segment */ |
SEGMENT_DATA /* initialized data segment */ |
SEGMENT_BSS /* uninitialized data segment */ |
In the latter case, which is marked by an MSB of 1, the remaining bits |
specify the index of the symbol in the symbol table. |
|
|
4) Symbol Table Records |
|
For every symbol which is imported into or exported from the current |
object file, there is a corresponding symbol table record: |
|
typedef struct { |
unsigned int name; /* offset in string space */ |
int type; /* if MSB = 0: the symbol's segment */ |
/* if MSB = 1: the symbol is undefined */ |
int value; /* if symbol defined: the symbol's value */ |
/* if symbol not defined: meaningless */ |
} SymbolRecord; |
|
The name of the symbol is given as an offset into the string space. |
|
If the "type" has an MSB of 0, the symbol is defined here (i.e., |
it is exported), and the "type" specifies the segment (for the |
segment constants see above) in which the symbol is defined, while |
the "value" holds its value. Otherwise, the symbol is not defined |
here (i.e., it is imported), and the "value" has no meaning. |
|
|
5) Symbol String Storage |
|
The strings are null-terminated and stored without any padding. |
|
|
6) Executing an Executable |
|
When an executable file is loaded into memory for execution, three |
logical segments are set up: the code segment, the data segment (with |
initialized data, followed by uninitialized data, which starts off |
as all 0), and a stack. |
|
The code segment begins at address 0 in virtual memory and is loaded |
with the contents of the code section from the executable file. |
|
The data segment begins at the next page boundary (multiple of 4 KB) |
after the code segment. It is loaded with the contents of the data |
section from the executable file and is followed immediately by the |
"uninitialized data", which must be zeroed by the loader. The data |
area is expanded upwards as requested by explicit "brk" system calls. |
|
The stack is located in the highest possible locations in the virtual |
address space, which are accessible in user mode, and thus expanding |
downwards from (but excluding) the address 0x80000000. It is extended |
automatically by the operating system. |
/binutils/dof/dof.c
0,0 → 1,386
/* |
* dof.c -- dump object file |
*/ |
|
|
#include <stdio.h> |
#include <stdlib.h> |
#include <string.h> |
#include <stdarg.h> |
|
#include "../include/a.out.h" |
|
|
#define MSB ((unsigned int) 1 << (sizeof(unsigned int) * 8 - 1)) |
|
|
/**************************************************************/ |
|
|
FILE *inFile; |
ExecHeader execHeader; |
char *segmentName[4] = { "ABS", "CODE", "DATA", "BSS" }; |
char *methodName[5] = { "H16", "L16", "R16", "R26", "W32" }; |
|
|
/**************************************************************/ |
|
|
void error(char *fmt, ...) { |
va_list ap; |
|
va_start(ap, fmt); |
printf("Error: "); |
vprintf(fmt, ap); |
printf("\n"); |
va_end(ap); |
exit(1); |
} |
|
|
/**************************************************************/ |
|
|
unsigned int read4FromEco(unsigned char *p) { |
return (unsigned int) p[0] << 24 | |
(unsigned int) p[1] << 16 | |
(unsigned int) p[2] << 8 | |
(unsigned int) p[3] << 0; |
} |
|
|
void write4ToEco(unsigned char *p, unsigned int data) { |
p[0] = data >> 24; |
p[1] = data >> 16; |
p[2] = data >> 8; |
p[3] = data >> 0; |
} |
|
|
void conv4FromEcoToNative(unsigned char *p) { |
unsigned int data; |
|
data = read4FromEco(p); |
* (unsigned int *) p = data; |
} |
|
|
void conv4FromNativeToEco(unsigned char *p) { |
unsigned int data; |
|
data = * (unsigned int *) p; |
write4ToEco(p, data); |
} |
|
|
/**************************************************************/ |
|
|
#define CODE_START (sizeof(ExecHeader)) |
#define DATA_START (CODE_START + execHeader.csize) |
#define CRELOC_START (DATA_START + execHeader.dsize) |
#define DRELOC_START (CRELOC_START + execHeader.crsize) |
#define SYMTBL_START (DRELOC_START + execHeader.drsize) |
#define STRING_START (SYMTBL_START + execHeader.symsize) |
|
|
void dumpHeader(void) { |
if (fseek(inFile, 0, SEEK_SET) < 0) { |
error("cannot seek to exec header"); |
} |
if (fread(&execHeader, sizeof(ExecHeader), 1, inFile) != 1) { |
error("cannot read exec header"); |
} |
conv4FromEcoToNative((unsigned char *) &execHeader.magic); |
conv4FromEcoToNative((unsigned char *) &execHeader.csize); |
conv4FromEcoToNative((unsigned char *) &execHeader.dsize); |
conv4FromEcoToNative((unsigned char *) &execHeader.bsize); |
conv4FromEcoToNative((unsigned char *) &execHeader.crsize); |
conv4FromEcoToNative((unsigned char *) &execHeader.drsize); |
conv4FromEcoToNative((unsigned char *) &execHeader.symsize); |
conv4FromEcoToNative((unsigned char *) &execHeader.strsize); |
if (execHeader.magic != EXEC_MAGIC) { |
error("wrong magic number in exec header"); |
} |
printf("Header\n"); |
printf(" size of code : %8u bytes\n", execHeader.csize); |
printf(" size of data : %8u bytes\n", execHeader.dsize); |
printf(" size of bss : %8u bytes\n", execHeader.bsize); |
printf(" size of code relocs : %8u bytes\n", execHeader.crsize); |
printf(" size of data relocs : %8u bytes\n", execHeader.drsize); |
printf(" size of symbol table : %8u bytes\n", execHeader.symsize); |
printf(" size of string space : %8u bytes\n", execHeader.strsize); |
} |
|
|
void dumpBytes(unsigned int totalSize) { |
unsigned int currSize; |
unsigned char line[16]; |
int n, i; |
unsigned char c; |
|
currSize = 0; |
while (currSize < totalSize) { |
if (totalSize - currSize >= 16) { |
n = 16; |
} else { |
n = totalSize - currSize; |
} |
for (i = 0; i < n; i++) { |
line[i] = fgetc(inFile); |
} |
printf("%08X: ", currSize); |
for (i = 0; i < 16; i++) { |
if (i < n) { |
c = line[i]; |
printf("%02X", c); |
} else { |
printf(" "); |
} |
printf(" "); |
} |
printf(" "); |
for (i = 0; i < 16; i++) { |
if (i < n) { |
c = line[i]; |
if (c >= 32 && c <= 126) { |
printf("%c", c); |
} else { |
printf("."); |
} |
} else { |
printf(" "); |
} |
} |
printf("\n"); |
currSize += n; |
} |
} |
|
|
void dumpCode(void) { |
if (fseek(inFile, CODE_START, SEEK_SET) < 0) { |
error("cannot seek to code section"); |
} |
printf("\nCode Segment\n"); |
dumpBytes(execHeader.csize); |
} |
|
|
void dumpData(void) { |
if (fseek(inFile, DATA_START, SEEK_SET) < 0) { |
error("cannot seek to data section"); |
} |
printf("\nData Segment\n"); |
dumpBytes(execHeader.dsize); |
} |
|
|
void dumpRelocs(unsigned int totalSize) { |
unsigned int currSize; |
int n; |
RelocRecord relRec; |
|
currSize = 0; |
n = 0; |
while (currSize < totalSize) { |
if (fread(&relRec, sizeof(RelocRecord), 1, inFile) != 1) { |
error("cannot read relocation record"); |
} |
conv4FromEcoToNative((unsigned char *) &relRec.offset); |
conv4FromEcoToNative((unsigned char *) &relRec.method); |
conv4FromEcoToNative((unsigned char *) &relRec.value); |
conv4FromEcoToNative((unsigned char *) &relRec.base); |
printf(" %d:\n", n); |
printf(" offset = 0x%08X\n", relRec.offset); |
if (relRec.method < 0 || relRec.method > 4) { |
error("illegal relocation method"); |
} |
printf(" method = %s\n", methodName[relRec.method]); |
printf(" value = 0x%08X\n", relRec.value); |
if (relRec.base & MSB) { |
printf(" base = symbol # %d\n", relRec.base & ~MSB); |
} else { |
if (relRec.base < 0 || relRec.base > 3) { |
error("base contains an illegal segment number"); |
} |
printf(" base = %s\n", segmentName[relRec.base]); |
} |
currSize += sizeof(RelocRecord); |
n++; |
} |
} |
|
|
void dumpCodeRelocs(void) { |
if (fseek(inFile, CRELOC_START, SEEK_SET) < 0) { |
error("cannot seek to code relocation section"); |
} |
printf("\nCode Relocation Records\n"); |
dumpRelocs(execHeader.crsize); |
} |
|
|
void dumpDataRelocs(void) { |
if (fseek(inFile, DRELOC_START, SEEK_SET) < 0) { |
error("cannot seek to data relocation section"); |
} |
printf("\nData Relocation Records\n"); |
dumpRelocs(execHeader.drsize); |
} |
|
|
void dumpString(unsigned int offset) { |
long pos; |
int c; |
|
pos = ftell(inFile); |
if (fseek(inFile, STRING_START + offset, SEEK_SET) < 0) { |
error("cannot seek to string"); |
} |
while (1) { |
c = fgetc(inFile); |
if (c == EOF) { |
error("unexpected end of file"); |
} |
if (c == 0) { |
break; |
} |
fputc(c, stdout); |
} |
fseek(inFile, pos, SEEK_SET); |
} |
|
|
void dumpSymbolTable(void) { |
unsigned int currSize; |
int n; |
SymbolRecord symRec; |
|
if (fseek(inFile, SYMTBL_START, SEEK_SET) < 0) { |
error("cannot seek to symbol table section"); |
} |
printf("\nSymbol Table Records\n"); |
currSize = 0; |
n = 0; |
while (currSize < execHeader.symsize) { |
if (fread(&symRec, sizeof(SymbolRecord), 1, inFile) != 1) { |
error("cannot read symbol record"); |
} |
conv4FromEcoToNative((unsigned char *) &symRec.name); |
conv4FromEcoToNative((unsigned char *) &symRec.type); |
conv4FromEcoToNative((unsigned char *) &symRec.value); |
printf(" %d:\n", n); |
printf(" name = "); |
dumpString(symRec.name); |
printf("\n"); |
if (symRec.type & MSB) { |
printf(" --- undefined ---\n"); |
} else { |
if (symRec.type < 0 || symRec.type > 3) { |
error("type contains an illegal segment number"); |
} |
printf(" segment = %s\n", segmentName[symRec.type]); |
printf(" value = 0x%08X\n", symRec.value); |
} |
currSize += sizeof(SymbolRecord); |
n++; |
} |
} |
|
|
/**************************************************************/ |
|
|
void usage(char *myself) { |
printf("Usage: %s\n", myself); |
printf(" [-c] dump code\n"); |
printf(" [-d] dump data\n"); |
printf(" [-x] dump code relocations\n"); |
printf(" [-y] dump data relocations\n"); |
printf(" [-s] dump symbol table\n"); |
printf(" [-a] dump all\n"); |
printf(" file object file to be dumped\n"); |
exit(1); |
} |
|
|
int main(int argc, char *argv[]) { |
int i; |
char *argp; |
int optionCode; |
int optionData; |
int optionCodeRelocs; |
int optionDataRelocs; |
int optionSymbolTable; |
char *inName; |
|
optionCode = 0; |
optionData = 0; |
optionCodeRelocs = 0; |
optionDataRelocs = 0; |
optionSymbolTable = 0; |
inName = NULL; |
for (i = 1; i < argc; i++) { |
argp = argv[i]; |
if (*argp == '-') { |
argp++; |
switch (*argp) { |
case 'c': |
optionCode = 1; |
break; |
case 'd': |
optionData = 1; |
break; |
case 'x': |
optionCodeRelocs = 1; |
break; |
case 'y': |
optionDataRelocs = 1; |
break; |
case 's': |
optionSymbolTable = 1; |
break; |
case 'a': |
optionCode = 1; |
optionData = 1; |
optionCodeRelocs = 1; |
optionDataRelocs = 1; |
optionSymbolTable = 1; |
break; |
default: |
usage(argv[0]); |
} |
} else { |
if (inName != NULL) { |
usage(argv[0]); |
} |
inName = argp; |
} |
} |
if (inName == NULL) { |
usage(argv[0]); |
} |
inFile = fopen(inName, "r"); |
if (inFile == NULL) { |
error("cannot open input file '%s'", inName); |
} |
dumpHeader(); |
if (optionCode) { |
dumpCode(); |
} |
if (optionData) { |
dumpData(); |
} |
if (optionCodeRelocs) { |
dumpCodeRelocs(); |
} |
if (optionDataRelocs) { |
dumpDataRelocs(); |
} |
if (optionSymbolTable) { |
dumpSymbolTable(); |
} |
fclose(inFile); |
return 0; |
} |
/binutils/dof/Makefile
0,0 → 1,36
# |
# Makefile for ECO32 object file dumper |
# |
|
BUILD = ../../build |
|
CC = gcc -m32 |
CFLAGS = -g -Wall |
LDFLAGS = -g |
LDLIBS = -lm |
|
SRCS = dof.c |
OBJS = $(patsubst %.c,%.o,$(SRCS)) |
BIN = dof |
|
.PHONY: all install clean |
|
all: $(BIN) |
|
install: $(BIN) |
mkdir -p $(BUILD)/bin |
cp $(BIN) $(BUILD)/bin |
|
$(BIN): $(OBJS) |
$(CC) $(LDFLAGS) -o $(BIN) $(OBJS) $(LDLIBS) |
|
%.o: %.c |
$(CC) $(CFLAGS) -o $@ -c $< |
|
depend.mak: |
$(CC) -MM -MG $(CFLAGS) $(SRCS) > depend.mak |
|
-include depend.mak |
|
clean: |
rm -f *~ $(OBJS) $(BIN) depend.mak |
/binutils/Makefile
0,0 → 1,25
# |
# Makefile for building the assembler tool chain |
# |
|
BUILD = ../build |
|
DIRS = ar as dof ld |
|
.PHONY: all install clean |
|
all: |
for i in $(DIRS) ; do \ |
$(MAKE) -C $$i all ; \ |
done |
|
install: |
for i in $(DIRS) ; do \ |
$(MAKE) -C $$i install ; \ |
done |
|
clean: |
for i in $(DIRS) ; do \ |
$(MAKE) -C $$i clean ; \ |
done |
rm -f *~ |
/Makefile
4,7 → 4,7
|
VERSION = 0.23 |
|
DIRS = doc |
DIRS = doc binutils |
BUILD = `pwd`/build |
|
.PHONY: all compiler builddir clean dist |