macross/slinky/read.c
2016-01-21 22:02:21 +01:00

551 lines
15 KiB
C

/*
* Copyright (c) 1987 Fujitsu
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*
read.c -- Routines to read stuff in from object files for the Slinky
linker.
Chip Morningstar -- Lucasfilm Ltd.
10-March-1985
*/
#include "slinkyTypes.h"
#include "slinkyGlobals.h"
#define isAbsolute(symbol) (((symbol)->symbolClass & SYMBOL_ABSOLUTE) != 0)
#define isRelocatable(symbol) (((symbol)->symbolClass &SYMBOL_RELOCATABLE)!=0)
void
fileCheck(fildes, fileName)
FILE *fildes;
char *fileName;
{
if (feof(fildes)) {
error(PREMATURE_EOF_ERROR, fileName);
chokePukeAndDie();
} else if (ferror(fildes)) {
error(ERROR_READING_OBJECT_FILE, fileName);
perror("Unix says");
chokePukeAndDie();
}
}
wordType
readWord(file, fileName)
FILE *file;
char *fileName;
{
wordType result;
register char loByte;
register char hiByte;
loByte = getc(file);
hiByte = getc(file);
fileCheck(file, fileName);
result = ((hiByte & 0xFF) << 8) | (loByte & 0xFF);
return(result);
}
byte
readByte(file, fileName)
FILE *file;
char *fileName;
{
int result;
if ((result = getc(file)) == EOF) {
fileCheck(file, fileName);
}
return(result);
}
bigWord
readBigword(file, fileName)
FILE *file;
char *fileName;
{
register bigWord result;
result = getc(file) & 0xFF;
result |= (getc(file) & 0xFF) << 8;
result |= (getc(file) & 0xFF) << 16;
result |= (getc(file) & 0xFF) << 24;
fileCheck(file, fileName);
return(result);
}
bigWord
read3ByteWord(file, fileName)
FILE *file;
char *fileName;
{
register bigWord result;
result = getc(file) & 0xFF;
result |= (getc(file) & 0xFF) << 8;
result |= (getc(file) & 0xFF) << 16;
fileCheck(file, fileName);
return(result);
}
int
readString(buffer, fildes, fileName)
char *buffer;
FILE *fildes;
char *fileName;
{
register char c;
register char *scratchBuffer;
scratchBuffer = buffer;
while ((c = getc(fildes)) != EOF && c != '\0')
*scratchBuffer++ = c;
fileCheck(fildes, fileName);
*scratchBuffer++ = '\0';
return(scratchBuffer - buffer);
}
void
readChunk(buffer, numberOfBytes, fildes, fileName)
byte *buffer;
int numberOfBytes;
FILE *fildes;
char *fileName;
{
do {
*buffer++ = getc(fildes);
} while (--numberOfBytes > 0);
fileCheck(fildes, fileName);
}
void
readCode(startAddress, endAddress, mode, objectFile, objectFildes)
addressType startAddress;
addressType endAddress;
int mode;
objectFileListType *objectFile;
FILE *objectFildes;
{
int size;
byte *codeBuffer;
codeSegmentHeaderType *newCodeSegment;
static int currentConstraint = 0;
static int currentAlignment = 0;
size = (short)endAddress - (short)startAddress + 1;
if (size == -2) {
entryPointAddress = startAddress;
entryPointMode = mode;
haveEntryPoint = TRUE;
readByte(objectFildes, objectFile->name);
return;
} else if (size == 0) {
currentConstraint = readWord(objectFildes, objectFile->name);
return;
} else if (size == -1) {
currentAlignment = readWord(objectFildes, objectFile->name);
return;
}
size = (wordType)endAddress - (wordType)startAddress + 1;
codeBuffer = typeAllocBlock(byte, size);
readChunk(codeBuffer, size, objectFildes, objectFile->name);
newCodeSegment = typeAlloc(codeSegmentHeaderType);
newCodeSegment->fileName = objectFile->name;
newCodeSegment->segmentStartAddress = startAddress;
newCodeSegment->segmentEndAddress = endAddress;
newCodeSegment->segmentMode = mode;
newCodeSegment->segmentCodeBuffer = codeBuffer;
newCodeSegment->relocationOffset = 0;
newCodeSegment->constraint = currentConstraint;
newCodeSegment->alignment = currentAlignment;
currentConstraint = currentAlignment = 0;
if (objectFile->lastCodeSegment == NULL) {
objectFile->codeSegments = newCodeSegment;
} else {
objectFile->lastCodeSegment->nextSegment = newCodeSegment;
}
objectFile->lastCodeSegment = newCodeSegment;
newCodeSegment->nextSegment = NULL;
if (mode == MODE_ABSOLUTE)
installAbsoluteCodeSegment(newCodeSegment);
if (debug)
printCode(startAddress, endAddress, mode);
}
bool
compareReferences(reference1, reference2)
expressionReferenceType *reference1;
expressionReferenceType *reference2;
{
if (reference1->referenceMode == MODE_ABSOLUTE && reference2->
referenceMode == MODE_RELOCATABLE)
return(-1);
else
return(reference1->referenceAddress - reference2->
referenceAddress);
/* else if (reference1->referenceAddress < reference2->referenceAddress)
return(-1);
else if (reference1->referenceAddress > reference2->referenceAddress)
return(1);
else
return(0);*/
}
void
sortReferences(theReferences, numberOfReferences)
expressionReferenceType *theReferences;
int numberOfReferences;
{
qsort(theReferences, numberOfReferences,
sizeof(expressionReferenceType), compareReferences);
}
void
readReference(reference, fildes, fileName)
expressionReferenceType *reference;
FILE *fildes;
char *fileName;
{
register byte funnyByte;
reference->referenceAddress = read3ByteWord(fildes, fileName);
funnyByte = readByte(fildes, fileName);
reference->referenceMode = funnyByte & 1;
reference->referenceRelative = (funnyByte >> 1) & 1;
reference->referenceExternal = (funnyByte >> 2) & 1;
reference->referenceKind = (funnyByte >> 3) & 7;
reference->referenceExpression.inFile = readBigword(fildes, fileName);
if (debug) {
printReference(reference);
}
}
void
readReferences(objectFile, objectFildes)
objectFileListType *objectFile;
FILE *objectFildes;
{
int count;
int readCount;
expressionReferenceType *theReferences;
expressionReferenceType *readPtr;
expressionReferenceType *subPtr;
codeSegmentHeaderType *codeSegment;
readCount = count = readBigword(objectFildes, objectFile->name);
if (readCount == 0)
readPtr = theReferences = NULL;
else
readPtr = theReferences =
typeAllocBlock(expressionReferenceType, count);
if (debug)
printf(" %d references\n", count);
while (readCount-- > 0)
readReference(readPtr++, objectFildes, objectFile->name);
sortReferences(theReferences, count);
if (debug) {
printf(" sorted references\n");
for (readCount=0; readCount<count; readCount++)
printReference(&(theReferences[readCount]));
}
readPtr = theReferences;
subPtr = theReferences;
readCount = count;
for (codeSegment = objectFile->codeSegments; codeSegment != NULL;
codeSegment = codeSegment->nextSegment) {
codeSegment->segmentReferences = readPtr;
while (codeSegment->nextSegment != NULL && readPtr != NULL &&
readPtr->referenceAddress <= codeSegment->
segmentEndAddress && readPtr->
referenceMode == codeSegment->segmentMode &&
readCount-- > 0) {
readPtr++;
}
if (codeSegment->nextSegment != NULL) {
codeSegment->referenceCount = readPtr - subPtr;
subPtr = readPtr;
} else {
codeSegment->referenceCount = count - (readPtr -
theReferences);
}
}
}
bool
compareSymbolValues(symbol1, symbol2)
symbolType **symbol1;
symbolType **symbol2;
{
if ((isAbsolute(*symbol1) && !isAbsolute(*symbol2)) ||
(isRelocatable(*symbol1) && !isRelocatable(*symbol2)
&& !isAbsolute(*symbol2)))
return(-1);
else if ((isAbsolute(*symbol2) && !isAbsolute(*symbol1)) ||
(isRelocatable(*symbol2) && !isRelocatable(*symbol1)
&& !isAbsolute(*symbol1)))
return(1);
else
return((*symbol1)->symbolValue - (*symbol2)->symbolValue);
/* else if ((*symbol1)->symbolValue < (*symbol2)->symbolValue)
return(-1);
else if ((*symbol1)->symbolValue == (*symbol2)->symbolValue)
return(0);
else
return(1);*/
}
void
readSymbols(objectFile, objectFildes)
objectFileListType *objectFile;
FILE *objectFildes;
{
symbolType *symbolTable;
symbolType **symbolTableIndir;
int symbolCount;
int stringSize;
char *stringBuffer;
char *fileName;
int symbolTag;
fileName = objectFile->name;
symbolCount = readBigword(objectFildes, fileName);
objectFile->symbolCount = symbolCount;
stringSize = readBigword(objectFildes, fileName);
if (debug) {
printf(" %d symbols with %d bytes of strings\n",
symbolCount, stringSize);
}
symbolTable = typeAllocBlock(symbolType, symbolCount);
symbolTableIndir = typeAllocBlock(symbolType *, symbolCount);
stringBuffer = typeAllocBlock(char, stringSize);
objectFile->symbolTable = symbolTableIndir;
symbolTag = 0;
while (symbolCount-- > 0) {
*symbolTableIndir++ = symbolTable;
symbolTable->symbolClass = readByte(objectFildes, fileName);
symbolTable->symbolValue = readBigword(objectFildes,fileName);
symbolTable->symbolName = stringBuffer;
stringBuffer += readString(stringBuffer, objectFildes,
fileName);
if (debug) {
printSymbol(symbolTag, symbolTable);
symbolTag++;
}
if ((symbolTable->symbolClass & SYMBOL_EXTERNAL) &&
(symbolTable->symbolClass & ~SYMBOL_EXTERNAL))
globalSymbolCount++;
symbolTable++;
}
}
expressionPCType
readOneExpression(objectFile, objectFildes)
objectFileListType *objectFile;
FILE *objectFildes;
{
char *fileName;
int expressionSize;
byte *expressionBuffer;
expressionPCType result;
int saveExpressionSize;
fileName = objectFile->name;
expressionSize = readBigword(objectFildes, fileName);
if (expressionSize == 0)
return(NULL);
expressionBuffer = typeAllocBlock(byte, expressionSize);
result = expressionBuffer;
saveExpressionSize = expressionSize;
do {
*expressionBuffer++ = readByte(objectFildes, fileName);
} while (--expressionSize > 0);
if (debug) {
printExpression(result, saveExpressionSize);
}
return(result);
}
void
readExpressions(objectFile, objectFildes)
objectFileListType *objectFile;
FILE *objectFildes;
{
expressionPCType *expressions;
int expressionCount;
int expressionSize;
int saveExpressionSize;
char *fileName;
byte *expressionBuffer;
fileName = objectFile->name;
expressionCount = readBigword(objectFildes, fileName);
objectFile->expressionCount = expressionCount;
if (debug)
printf(" %d expressions\n", expressionCount);
expressions = typeAllocBlock(expressionPCType, expressionCount);
objectFile->expressions = expressions;
while (expressionCount-- > 0) {
*expressions = readOneExpression(objectFile, objectFildes);
expressions++;
}
if (haveEntryPoint && entryPointAddress==0xFFFE && entryPointMode==
MODE_RELOCATABLE && !haveExpressionEntryPoint) {
if (debug)
printf("Start address expression:\n");
entryPointAddress = 0;
entryPointExpression = readOneExpression(objectFile,
objectFildes);
readExpressionEntryPoint = TRUE;
}
}
argumentListType *
readArgumentList(objectFile, objectFildes)
objectFileListType *objectFile;
FILE *objectFildes;
{
int argumentCount;
char *fileName;
argumentListType *result;
int i;
int symbolNumber;
fileName = objectFile->name;
argumentCount = readByte(objectFildes, fileName);
if (argumentCount == 0)
return(NULL);
result = typeAllocBlock(argumentListType, argumentCount);
for (i=0; i<argumentCount-1; ++i)
result[i].nextArgument = &(result[i+1]);
result[argumentCount].nextArgument = NULL;
for (i=0; i<argumentCount; ++i) {
symbolNumber = readBigword(objectFildes, fileName);
result[i].argumentSymbol = objectFile->
symbolTable[symbolNumber];
}
return(result);
}
void
readFunctions(objectFile, objectFildes)
objectFileListType *objectFile;
FILE *objectFildes;
{
functionType *functions;
int functionCount;
int functionSize;
int argumentCount;
int useFunctionSize;
char *fileName;
byte *functionBuffer;
fileName = objectFile->name;
functionCount = readBigword(objectFildes, fileName);
objectFile->functionCount = functionCount;
if (debug)
printf(" %d functions\n", functionCount);
functions = typeAllocBlock(functionType, functionCount);
objectFile->functions = functions;
while (functionCount-- > 0) {
functions->functionArguments = readArgumentList(objectFile,
objectFildes);
functionSize = readBigword(objectFildes, fileName);
functionBuffer = typeAllocBlock(byte, functionSize);
functions->functionBody = functionBuffer;
useFunctionSize = functionSize;
while (useFunctionSize-- > 0)
*functionBuffer++ = readByte(objectFildes,fileName);
if (debug) {
printExpression(functions->functionBody,functionSize);
}
functions++;
}
}
void
instantiateExpressionAndSymbolPointers(objectFile)
objectFileListType *objectFile;
{
symbolType **symbolTable;
expressionPCType *expressions;
functionType *functions;
int i;
codeSegmentHeaderType *codeSegment;
expressionReferenceType *reference;
int referenceCount;
currentSymbolTable = objectFile->symbolTable;
currentFunctionTable = objectFile->functions;
expressions = objectFile->expressions;
for (codeSegment = objectFile->codeSegments; codeSegment != NULL;
codeSegment = codeSegment->nextSegment) {
for (reference = codeSegment->segmentReferences, referenceCount =
codeSegment->referenceCount; referenceCount > 0;
reference++, referenceCount--) {
pc = reference->referenceExpression.inCore = expressions[
reference->referenceExpression.inFile];
putSymbolPointersIntoExpression();
}
}
functions = objectFile->functions;
for (i=0; i<objectFile->functionCount; ++i) {
pc = functions[i].functionBody;
putSymbolPointersIntoExpression();
}
}
void
readReservations(objectFile, objectFildes)
objectFileListType *objectFile;
FILE *objectFildes;
{
addressType startAddress;
reservationListType *buildReservation();
if (debug)
printf(" reservations\n");
while ((startAddress = readWord(objectFildes, objectFile->name)) !=
0xFFFF)
reservationList = buildReservation(startAddress,
readWord(objectFildes, objectFile->name),
reservationList);
}
reservationListType *
buildReservation(startAddress, blockSize, nextReservation)
addressType startAddress;
int blockSize;
reservationListType *nextReservation;
{
reservationListType *result;
result = typeAlloc(reservationListType);
result->startAddress = startAddress;
result->blockSize = blockSize;
result->nextReservation = nextReservation;
if (debug)
printf(" Res: 0x%x 0x%x @0x%x -> 0x%x\n", startAddress,
blockSize, result, nextReservation);
return(result);
}