macross/slinky/relocate.c
Michael Martin 693c15a2a8 Protoize.
2016-01-23 23:13:44 -08:00

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();
}