mirror of
https://github.com/Museum-of-Art-and-Digital-Entertainment/macross.git
synced 2024-11-22 11:32:10 +00:00
355 lines
11 KiB
C
355 lines
11 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.
|
|
*/
|
|
/*
|
|
relocate.c -- Routines to relocate relocatable code for the Slinky
|
|
linker.
|
|
|
|
Chip Morningstar -- Lucasfilm Ltd.
|
|
|
|
15-March-1985
|
|
*/
|
|
|
|
#include "slinkyTypes.h"
|
|
#include "slinkyGlobals.h"
|
|
#include "relocate.h"
|
|
#include "debugPrint.h"
|
|
#include "errorStuff.h"
|
|
#include "link.h"
|
|
#include "map.h"
|
|
|
|
#define isUndefined(symbol) (((symbol)->symbolClass & ~SYMBOL_EXTERNAL) == 0)
|
|
|
|
void
|
|
removeZeroPageFromFreeList(void)
|
|
{
|
|
while (freeSegmentList->segmentEndAddress <= 0x100)
|
|
freeSegmentList = freeSegmentList->nextFreeSegment;
|
|
if (freeSegmentList->segmentStartAddress < 0x100)
|
|
freeSegmentList->segmentStartAddress = 0x100;
|
|
}
|
|
|
|
addressType
|
|
align(addressType address, int alignment)
|
|
{
|
|
if (alignment == 0)
|
|
return(address);
|
|
else
|
|
return(((address + alignment - 1) / alignment) * alignment);
|
|
}
|
|
|
|
addressType
|
|
constrain(addressType address, int size, addressType constraint)
|
|
{
|
|
if (constraint == 0)
|
|
return(address);
|
|
else if (address/constraint != (address + size - 1)/constraint)
|
|
return(align(address, constraint));
|
|
else
|
|
return(address);
|
|
}
|
|
void
|
|
moveRelocationBase(addressType newBase)
|
|
{
|
|
freeSegmentEntryType *freePtr;
|
|
freeSegmentEntryType *newFreePtr;
|
|
|
|
freePtr = freeSegmentList;
|
|
while (freePtr != NULL && newBase > freePtr->segmentEndAddress)
|
|
freePtr = freePtr->nextFreeSegment;
|
|
if (freePtr == NULL || freePtr->segmentStartAddress == newBase) {
|
|
effectiveFreeSegmentList = freePtr;
|
|
} else {
|
|
newFreePtr = typeAlloc(freeSegmentEntryType);
|
|
newFreePtr->segmentEndAddress = freePtr->segmentEndAddress;
|
|
freePtr->segmentEndAddress = newBase - 1;
|
|
newFreePtr->segmentStartAddress = newBase;
|
|
newFreePtr->nextFreeSegment = freePtr->nextFreeSegment;
|
|
freePtr->nextFreeSegment = newFreePtr;
|
|
effectiveFreeSegmentList = newFreePtr;
|
|
}
|
|
}
|
|
|
|
addressType
|
|
allocateRelocatable(codeSegmentHeaderType *codeSegment)
|
|
{
|
|
freeSegmentEntryType *freePtr;
|
|
freeSegmentEntryType *previousPtr;
|
|
freeSegmentEntryType *newFreePtr;
|
|
int size;
|
|
addressType effectiveStartAddress;
|
|
|
|
freePtr = effectiveFreeSegmentList;
|
|
previousPtr = NULL;
|
|
size = codeSegment->segmentEndAddress - codeSegment->
|
|
segmentStartAddress + 1;
|
|
while (freePtr != NULL) {
|
|
effectiveStartAddress = align(freePtr->segmentStartAddress,
|
|
codeSegment->alignment);
|
|
effectiveStartAddress = constrain(effectiveStartAddress, size,
|
|
codeSegment->constraint);
|
|
if (freePtr->segmentEndAddress - effectiveStartAddress + 1 <
|
|
size) {
|
|
previousPtr = freePtr;
|
|
freePtr = freePtr->nextFreeSegment;
|
|
continue;
|
|
}
|
|
/* if we made it to here, we got a winner! */
|
|
if (effectiveStartAddress == freePtr->segmentStartAddress) {
|
|
if (effectiveStartAddress + size - 1 == freePtr->
|
|
segmentEndAddress) {
|
|
if (previousPtr == NULL)
|
|
freeSegmentList = freePtr->nextFreeSegment;
|
|
else
|
|
previousPtr->nextFreeSegment = freePtr->
|
|
nextFreeSegment;
|
|
} else {
|
|
freePtr->segmentStartAddress += size;
|
|
}
|
|
} else {
|
|
if (effectiveStartAddress + size - 1 == freePtr->
|
|
segmentEndAddress) {
|
|
freePtr->segmentEndAddress -= size;
|
|
} else {
|
|
newFreePtr = typeAlloc(freeSegmentEntryType);
|
|
newFreePtr->nextFreeSegment = freePtr->nextFreeSegment;
|
|
freePtr->nextFreeSegment = newFreePtr;
|
|
newFreePtr->segmentEndAddress =freePtr->segmentEndAddress;
|
|
freePtr->segmentEndAddress = effectiveStartAddress - 1;
|
|
newFreePtr->segmentStartAddress = effectiveStartAddress +
|
|
size;
|
|
}
|
|
}
|
|
return(effectiveStartAddress);
|
|
}
|
|
return((addressType) -1);
|
|
}
|
|
|
|
void
|
|
relocateOneCodeSegment(codeSegmentHeaderType *codeSegment, addressType targetLocation)
|
|
{
|
|
int relocationOffset;
|
|
|
|
relocationOffset = targetLocation - codeSegment->segmentStartAddress;
|
|
if (verbose)
|
|
printf(" 0x%04x:0x%04x --> 0x%04x", codeSegment->
|
|
segmentStartAddress, codeSegment->segmentEndAddress,
|
|
targetLocation);
|
|
codeSegment->relocationOffset = relocationOffset;
|
|
codeSegment->segmentStartAddress += relocationOffset;
|
|
codeSegment->segmentEndAddress += relocationOffset;
|
|
if (!packFlag) {
|
|
moveRelocationBase(codeSegment->segmentEndAddress+1);
|
|
}
|
|
if (verbose)
|
|
printf(" (0x%04x:0x%04x)\n", codeSegment->segmentStartAddress,
|
|
codeSegment->segmentEndAddress);
|
|
installSegment(codeSegment);
|
|
}
|
|
|
|
void
|
|
relocatem(void)
|
|
{
|
|
objectFileListType *inputFileList;
|
|
addressType targetLocation;
|
|
codeSegmentHeaderType *codeSegment;
|
|
|
|
reserveReservations();
|
|
removeZeroPageFromFreeList();
|
|
for (inputFileList = objectFileList; inputFileList != NULL;
|
|
inputFileList = inputFileList->nextObjectFile) {
|
|
if (inputFileList->name != NULL) {
|
|
currentFileName = inputFileList->name;
|
|
if (verbose)
|
|
printf("%s:\n", inputFileList->name);
|
|
for (codeSegment = inputFileList->codeSegments; codeSegment !=
|
|
NULL; codeSegment = codeSegment->nextSegment) {
|
|
if (codeSegment->segmentMode == MODE_RELOCATABLE) {
|
|
if ((targetLocation=allocateRelocatable(codeSegment))
|
|
== (addressType) -1) {
|
|
error(NO_PLACE_TO_PUT_CODE_SEGMENT_ERROR,
|
|
codeSegment->segmentStartAddress,
|
|
inputFileList->name);
|
|
} else {
|
|
relocateOneCodeSegment(codeSegment,
|
|
targetLocation);
|
|
}
|
|
}
|
|
}
|
|
} else { /* null name encodes new relocation base */
|
|
moveRelocationBase(inputFileList->symbolCount);
|
|
}
|
|
}
|
|
}
|
|
|
|
codeSegmentHeaderType *
|
|
matchModes(symbolType *symbol, codeSegmentHeaderType *codeSegment)
|
|
{
|
|
while (codeSegment!=NULL && ((codeSegment->segmentMode==MODE_ABSOLUTE
|
|
&& !(symbol->symbolClass & SYMBOL_ABSOLUTE)) ||
|
|
(codeSegment->segmentMode==MODE_RELOCATABLE &&
|
|
!(symbol->symbolClass & SYMBOL_RELOCATABLE) &&
|
|
!(symbol->symbolClass & SYMBOL_ABSOLUTE))))
|
|
codeSegment = codeSegment->nextSegment;
|
|
return(codeSegment);
|
|
}
|
|
|
|
bool
|
|
matchedModes(symbolType *symbol, codeSegmentHeaderType *codeSegment)
|
|
{
|
|
return(((symbol->symbolClass & SYMBOL_ABSOLUTE) && codeSegment->
|
|
segmentMode == MODE_ABSOLUTE) || ((symbol->symbolClass &
|
|
SYMBOL_RELOCATABLE) && codeSegment->segmentMode ==
|
|
MODE_RELOCATABLE));
|
|
}
|
|
|
|
codeSegmentHeaderType *
|
|
synchronizeCodeSegment(symbolType *symbol, codeSegmentHeaderType *codeSegment)
|
|
{
|
|
codeSegment = matchModes(symbol, codeSegment);
|
|
while (codeSegment != NULL && codeSegment->nextSegment != NULL &&
|
|
codeSegment->segmentEndAddress - codeSegment->
|
|
relocationOffset < symbol->symbolValue &&
|
|
matchedModes(symbol, codeSegment)) {
|
|
codeSegment = codeSegment->nextSegment;
|
|
}
|
|
return(codeSegment);
|
|
}
|
|
|
|
void
|
|
handleGlobalSymbol(symbolType *symbol)
|
|
{
|
|
}
|
|
|
|
void
|
|
valueSymbol(symbolType *symbol, codeSegmentHeaderType *codeSegment)
|
|
{
|
|
if (symbol->symbolClass & SYMBOL_ABSOLUTE) {
|
|
return;
|
|
} else if (symbol->symbolClass & SYMBOL_RELOCATABLE) {
|
|
symbol->symbolValue += codeSegment->relocationOffset;
|
|
} else {
|
|
printf("Super botcho! Undefined symbol in ValueSymbol.\n");
|
|
}
|
|
}
|
|
|
|
symbolType *
|
|
lookupGlobalSymbol(char *symbolName)
|
|
{
|
|
int guess;
|
|
int top;
|
|
int bottom;
|
|
int compare;
|
|
int oldTop;
|
|
int oldBottom;
|
|
|
|
top = oldBottom = globalSymbolCount;
|
|
bottom = oldTop = 0;
|
|
while (top != bottom && top != oldTop && bottom != oldBottom) {
|
|
guess = (top + bottom) >> 1;
|
|
compare = strcmplc(globalSymbolTable[guess]->symbolName,
|
|
symbolName);
|
|
if (compare == 0)
|
|
return(globalSymbolTable[guess]);
|
|
else if (compare < 0) {
|
|
oldBottom = bottom;
|
|
bottom = guess;
|
|
} else {
|
|
oldTop = top;
|
|
top = guess;
|
|
}
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
void
|
|
valueUndefinedSymbol(symbolType *symbol)
|
|
{
|
|
symbolType *globalSymbol;
|
|
|
|
if ((globalSymbol = lookupGlobalSymbol(symbol->symbolName)) == NULL) {
|
|
error(UNDEFINED_SYMBOL_ERROR, symbol->symbolName);
|
|
} else {
|
|
symbol->symbolClass = globalSymbol->symbolClass;
|
|
symbol->symbolValue = globalSymbol->symbolValue;
|
|
}
|
|
}
|
|
|
|
void
|
|
valuem(void)
|
|
{
|
|
objectFileListType *inputFileList;
|
|
codeSegmentHeaderType *codeSegmentPtr;
|
|
symbolType *symbolPtr;
|
|
int symbolCount;
|
|
|
|
totalSymbolCount = 0;
|
|
for (inputFileList = objectFileList; inputFileList != NULL;
|
|
inputFileList = inputFileList->nextObjectFile) {
|
|
if (inputFileList->name != NULL) {
|
|
currentFileName = inputFileList->name;
|
|
if (debug)
|
|
printf("\nSymbols with values (%s):\n", inputFileList->
|
|
name);
|
|
codeSegmentPtr = inputFileList->codeSegments;
|
|
for (symbolCount = 0; symbolCount<inputFileList->symbolCount;
|
|
symbolCount++) {
|
|
symbolPtr = inputFileList->symbolTable[symbolCount];
|
|
if (isUndefined(symbolPtr)) {
|
|
/* inputFileList->undefinedSymbols = symbolPtr;*/
|
|
inputFileList->undefinedSymbols = &(inputFileList->symbolTable[symbolCount]);
|
|
break;
|
|
}
|
|
codeSegmentPtr = synchronizeCodeSegment(symbolPtr,
|
|
codeSegmentPtr);
|
|
valueSymbol(symbolPtr, codeSegmentPtr);
|
|
if (debug)
|
|
printSymbol(symbolCount, symbolPtr);
|
|
}
|
|
inputFileList->baseSymbolCount = symbolCount;
|
|
inputFileList->symbolCount -= symbolCount;
|
|
}
|
|
}
|
|
|
|
for (inputFileList = objectFileList; inputFileList != NULL;
|
|
inputFileList = inputFileList->nextObjectFile) {
|
|
if (inputFileList->name != NULL) {
|
|
currentFileName = inputFileList->name;
|
|
if (debug)
|
|
printf("\nGlobal symbols with values (%s):\n",
|
|
inputFileList->name);
|
|
for (symbolCount = 0; symbolCount <inputFileList->symbolCount;
|
|
symbolCount++) {
|
|
symbolPtr = inputFileList->undefinedSymbols[symbolCount];
|
|
valueUndefinedSymbol(symbolPtr);
|
|
if (debug)
|
|
printSymbol(symbolCount, symbolPtr);
|
|
}
|
|
inputFileList->symbolCount = inputFileList->baseSymbolCount;
|
|
totalSymbolCount += inputFileList->baseSymbolCount;
|
|
}
|
|
}
|
|
if (debug)
|
|
printf("\nTotal symbol count = %d\n", totalSymbolCount);
|
|
if (produceLoadMap)
|
|
outputLoadMap();
|
|
}
|