mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6121 lines
173 KiB
6121 lines
173 KiB
/***********************************************************************
|
|
* Microsoft (R) 32-Bit Incremental Linker
|
|
*
|
|
* Copyright (C) Microsoft Corp 1992-1996. All rights reserved.
|
|
*
|
|
* File: mppc.cpp
|
|
*
|
|
* File Comments:
|
|
*
|
|
* Code specific to PowerMac images
|
|
*
|
|
***********************************************************************/
|
|
|
|
#include "link.h"
|
|
|
|
BOOL fPowerMacBuildShared;
|
|
|
|
BYTE mppc_numOfCodeFrag;
|
|
DWORD mppc_numTocEntries;
|
|
LONG mppc_numDescriptors;
|
|
DWORD mppc_numRelocations;
|
|
DWORD mppc_baseOfInitData;
|
|
DWORD mppc_baseOfCode;
|
|
PCON pconTocTable;
|
|
PCON pconMppcFuncTable;
|
|
PCON pconTocDescriptors;
|
|
PCON pconGlueCode;
|
|
PCON pconPowerMacLoader;
|
|
BOOL fPowerMac;
|
|
|
|
static union {
|
|
BOOL fEHfuncXToc;
|
|
IMPORT_INFO *pFrameHandler;
|
|
};
|
|
|
|
static DWORD cRelocsAdded = 0;
|
|
|
|
#define INSTR_SIZE 4
|
|
#define GLUE_GROUP_NAME ".text$_glue"
|
|
#define FUNC_TABLE_TOC_INDEX 16 // C++ Exception Handling
|
|
|
|
|
|
struct OLDCROSSTOCGLUE {
|
|
DWORD loadProcDesc; // lwz R12,off(R2)
|
|
DWORD loadProcEntry; // lwz R0, 0(R12)
|
|
DWORD saveCallersTOC; // stw R2, 20(R1)
|
|
DWORD moveToCTR; // mtctr R0
|
|
DWORD loadProcsTOC; // lwz R2, 4(R12)
|
|
DWORD jumpThruCTR; // bctr
|
|
}
|
|
OldCrossTocGlue = { 0x81820000, // Set at run time
|
|
0x800c0000,
|
|
0x90410014,
|
|
0x7c0903a6,
|
|
0x804c0004,
|
|
0x4e800420 };
|
|
|
|
struct NEWCROSSTOCGLUE {
|
|
DWORD loadProcDesc; // lwz R12,off(R2)
|
|
DWORD jumpToExt; // branch without setting lnk register
|
|
}
|
|
NewCrossTocGlue;
|
|
|
|
|
|
struct CROSSTOCGLUEEXTENSION {
|
|
DWORD loadProcEntry; // lwz R0, 0(R12)
|
|
DWORD saveCallersTOC; // stw R2, 20(R1)
|
|
DWORD moveToCTR; // mtctr R0
|
|
DWORD loadProcsTOC; // lwz R2, 4(R12)
|
|
DWORD jumpThruCTR; // bctr
|
|
}
|
|
crossTocGlueExtension = { 0x800c0000,
|
|
0x90410014,
|
|
0x7c0903a6,
|
|
0x804c0004,
|
|
0x4e800420 };
|
|
|
|
struct INDIRECTCALLGLUE {
|
|
DWORD loadEntryPoint; // lwz R0, 0(R12)
|
|
DWORD saveCallersTOC; // stw R2, 20(R1)
|
|
DWORD moveToCTR; // mtctr R0
|
|
DWORD loadProcsTOC; // lwz R2, 4(R12)
|
|
// The environment ptr is not loaded because
|
|
// R12 should point to the transition vector
|
|
// DWORD loadEnvPtr; // lwz R12, 8(R12)
|
|
DWORD jumpThruCTR; // bctr
|
|
}
|
|
indirectCallGlue = { 0x800c0000,
|
|
0x90410014,
|
|
0x7c0903a6,
|
|
0x804c0004,
|
|
// 0x818c0008,
|
|
0x4e800420 };
|
|
|
|
struct HASH_INFO_TABLE {
|
|
CHAR name[EXPORT_NAMESZ];
|
|
HASH_WORD hashWord;
|
|
PEXTERNAL pextDot;
|
|
PEXTERNAL pext;
|
|
BOOL fDotExtern;
|
|
struct HASH_INFO_TABLE *next;
|
|
};
|
|
|
|
struct FTINFO {
|
|
unsigned long dwMagicNumber; // magic number
|
|
void *pFrameInfo; // pointer to runtime frame info(set to NULL)
|
|
unsigned long rgFuncTable; // pointer to function table
|
|
unsigned long cbFuncTable; // number of function entry
|
|
unsigned long dwEntryCF; // address of starting of the code fragment
|
|
unsigned long dwSizeCF; // size of the code fragment
|
|
// The last four entries will become arrays as we do multiple code fragments
|
|
};
|
|
|
|
|
|
STATIC DWORD StringTableOffset;
|
|
STATIC DWORD numContainers;
|
|
STATIC DWORD containerNameOffset;
|
|
STATIC LONG nSymbolEnt;
|
|
STATIC DWORD curStringTableOffset;
|
|
STATIC DWORD curSymbolTableOffset;
|
|
STATIC DWORD relocationHeaderOffset;
|
|
STATIC LOADER_HEADER loaderHeader;
|
|
STATIC CONTAINER_LIST *pcontainerlistHead;
|
|
STATIC RELOCATION_INFO *curRelocTable;
|
|
STATIC RELOCATION_INFO *pRelocTable;
|
|
STATIC HASH_INFO_TABLE *ExportInfoTable;
|
|
STATIC DWORD ExportChainTableOffset;
|
|
STATIC DWORD ExportSymbolTableOffset;
|
|
STATIC INT UniqueNumber;
|
|
STATIC char exportFilename[_MAX_PATH];
|
|
|
|
STATIC DWORD WriteNameToStringTable(const char *name);
|
|
STATIC void SortPData(DWORD);
|
|
|
|
STATIC NUMBER_LIST CurrentVersionList;
|
|
STATIC NUMBER_LIST OldCodeVersionList;
|
|
STATIC NUMBER_LIST VerboseCurrentVersionList;
|
|
STATIC NUMBER_LIST VerboseOldCodeVersionList;
|
|
STATIC NUMBER_LIST VerboseOldAPIVersionList;
|
|
|
|
typedef struct
|
|
{
|
|
PSEC psec;
|
|
}
|
|
biasStructType;
|
|
|
|
STATIC biasStructType *biasInfo;
|
|
STATIC DWORD numSections;
|
|
|
|
#if DBG
|
|
|
|
void
|
|
KillDuplicateRelocs (
|
|
void
|
|
)
|
|
/* ++
|
|
There should not be any duplicate relocs
|
|
If there are some, this would kill it
|
|
++ */
|
|
{
|
|
DWORD i;
|
|
RELOCATION_INFO *curRelocTable = pRelocTable;
|
|
|
|
if (!cRelocsAdded) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < cRelocsAdded - 1; i++) {
|
|
if (curRelocTable->sectionOffset == (curRelocTable+1)->sectionOffset) {
|
|
assert(curRelocTable->sectionOffset == (curRelocTable+1)->sectionOffset);
|
|
curRelocTable->type = ILL_RELO;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
void
|
|
MppcSetExpFilename(
|
|
const char *szName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Save the export filename for later. exportFilename is a static.
|
|
|
|
Arguments:
|
|
name
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
strcpy(exportFilename, szName);
|
|
}
|
|
|
|
|
|
void
|
|
MppcWriteShlSection(
|
|
INT ExpFileHandle,
|
|
const char *dllName,
|
|
BYTE *RawData,
|
|
DWORD ibNamePtr,
|
|
DWORD NumNames,
|
|
DWORD pointerToRawData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Writes out the .ppcshl section on the creation of a dll
|
|
|
|
Arguments:
|
|
dllName
|
|
RawData - raw data from the .edata export directory
|
|
NamePtr
|
|
NumNames
|
|
pointerToRawData - ftell of the section about to write
|
|
pimage
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG i;
|
|
DWORD l;
|
|
SHL_HEADER header;
|
|
LONG offset;
|
|
DWORD *NamePtr = (DWORD *) (RawData + ibNamePtr);
|
|
|
|
// Build the shl header
|
|
|
|
offset = 0;
|
|
if (NumNames) {
|
|
for (i = '0'; i <= 'z'; i++) {
|
|
char *name;
|
|
|
|
name = (char *) RawData + NamePtr[offset];
|
|
|
|
/* skip over table entries that don't match the export */
|
|
while (*name != i) {
|
|
// -1 means no exports starting with this character
|
|
|
|
(header.mapTable[(i-'0')]).offset = -1;
|
|
(header.mapTable[(i-'0')]).size = 0;
|
|
|
|
i++;
|
|
if (i > 'z') {
|
|
// if we have already seen all of the characters we are thru
|
|
break;
|
|
}
|
|
}
|
|
|
|
header.mapTable[(i-'0')].offset = offset;
|
|
|
|
// Skip exports starting with the same character
|
|
|
|
while (*name == i) {
|
|
if (offset >= (LONG) NumNames-1) {
|
|
break;
|
|
}
|
|
|
|
name = (char *) RawData + NamePtr[++offset];
|
|
}
|
|
|
|
header.mapTable[(i-'0')].size = offset -
|
|
header.mapTable[(i-'0')].offset;
|
|
}
|
|
} else {
|
|
for (i = 0; i < MAPTABLE_SIZE; i++) {
|
|
header.mapTable[i].offset = -1;
|
|
header.mapTable[i].size = 0;
|
|
}
|
|
}
|
|
|
|
header.numberOfExports = NumNames;
|
|
header.version = CURRENT_SHL_SUPPORTED;
|
|
header.fileOffset = pointerToRawData;
|
|
|
|
strcpy(header.libName, dllName);
|
|
FileWrite(ExpFileHandle, &header, sizeof(SHL_HEADER));
|
|
|
|
for (l = 0; l < NumNames; l++) {
|
|
char temp[EXPORT_NAMESZ];
|
|
|
|
memset(temp, 0, EXPORT_NAMESZ);
|
|
strncpy(temp, (char *) RawData + NamePtr[l], EXPORT_NAMESZ);
|
|
|
|
FileWrite(ExpFileHandle, temp, EXPORT_NAMESZ);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
MppcSetInitRoutine(
|
|
PIMAGE pimage,
|
|
const char *szName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Store away the init routine name from the argument list to be
|
|
used later.
|
|
|
|
Arguments:
|
|
name
|
|
PIMAGE
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
pimage->SwitchInfo.szMacInit = (char *) Malloc(strlen(szName) + 3);
|
|
|
|
if (szName[0] != '?') {
|
|
strcpy(pimage->SwitchInfo.szMacInit, "_");
|
|
strcat(pimage->SwitchInfo.szMacInit, szName);
|
|
} else {
|
|
strcpy(pimage->SwitchInfo.szMacInit, szName);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
MppcSetTermRoutine(
|
|
PIMAGE pimage,
|
|
const char *szName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Store away the term routine name from the argument list to be
|
|
used later.
|
|
|
|
Arguments:
|
|
name
|
|
PIMAGE
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
pimage->SwitchInfo.szMacTerm = (char *) Malloc(strlen(szName) + 3);
|
|
|
|
if (szName[0] != '?') {
|
|
strcpy(pimage->SwitchInfo.szMacTerm,"_");
|
|
strcat(pimage->SwitchInfo.szMacTerm, szName);
|
|
} else {
|
|
strcpy(pimage->SwitchInfo.szMacTerm, szName);
|
|
}
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
AddRelocation(
|
|
DWORD ibSec,
|
|
BYTE type,
|
|
IMPORT_INFO *pimportinfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Adds to the relocation table linked list.
|
|
|
|
Arguments:
|
|
ibSec - section offset of the symbol
|
|
type - relocation type
|
|
isym
|
|
pimportinfo - if not null, crosstoc info for an import
|
|
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
assert(cRelocsAdded < mppc_numRelocations);
|
|
|
|
curRelocTable->sectionOffset = ibSec;
|
|
curRelocTable->type = (PPCRELOCTYPES) type;
|
|
curRelocTable->relocInstr.instr = 0;
|
|
curRelocTable->relocInstr.count = 0;
|
|
curRelocTable->pimportinfo = pimportinfo;
|
|
curRelocTable++;
|
|
cRelocsAdded++;
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
BuildRelocTables(
|
|
DWORD relocInstrTableOffset
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Writes the relocation header into the loader section.
|
|
Determines the relocation instructions and writes the relocations
|
|
into the loader section. These relocation instruction are not the
|
|
final instruction in the PPC PEF file. More construction takes
|
|
place in the makepef phase.
|
|
|
|
Arguments:
|
|
relocInstrTableOffset
|
|
Pointer to image
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD i;
|
|
|
|
// Create and write out the relocation table
|
|
|
|
FileSeek(FileWriteHandle,
|
|
pconPowerMacLoader->foRawDataDest + relocInstrTableOffset,
|
|
SEEK_SET);
|
|
|
|
curRelocTable = pRelocTable;
|
|
|
|
DWORD crelocEmit = 0;
|
|
|
|
for (i = 0; i < cRelocsAdded; i++, curRelocTable++) {
|
|
DWORD sOffset = curRelocTable->sectionOffset;
|
|
DWORD opcode;
|
|
DWORD count = 1;
|
|
|
|
switch (curRelocTable->type) {
|
|
case DDAT_RELO :
|
|
opcode = opDDAT | OFFSET(sOffset);
|
|
|
|
// Absorb the rest of the DDAT's if possible.
|
|
|
|
if (!fINCR) {
|
|
// There is a limit of 0x3F since this is all that
|
|
// the PEF DDAT relocation will support
|
|
|
|
while (count < 0x3F) {
|
|
if (i >= (cRelocsAdded - 1)) {
|
|
// There are no further relocations
|
|
|
|
break;
|
|
}
|
|
|
|
if (curRelocTable[1].type != DDAT_RELO) {
|
|
// The next relocation isn't a DDAT
|
|
|
|
break;
|
|
}
|
|
|
|
DWORD nOffset = curRelocTable[1].sectionOffset;
|
|
|
|
if (nOffset != (sOffset + sizeof(DWORD))) {
|
|
// The next relocation doesn't immediately follow this one
|
|
|
|
break;
|
|
}
|
|
|
|
count++;
|
|
sOffset = nOffset;
|
|
|
|
i++;
|
|
curRelocTable++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DESC_RELO :
|
|
opcode = opDESC | OFFSET(sOffset);
|
|
break;
|
|
|
|
case SYMB_RELO :
|
|
opcode = opSYMB | OFFSET(sOffset);
|
|
count = curRelocTable->pimportinfo->order;
|
|
break;
|
|
|
|
case CODE_RELO :
|
|
opcode = opCODE | OFFSET(sOffset);
|
|
break;
|
|
}
|
|
|
|
curRelocTable->relocInstr.instr = opcode;
|
|
curRelocTable->relocInstr.count = count;
|
|
|
|
FileWrite(FileWriteHandle, &curRelocTable->relocInstr, sizeof(RELOCATION_INSTR));
|
|
|
|
crelocEmit++;
|
|
}
|
|
|
|
RELOCATION_HEADER relocHeader;
|
|
|
|
relocHeader.sectionNumber = WSwap(PPC_PEF_DATA_SECTION);
|
|
relocHeader.reserved = 0;;
|
|
relocHeader.nbrOfRelocs = DwSwap(crelocEmit);
|
|
relocHeader.firstRelocInstr = 0;
|
|
|
|
// Write the relocation header
|
|
|
|
FileSeek(FileWriteHandle,
|
|
pconPowerMacLoader->foRawDataDest + relocationHeaderOffset,
|
|
SEEK_SET);
|
|
|
|
FileWrite(FileWriteHandle, &relocHeader, sizeof(RELOCATION_HEADER));
|
|
}
|
|
|
|
|
|
STATIC
|
|
INT
|
|
__cdecl
|
|
PpcCompareReloc(
|
|
const void *R1,
|
|
const void *R2
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Used by qsort to compare relocation offsets within the relocation
|
|
table.
|
|
|
|
Arguments:
|
|
R1, R2 - two elements in the relocation table to be compared.
|
|
|
|
Return Value:
|
|
-1 (less than), 1 (greater than) or 0 (equal)
|
|
|
|
--*/
|
|
|
|
{
|
|
RELOCATION_INFO *r1 = (RELOCATION_INFO *) R1;
|
|
RELOCATION_INFO *r2 = (RELOCATION_INFO *) R2;
|
|
|
|
if (r1->sectionOffset < r2->sectionOffset) {
|
|
return(-1);
|
|
}
|
|
|
|
if (r1->sectionOffset > r2->sectionOffset) {
|
|
return(1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
#define AvgChainSize 10
|
|
|
|
#define HashSlot(h,S,M) (((h)^((h)>>(S)))&(DWORD)(M))
|
|
#define ROTL(x) (((x)<<1)-((x)>>(16)))
|
|
|
|
|
|
INT
|
|
NumSlotBits(
|
|
LONG exportCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Determines the number of slot bits neccessary for the number
|
|
of exports.
|
|
|
|
Arguments:
|
|
exportCount
|
|
|
|
Return Value:
|
|
number of slot bits.
|
|
|
|
--*/
|
|
|
|
{
|
|
INT i;
|
|
|
|
for (i = 0; i < 13; i++) {
|
|
if (exportCount / (1<<i) < AvgChainSize) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( i < 10) {
|
|
return i+1;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
STATIC
|
|
HASH
|
|
Hash(
|
|
const char *name,
|
|
INT length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Apples PPC hashing function.
|
|
|
|
Arguments:
|
|
name
|
|
length
|
|
|
|
Return Value:
|
|
the hash value in the lower 16 bits and the length in the upper.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG hash = 0;
|
|
INT len = 0;
|
|
|
|
while (*name != '\0') {
|
|
hash = ROTL(hash);
|
|
hash ^= (BYTE) *name++;
|
|
|
|
len++;
|
|
|
|
if (--length == 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (unsigned short) (hash ^ (hash >> 16)) + (len << 16);
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
AddImportToContainerList(
|
|
PIMAGE pimage,
|
|
CONTAINER_LIST *pcontainerlistCur,
|
|
IMPORT_INFO *pimportinfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Create an import list for each import library (container).
|
|
|
|
Arguments:
|
|
pcontainerlistCur
|
|
pimportinfo
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
// Add to end of list of imports for this container
|
|
|
|
IMPORT_INFO **ppimportinfoPrev = &pcontainerlistCur->pimportinfoHead;
|
|
|
|
while (*ppimportinfoPrev != NULL) {
|
|
ppimportinfoPrev = &(*ppimportinfoPrev)->pimportinfoNext;
|
|
}
|
|
|
|
*ppimportinfoPrev = pimportinfo;
|
|
pimportinfo->pimportinfoNext = NULL;
|
|
|
|
// Count the length of the loader string table
|
|
|
|
const char *szName = SzNamePext(pimportinfo->pext, pimage->pst);
|
|
|
|
if (szName[0] == '_') {
|
|
szName++;
|
|
}
|
|
|
|
curStringTableOffset += strlen(szName) + 1;
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
AddContainerInfo(
|
|
PIMAGE pimage,
|
|
const char *szContainerName,
|
|
IMPORT_INFO *pimportinfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Given an import check for a container that already has it or
|
|
create a new container adding that import.
|
|
|
|
Arguments:
|
|
pimportinfo
|
|
|
|
--*/
|
|
{
|
|
|
|
CONTAINER_LIST **ppcontainerlistCur = &pcontainerlistHead;
|
|
|
|
while (*ppcontainerlistCur != NULL) {
|
|
if (!strcmp((*ppcontainerlistCur)->szName, szContainerName)) {
|
|
break;
|
|
}
|
|
|
|
ppcontainerlistCur = &(*ppcontainerlistCur)->pcontainerlistNext;
|
|
}
|
|
|
|
CONTAINER_LIST *pcontainerlistCur = *ppcontainerlistCur;
|
|
|
|
if (pcontainerlistCur == NULL) {
|
|
// No matching container exists. Allocate a new one.
|
|
|
|
CONTAINER_TABLE *pcontainertable = (CONTAINER_TABLE *) Calloc(1, sizeof(CONTAINER_TABLE));
|
|
|
|
pcontainerlistCur = (CONTAINER_LIST *) Calloc(1, sizeof(CONTAINER_LIST));
|
|
|
|
pcontainerlistCur->szName = Strdup(szContainerName);
|
|
pcontainerlistCur->header = pcontainertable;
|
|
|
|
// Add to the end of the list
|
|
|
|
*ppcontainerlistCur = pcontainerlistCur;
|
|
|
|
numContainers++;
|
|
|
|
// Count the strings for the loader string table
|
|
|
|
containerNameOffset += strlen(pcontainerlistCur->szName) + 1;
|
|
}
|
|
|
|
|
|
pcontainerlistCur->header->nbrOfImports++;
|
|
|
|
AddImportToContainerList(pimage, pcontainerlistCur, pimportinfo);
|
|
|
|
// Count the unique symbols relocated on
|
|
|
|
nSymbolEnt++;
|
|
}
|
|
|
|
|
|
void
|
|
AssignDescriptorsPcon(
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Loop thru all external symbols calling UpdateExternalSymbol
|
|
|
|
Arguments:
|
|
pimage
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PST pst = pimage->pst;
|
|
|
|
DWORD cext = Cexternal(pst);
|
|
|
|
InitEnumerateExternals(pst);
|
|
|
|
for (DWORD iext = 0; iext < cext; iext++) {
|
|
EXTERNAL *pext = PexternalEnumerateNext(pst);
|
|
|
|
if (READ_BIT(pext, sy_TOCDESCRREL)) {
|
|
UpdateExternalSymbol(pext,
|
|
pconTocDescriptors,
|
|
pext->ImageSymbol.Value,
|
|
IMAGE_SYM_DEBUG,
|
|
IMAGE_SYM_TYPE_NULL,
|
|
0,
|
|
pmodLinkerDefined,
|
|
pst);
|
|
}
|
|
}
|
|
|
|
TerminateEnumerateExternals(pst);
|
|
}
|
|
|
|
|
|
void
|
|
MppcPass2Descriptors(
|
|
PIMAGE pimage
|
|
)
|
|
{
|
|
PST pst = pimage->pst;
|
|
|
|
DWORD cext = Cexternal(pst);
|
|
|
|
InitEnumerateExternals(pst);
|
|
|
|
for (DWORD iext = 0; iext < cext; iext++) {
|
|
EXTERNAL *pext = PexternalEnumerateNext(pst);
|
|
|
|
if (READ_BIT(pext, sy_TOCDESCRREL)) {
|
|
PSEC psec = PsecPCON(pext->pcon);
|
|
|
|
assert(pext->pcon == pconTocDescriptors);
|
|
|
|
// Update FinalValue so that the .MAP file has the correct order
|
|
|
|
pext->FinalValue = pext->pcon->rva + pext->ImageSymbol.Value;
|
|
|
|
if (fPdb) {
|
|
DBG_AddPublicDBI(SzNamePext(pext, pst),
|
|
psec->isec,
|
|
pext->FinalValue - psec->rva);
|
|
}
|
|
}
|
|
}
|
|
|
|
TerminateEnumerateExternals(pst);
|
|
}
|
|
|
|
|
|
STATIC
|
|
char *
|
|
GenerateUniqueName(
|
|
char *dotName,
|
|
const char *szName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Used to create unique names for static functions.
|
|
|
|
Arguments:
|
|
dotName
|
|
name
|
|
|
|
Return Value:
|
|
unique name (name001 etc.)
|
|
|
|
--*/
|
|
{
|
|
sprintf(dotName, "%s%03d", szName, UniqueNumber++);
|
|
|
|
return(dotName);
|
|
}
|
|
|
|
|
|
PEXTERNAL
|
|
CreateDescriptor(
|
|
const char *szName,
|
|
PCON pcon,
|
|
PIMAGE pimage,
|
|
BOOL fStaticFunction
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Create a procedure descriptor for a function,
|
|
usually due to an address of a function taken.
|
|
And one for the entry point routine.
|
|
|
|
Return Value:
|
|
The new dot extern symbol
|
|
|
|
--*/
|
|
{
|
|
char *szDotName = (char *) PvAlloc(strlen(szName) + 7);
|
|
// The extra ones are for generating unique names
|
|
strcpy(szDotName, ".");
|
|
strcat(szDotName, szName);
|
|
|
|
PEXTERNAL pextDot = LookupExternSz(pimage->pst, szDotName, NULL);
|
|
|
|
if (fStaticFunction) {
|
|
// Static Functions have the compiler-created descriptors
|
|
// (prepended by the period) in the external symbol table.
|
|
// These symbols were being resolved at the end of Pass1
|
|
// in the function FindMatchingExportByName. But it makes
|
|
// sense to set them defined right now so that we don't need
|
|
// to deal with it at the end of Pass1.
|
|
|
|
SetDefinedExt(pextDot, TRUE, pimage->pst);
|
|
|
|
assert(pcon != NULL);
|
|
pextDot->pcon = pcon;
|
|
|
|
szDotName = GenerateUniqueName(szDotName, szName);
|
|
pextDot = LookupExternSz(pimage->pst, szDotName, NULL);
|
|
}
|
|
|
|
if (!READ_BIT(pextDot, sy_TOCDESCRREL) &&
|
|
!READ_BIT(pextDot, sy_DESCRRELCREATED)) {
|
|
SetDefinedExt(pextDot, TRUE, pimage->pst);
|
|
pextDot->ImageSymbol.Value = mppc_numDescriptors * 12;
|
|
pextDot->ImageSymbol.SectionNumber = IMAGE_SYM_DEBUG;
|
|
|
|
mppc_numDescriptors++;
|
|
mppc_numRelocations++;
|
|
|
|
crelocTotal += 2;
|
|
|
|
SET_BIT(pextDot, sy_TOCDESCRREL);
|
|
}
|
|
|
|
SET_BIT(pextDot, sy_DESCRRELCREATED);
|
|
|
|
FreePv(szDotName);
|
|
|
|
return(pextDot);
|
|
}
|
|
|
|
|
|
void
|
|
CreateEntryInitTermDescriptors(
|
|
PPEXTERNAL ppextEntry,
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Create procedure descriptors for the init term and entry routines.
|
|
The logic is as follows. For exes, you can have all ENTRY, INIT, and
|
|
TERM routines, but only INIT and TERM make sense for DLLs. However,
|
|
there is only ENTRY and no INIT for I386 DLLs. Hence to stay compatible
|
|
with the intel platform, the ENTRY is mapped on to INIT for PowerMac
|
|
DLLs. If both ENRTY and INIT are specified when building DLLs, then
|
|
both of them are set. - ShankarV
|
|
|
|
--*/
|
|
|
|
{
|
|
const char *szName =
|
|
(*ppextEntry ? SzNamePext(*ppextEntry, pimage->pst) : NULL);
|
|
|
|
AllowInserts(pimage->pst);
|
|
|
|
if (fPowerMacBuildShared) {
|
|
// This is a DLL (Shared Library)
|
|
|
|
if (pimage->SwitchInfo.szMacInit == NULL) {
|
|
if (*ppextEntry != NULL) {
|
|
// Entry is mapped on to init. Now entry can be ignored
|
|
|
|
pimage->SwitchInfo.szMacInit = Strdup(szName);
|
|
*ppextEntry = NULL;
|
|
Warning(NULL, MACDLLENTRYMAPPEDTOINIT);
|
|
} else {
|
|
pimage->SwitchInfo.szMacInit = Strdup("__DllMainCRTStartup");
|
|
}
|
|
}
|
|
|
|
if (pimage->SwitchInfo.szMacTerm == NULL) {
|
|
pimage->SwitchInfo.szMacTerm = Strdup("__DllMainCRTExit");
|
|
}
|
|
|
|
}
|
|
|
|
if (*ppextEntry && !READ_BIT(*ppextEntry, sy_DESCRRELCREATED)) {
|
|
// UNDONE: Why is mppc_numRelocations incremented?
|
|
|
|
mppc_numRelocations++;
|
|
|
|
CreateDescriptor(szName, (*ppextEntry)->pcon, pimage, FALSE);
|
|
|
|
SET_BIT(*ppextEntry, sy_DESCRRELCREATED);
|
|
}
|
|
|
|
if (pimage->SwitchInfo.szMacInit != NULL) {
|
|
// Create a new external symbol for init routine
|
|
|
|
PEXTERNAL pextInit = LookupExternSz(pimage->pst, pimage->SwitchInfo.szMacInit, NULL);
|
|
|
|
if (!READ_BIT(pextInit, sy_DESCRRELCREATED)) {
|
|
szName = SzNamePext(pextInit, pimage->pst);
|
|
|
|
// UNDONE: Why is mppc_numRelocations incremented?
|
|
|
|
mppc_numRelocations++;
|
|
|
|
CreateDescriptor(szName, pextInit->pcon, pimage, FALSE);
|
|
|
|
SET_BIT(pextInit, sy_DESCRRELCREATED);
|
|
}
|
|
|
|
if (pimage->Switch.Link.fTCE) {
|
|
PentNew_TCE(NULL, pextInit, NULL, &pentHeadImage);
|
|
}
|
|
}
|
|
|
|
if (pimage->SwitchInfo.szMacTerm != NULL) {
|
|
// Create a new external symbol for term routine
|
|
|
|
PEXTERNAL pextTerm = LookupExternSz(pimage->pst, pimage->SwitchInfo.szMacTerm, NULL);
|
|
|
|
if (!READ_BIT(pextTerm, sy_DESCRRELCREATED)) {
|
|
szName = SzNamePext(pextTerm, pimage->pst);
|
|
|
|
// UNDONE: Why is mppc_numRelocations incremented?
|
|
|
|
mppc_numRelocations++;
|
|
|
|
CreateDescriptor(szName, pextTerm->pcon, pimage, FALSE);
|
|
|
|
SET_BIT(pextTerm, sy_DESCRRELCREATED);
|
|
}
|
|
|
|
if (pimage->Switch.Link.fTCE) {
|
|
PentNew_TCE(NULL, pextTerm, NULL, &pentHeadImage);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
MppcCreatePconDescriptors(
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Create the pcon for the procedure descriptors.
|
|
|
|
Arguments:
|
|
pimage
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD cb;
|
|
DWORD cbPad;
|
|
|
|
// Procedure descriptors are 3 dwords long
|
|
|
|
cb = mppc_numDescriptors * 12;
|
|
|
|
cbPad = (fINCR ? __min((WORD) cb, (USHRT_MAX / 12) * 12) : 0);
|
|
cb += cbPad;
|
|
|
|
pconTocDescriptors = PconNew(ReservedSection.Data.Name,
|
|
cb,
|
|
0,
|
|
ReservedSection.Data.Characteristics,
|
|
pmodLinkerDefined,
|
|
&pimage->secs, pimage);
|
|
|
|
pconTocDescriptors->cbPad = cbPad;
|
|
|
|
if (pimage->Switch.Link.fTCE) {
|
|
InitNodPcon(pconTocDescriptors, NULL, TRUE);
|
|
}
|
|
|
|
AssignDescriptorsPcon(pimage);
|
|
}
|
|
|
|
|
|
void
|
|
MppcCreatePconTocTable(
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Create the pcon for the TOC table.
|
|
|
|
Arguments:
|
|
pimage
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD cbToc;
|
|
DWORD cbTocPad = 0;
|
|
|
|
cbToc = mppc_numTocEntries * sizeof(DWORD);
|
|
|
|
/* create some pad size so if there is nothing in the toc table */
|
|
/* it won't be removed by the linker. */
|
|
|
|
cbTocPad = fINCR ? __min((WORD) cbToc, USHRT_MAX) : sizeof(DWORD);
|
|
cbToc += cbTocPad;
|
|
|
|
pconTocTable = PconNew(ReservedSection.Data.Name,
|
|
cbToc,
|
|
IMAGE_SCN_CNT_INITIALIZED_DATA |
|
|
IMAGE_SCN_MEM_READ |
|
|
IMAGE_SCN_ALIGN_4BYTES,
|
|
ReservedSection.Data.Characteristics,
|
|
pmodLinkerDefined,
|
|
&pimage->secs, pimage);
|
|
|
|
pconTocTable->cbPad = cbTocPad;
|
|
|
|
if (pimage->Switch.Link.fTCE) {
|
|
InitNodPcon(pconTocTable, NULL, TRUE);
|
|
}
|
|
|
|
UpdateExternalSymbol(pextToc,
|
|
pconTocTable,
|
|
MPPC_TOC_BIAS,
|
|
IMAGE_SYM_DEBUG,
|
|
IMAGE_SYM_TYPE_NULL,
|
|
0,
|
|
pmodLinkerDefined,
|
|
pimage->pst);
|
|
}
|
|
|
|
|
|
void
|
|
MppcCreatePconCxxEHFunctionTable(
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Create the pcon for the C++ Exception Handling Function table.
|
|
|
|
Arguments:
|
|
pimage
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
// Refer FTINFO struture for the actual size
|
|
|
|
DWORD cbFTInfo = 2 * sizeof(DWORD) + 4 * sizeof(DWORD) * mppc_numOfCodeFrag;
|
|
|
|
// UNDONE: Do we need some pad here?
|
|
|
|
pconMppcFuncTable = PconNew(ReservedSection.Data.Name,
|
|
cbFTInfo,
|
|
IMAGE_SCN_CNT_INITIALIZED_DATA |
|
|
IMAGE_SCN_MEM_READ |
|
|
IMAGE_SCN_ALIGN_4BYTES,
|
|
ReservedSection.Data.Characteristics,
|
|
pmodLinkerDefined,
|
|
&pimage->secs, pimage);
|
|
|
|
if (pimage->Switch.Link.fTCE) {
|
|
InitNodPcon(pconMppcFuncTable, NULL, TRUE);
|
|
}
|
|
|
|
pextFTInfo->ibToc = (SHORT) (FUNC_TABLE_TOC_INDEX * sizeof(DWORD) - MPPC_TOC_BIAS);
|
|
|
|
SET_BIT(pextFTInfo, sy_TOCALLOCATED);
|
|
|
|
UpdateExternalSymbol(pextFTInfo,
|
|
pconMppcFuncTable,
|
|
0,
|
|
IMAGE_SYM_DEBUG,
|
|
IMAGE_SYM_TYPE_NULL,
|
|
0,
|
|
pmodLinkerDefined,
|
|
pimage->pst);
|
|
}
|
|
|
|
|
|
void
|
|
MppcCreatePconGlueCode(
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Create the contribution for the glue code. Code from this
|
|
section will be added to the group called GLUE_GROUP_NAME
|
|
(".text$_glue") in the .text section. This allows the glue
|
|
code group to be ordered, if needed.
|
|
|
|
Arguments:
|
|
pimage - needed for the PconNew()
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD cb;
|
|
DWORD cbPad;
|
|
|
|
if (pimage->Switch.Link.fNewGlue) {
|
|
cb = pimage->nUniqueCrossTocCalls * sizeof(NewCrossTocGlue) +
|
|
sizeof(indirectCallGlue) + sizeof(crossTocGlueExtension);
|
|
} else {
|
|
cb = pimage->nUniqueCrossTocCalls * sizeof(OldCrossTocGlue) +
|
|
sizeof(indirectCallGlue);
|
|
}
|
|
|
|
// Padding for incremental linking
|
|
|
|
cbPad = fINCR ? __min((WORD) cb, (USHRT_MAX >> 4) << 4) : 0;
|
|
cb += cbPad;
|
|
|
|
pconGlueCode = PconNew(GLUE_GROUP_NAME,
|
|
cb,
|
|
0,
|
|
ReservedSection.Text.Characteristics,
|
|
pmodLinkerDefined,
|
|
&pimage->secs, pimage);
|
|
|
|
pconGlueCode->cbPad = cbPad;
|
|
|
|
if (pimage->Switch.Link.fTCE) {
|
|
InitNodPcon(pconGlueCode, NULL, TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
STATIC
|
|
BOOL
|
|
FSeekToShlSection(
|
|
INT *exportHandle
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Seeks to the special .ppcshl section in the shared library.
|
|
Leaves the pointer in the file at the raw data of that section.
|
|
|
|
Arguments:
|
|
pointer to the handle
|
|
|
|
Return Value:
|
|
The handle for the file seeked to that position.
|
|
|
|
--*/
|
|
|
|
{
|
|
IMAGE_SECTION_HEADER secHeader;
|
|
|
|
if ( '\0' == *exportFilename ) {
|
|
return 0;
|
|
}
|
|
|
|
*exportHandle = FileOpen(exportFilename, O_RDONLY | O_BINARY, 0);
|
|
|
|
FileSeek(*exportHandle, sizeof(IMAGE_FILE_HEADER), SEEK_SET);
|
|
|
|
do
|
|
{
|
|
FileRead(*exportHandle, &secHeader, sizeof(IMAGE_SECTION_HEADER));
|
|
|
|
} while (strcmp((char *) secHeader.Name, ".ppcshl"));
|
|
|
|
FileSeek(*exportHandle, secHeader.PointerToRawData, SEEK_SET);
|
|
|
|
if (strcmp((char *) secHeader.Name, ".ppcshl")) {
|
|
return FALSE;
|
|
} else {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
AddToExportInfo(
|
|
PIMAGE pimage,
|
|
PEXTERNAL pext,
|
|
const char *szName,
|
|
INT numSlotBits
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Build an internal linked list of export symbol info. The
|
|
info is collected into a hash table of collisions link together.
|
|
this list is later written into the pef container.
|
|
|
|
Arguments:
|
|
pimage
|
|
pext
|
|
name of the export
|
|
numSlotBits total number of slots in the info table.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
size_t len;
|
|
DWORD hashWord;
|
|
DWORD slotNumber;
|
|
HASH_INFO_TABLE *current;
|
|
|
|
assert(pext != NULL);
|
|
|
|
// Remove the leading underscore
|
|
|
|
if (szName[0] == '_') {
|
|
szName++;
|
|
}
|
|
|
|
len = strlen(szName);
|
|
hashWord = Hash(szName, len);
|
|
slotNumber = HashSlot(hashWord, numSlotBits, ((1 << numSlotBits) - 1));
|
|
|
|
current = ExportInfoTable + slotNumber;
|
|
|
|
if (current->pext != NULL) {
|
|
// Found a collision
|
|
|
|
// Get to the end
|
|
|
|
while (current->next != NULL) {
|
|
current = current->next;
|
|
}
|
|
|
|
current->next = (HASH_INFO_TABLE *) PvAllocZ(sizeof(HASH_INFO_TABLE));
|
|
|
|
current = current->next;
|
|
}
|
|
|
|
strncpy(current->name, szName, EXPORT_NAMESZ);
|
|
current->hashWord = hashWord;
|
|
current->pext = pext;
|
|
|
|
// If the external symbol is a function create a routine descriptor
|
|
|
|
if (!READ_BIT(pext, sy_CROSSTOCCALL) && ISFCN(pext->ImageSymbol.Type)) {
|
|
PEXTERNAL pextDot;
|
|
|
|
assert(pext->pcon);
|
|
pextDot = CreateDescriptor(szName, pext->pcon, pimage, FALSE);
|
|
SET_BIT(pextDot, sy_ISDOTEXTERN);
|
|
|
|
current->fDotExtern = TRUE;
|
|
current->pextDot = pextDot;
|
|
}
|
|
|
|
// For now just count the name length for the string table
|
|
|
|
curStringTableOffset += len + 1;
|
|
}
|
|
|
|
|
|
STATIC
|
|
INT
|
|
BuildExportInfo(
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Main loop for building the export info table. This table contains
|
|
exports hashed into a table with a linked list of collisions.
|
|
|
|
Arguments:
|
|
pimage
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD numExports;
|
|
INT numSlotBits;
|
|
DWORD slotTableSize;
|
|
DWORD chainTableSize;
|
|
DWORD exportSymbolTableSize;
|
|
DWORD i;
|
|
INT exportHandle;
|
|
SHL_HEADER shlHeader;
|
|
|
|
if (!FSeekToShlSection(&exportHandle)) {
|
|
return(0);
|
|
}
|
|
|
|
FileRead(exportHandle, &shlHeader, sizeof(SHL_HEADER));
|
|
|
|
numExports = shlHeader.numberOfExports;
|
|
if (!numExports) {
|
|
Warning(NULL, MACNODLLEXPORTS, shlHeader.libName);
|
|
}
|
|
numSlotBits = NumSlotBits(numExports);
|
|
slotTableSize = (1 << numSlotBits);
|
|
chainTableSize = numExports * sizeof(HASH_CHAIN_TABLE);
|
|
exportSymbolTableSize = numExports * EXPORT_SYMBOL_TABLESZ;
|
|
ExportInfoTable = (HASH_INFO_TABLE *) PvAllocZ((slotTableSize+1)*sizeof(HASH_INFO_TABLE));
|
|
|
|
loaderHeader.hashSlotCount = numSlotBits;
|
|
loaderHeader.nExportedSymbols = numExports;
|
|
|
|
DBEXEC(DB_MPPC_EXPORTINFO,
|
|
printf("%d numSlotsBits %d num exports\n", numSlotBits, numExports));
|
|
|
|
AllowInserts(pimage->pst);
|
|
for (i = 0; i < numExports; i++) {
|
|
char szExportName[EXPORT_NAMESZ+1];
|
|
char *szExternalName = NULL;
|
|
PEXTERNAL pext;
|
|
|
|
FileRead(exportHandle, szExportName, EXPORT_NAMESZ);
|
|
szExportName[EXPORT_NAMESZ] = '\0';
|
|
|
|
// In the case of PowerMac, both the internal and the external (aliased) exported names
|
|
// are sent through the .ppcshl section with an exclamation mark between them. So look
|
|
// for the exclamation mark and identify the internal name first. Both the names are
|
|
// already decorated.
|
|
|
|
if ((szExternalName = strchr(szExportName, '!')) != NULL) {
|
|
*szExternalName = '\0';
|
|
}
|
|
|
|
pext = SearchExternSz(pimage->pst, szExportName);
|
|
assert(pext != NULL);
|
|
|
|
if (szExternalName != NULL) {
|
|
szExternalName++;
|
|
} else {
|
|
szExternalName = szExportName; // else make szExternalName point to szExportName
|
|
}
|
|
|
|
// PowerMac differs from Win32 in the following respect:
|
|
// On the Win32 side let's suppose a function named A is specified in the DEF file
|
|
// under EXPORTS whose actual symbol is decorated. This will cause the import library
|
|
// to have the decorated name, but the loader of the executable (.idata) will have
|
|
// the undecorated name. However, on the PowerMac side, the loader will still have the
|
|
// decorated name. PowerMac differs from Win32 also in the case where the exported
|
|
// symbol is aliased in the DEF file. - ShankarV
|
|
|
|
// UNDONE: Make PowerMac loader behave the same way as that of Win32 in the case of
|
|
// exported symbols whose internal names are decorated.
|
|
|
|
if (((pext->Flags & EXTERN_DEFINED) != 0) &&
|
|
(pext->ImageSymbol.SectionNumber != IMAGE_SYM_DEBUG)) {
|
|
|
|
AddToExportInfo(pimage, pext, szExternalName, numSlotBits);
|
|
|
|
if (pimage->Switch.Link.fTCE) {
|
|
PentNew_TCE(NULL, pext, NULL, &pentHeadImage);
|
|
}
|
|
}
|
|
}
|
|
|
|
FileClose(exportHandle, TRUE);
|
|
|
|
return(slotTableSize * sizeof(HASH_SLOT_TABLE)) + chainTableSize + exportSymbolTableSize;
|
|
}
|
|
|
|
|
|
DWORD
|
|
MppcCreatePconLoader(
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Create the Loader section (.ppcldr). This section holds the relocation instructions
|
|
for the runtime loader on the ppc.
|
|
Global variables curSymbolTableOffset, relocationHeaderOffset and
|
|
loaderHeader variables relocationTableOffset, stringTableOffset
|
|
are initialized.
|
|
|
|
Arguments:
|
|
pimage - required for the PconNew call.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD loaderHeaderOffset;
|
|
DWORD sizeOfLoaderHeader = 0;
|
|
DWORD sizeOfContainerTable;
|
|
DWORD sizeOfImportSymbolTable = 0;
|
|
DWORD sizeOfRelocationTable = 0;
|
|
DWORD sizeOfRelocationHeader = 0;
|
|
DWORD sizeOfStringTable = 0;
|
|
DWORD sizeOfExportTables = 0;
|
|
DWORD totalSizeOfLoaderSection = 0;
|
|
DWORD importSymbolTableOffset;
|
|
DWORD containerTableOffset;
|
|
DWORD cbRelocTablePad = 0;
|
|
|
|
loaderHeaderOffset = 0; /* first item in the loader section */
|
|
sizeOfLoaderHeader = sizeof(LOADER_HEADER);
|
|
|
|
containerTableOffset = loaderHeaderOffset + sizeOfLoaderHeader;
|
|
sizeOfContainerTable = numContainers * sizeof(CONTAINER_TABLE);
|
|
|
|
importSymbolTableOffset = containerTableOffset + sizeOfContainerTable;
|
|
sizeOfImportSymbolTable = nSymbolEnt * sizeof(IMPORT_TABLE);
|
|
|
|
/* initialize the first symbol in the import symbol table */
|
|
curSymbolTableOffset = importSymbolTableOffset;
|
|
|
|
/* BuildExportInfo must be called before calculating */
|
|
/* the string table size because it is also adding to the string */
|
|
/* table, must also be before calculating size of relocation tbl */
|
|
sizeOfExportTables = BuildExportInfo(pimage);
|
|
|
|
|
|
relocationHeaderOffset = importSymbolTableOffset + sizeOfImportSymbolTable;
|
|
sizeOfRelocationHeader = sizeof(RELOCATION_HEADER);
|
|
|
|
loaderHeader.relocTableOffset = relocationHeaderOffset +
|
|
sizeOfRelocationHeader;
|
|
|
|
pRelocTable = (RELOCATION_INFO *)
|
|
PvAllocZ((mppc_numRelocations + 1) * sizeof(RELOCATION_INFO));
|
|
|
|
curRelocTable = pRelocTable;
|
|
|
|
sizeOfRelocationTable = mppc_numRelocations * sizeof(RELOCATION_INSTR);
|
|
|
|
cbRelocTablePad = (fINCR ? __min((WORD)sizeOfRelocationTable,
|
|
(USHRT_MAX / sizeof(RELOCATION_INSTR)) * sizeof(RELOCATION_INSTR)) : 0);
|
|
sizeOfRelocationTable += cbRelocTablePad;
|
|
|
|
if (fINCR) {
|
|
MPPCInitPbri(&pimage->bri, relocationHeaderOffset,
|
|
loaderHeader.relocTableOffset, sizeOfRelocationTable);
|
|
}
|
|
|
|
loaderHeader.stringTableOffset = loaderHeader.relocTableOffset +
|
|
sizeOfRelocationTable;
|
|
|
|
// Reference the global since loaderHeader will be swapped later
|
|
|
|
StringTableOffset = loaderHeader.stringTableOffset;
|
|
|
|
sizeOfStringTable = containerNameOffset + curStringTableOffset + 2;
|
|
|
|
// Initalize the first string table entry to follow the container names
|
|
|
|
curStringTableOffset = containerNameOffset;
|
|
|
|
loaderHeader.hashSlotTableOffset = loaderHeader.stringTableOffset +
|
|
sizeOfStringTable;
|
|
|
|
totalSizeOfLoaderSection = sizeOfLoaderHeader +
|
|
sizeOfContainerTable +
|
|
sizeOfImportSymbolTable +
|
|
sizeOfRelocationHeader +
|
|
sizeOfRelocationTable +
|
|
sizeOfStringTable +
|
|
sizeOfExportTables;
|
|
// + cbRelocTablePad;
|
|
|
|
pconPowerMacLoader = PconNew(ReservedSection.PowerMacLoader.Name,
|
|
totalSizeOfLoaderSection,
|
|
0,
|
|
ReservedSection.PowerMacLoader.Characteristics,
|
|
pmodLinkerDefined,
|
|
&pimage->secs,
|
|
pimage);
|
|
|
|
// TODO: Check to make sure that this won't cause grief - ShankarV
|
|
// pconPowerMacLoader->cbPad = cbRelocTablePad;
|
|
|
|
#ifdef MFILE_PAD
|
|
if (fMfilePad) {
|
|
pconPowerMacLoader->cbPad =
|
|
CalculateMFilePad(totalSizeOfLoaderSection);
|
|
pconPowerMacLoader->cbRawData += pconPowerMacLoader->cbPad;
|
|
}
|
|
#endif
|
|
|
|
if (pimage->Switch.Link.fTCE) {
|
|
InitNodPcon(pconPowerMacLoader, NULL, TRUE);
|
|
}
|
|
|
|
return(totalSizeOfLoaderSection);
|
|
}
|
|
|
|
|
|
STATIC
|
|
PEXTERNAL
|
|
GetDotExtern(
|
|
const char *szName,
|
|
PIMAGE pimage,
|
|
BOOL fAdd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Given an external symbol create a new external with
|
|
a dot before the name. This symbol represents the
|
|
procedure descriptor of a externally visible routine.
|
|
|
|
Arguments:
|
|
name of the external symbol
|
|
pimage
|
|
fAdd to indicate whether or not to add it to the symbol table
|
|
|
|
Return Value:
|
|
The dot external it created.
|
|
|
|
--*/
|
|
|
|
{
|
|
char *szDotName = (char *) PvAlloc(strlen(szName) + 2);
|
|
strcpy(szDotName, ".");
|
|
strcat(szDotName, szName);
|
|
|
|
PEXTERNAL pextDot;
|
|
|
|
if (fAdd) {
|
|
pextDot = LookupExternSz(pimage->pst, szDotName, NULL);
|
|
} else {
|
|
pextDot = SearchExternSz(pimage->pst, szDotName);
|
|
}
|
|
|
|
FreePv(szDotName);
|
|
|
|
return(pextDot);
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
FixupDescriptor(
|
|
const char *szName,
|
|
PEXTERNAL pext,
|
|
DWORD ibSec,
|
|
PIMAGE pimage,
|
|
BOOL isDotExtern
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Fixup the routine descriptor code offset and toc offset.
|
|
Store away the relocation for this DESC.
|
|
|
|
Arguments:
|
|
name of the external symbol
|
|
pext a pointer to the external symbol
|
|
ibSec
|
|
pimage
|
|
isDotExtern bool true if it is a dot extern (procedure descriptors)
|
|
|
|
--*/
|
|
|
|
{
|
|
PEXTERNAL pextDot;
|
|
DWORD descOffset;
|
|
DWORD tocOffset;
|
|
|
|
if (!isDotExtern) {
|
|
if (READ_BIT(pext, sy_CROSSTOCCALL)) {
|
|
return;
|
|
}
|
|
|
|
pextDot = GetDotExtern(szName, pimage, TRUE);
|
|
} else {
|
|
pextDot = pext;
|
|
}
|
|
|
|
// TODO: First remove the global symbol walk in incr.cpp - ShankarV
|
|
// Also we don't need to fixup descroptors for FNoPass1PMOD(pmod)
|
|
// But I guess that will be automatically taken care if sy_DESCRRELWRITTEN is set
|
|
|
|
if (READ_BIT(pextDot, sy_DESCRRELWRITTEN)) {
|
|
return;
|
|
}
|
|
|
|
assert(pextDot->pcon - pconTocDescriptors->rva);
|
|
assert(PsecPCON(pconTocDescriptors)->rva == mppc_baseOfInitData);
|
|
|
|
descOffset = pconTocDescriptors->rva + pextDot->ImageSymbol.Value
|
|
- mppc_baseOfInitData;
|
|
|
|
tocOffset = pextToc->FinalValue - mppc_baseOfInitData;
|
|
|
|
if (pimage->Switch.Link.DebugType & FixupDebug) {
|
|
DWORD rvaCur = pconTocDescriptors->rva + pextDot->ImageSymbol.Value;
|
|
DWORD rvaTarget = mppc_baseOfCode + ibSec;
|
|
|
|
SaveDebugFixup(IMAGE_REL_MPPC_DATAREL, 0, rvaCur, rvaTarget);
|
|
|
|
SaveDebugFixup(IMAGE_REL_MPPC_DATAREL, 1, rvaCur + 4, pextToc->FinalValue);
|
|
}
|
|
|
|
FileSeek(FileWriteHandle, (pconTocDescriptors->foRawDataDest +
|
|
pextDot->ImageSymbol.Value), SEEK_SET);
|
|
|
|
SwapBytes(&ibSec, 4);
|
|
FileWrite(FileWriteHandle, &ibSec, sizeof(DWORD));
|
|
|
|
SwapBytes(&tocOffset, 4);
|
|
FileWrite(FileWriteHandle, &tocOffset, sizeof(DWORD));
|
|
|
|
if (!READ_BIT(pextDot, sy_DESCRELOCADDED)) {
|
|
// This is mainly to accommodate Entry/Init/Term descriptors
|
|
// during subsequent incremental builds. Since CreateEntryInitTermDescriptors
|
|
// is not called the second time around, there is no reloc added.
|
|
|
|
AddRelocation(descOffset, DESC_RELO, NULL);
|
|
|
|
SET_BIT(pextDot, sy_DESCRELOCADDED);
|
|
}
|
|
|
|
SET_BIT(pextDot, sy_DESCRRELWRITTEN);
|
|
}
|
|
|
|
|
|
void
|
|
MppcFixIncrDotExternFlags(
|
|
PEXTERNAL pext,
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
To reset the ppc flags of pext so that
|
|
the descriptor fixups are properly done
|
|
|
|
--*/
|
|
{
|
|
if (!READ_BIT(pext, sy_CROSSTOCCALL)) {
|
|
const char *szName = SzNamePext(pext, pimage->pst);
|
|
|
|
PEXTERNAL pextDot = GetDotExtern(szName, pimage, FALSE);
|
|
|
|
if (pextDot == NULL) {
|
|
return;
|
|
}
|
|
|
|
// This is mainly to accommodate Entry/Init/Term descriptors
|
|
// during subsequent incremental builds. Since CreateEntryInitTermDescriptors
|
|
// is not called the second time around, there is no reloc added.
|
|
|
|
// However we can't assert here because of newly added descriptors
|
|
// which do need a reloc during FixupDescriptors
|
|
// assert(READ_BIT(pextDot, sy_DESCRELOCADDED));
|
|
// SET_BIT(pextDot, sy_DESCRELOCADDED);
|
|
|
|
// The descriptor should have been fixed-up during the first build
|
|
// but not if it is a brand new one.
|
|
// assert(READ_BIT(pextDot, sy_DESCRRELWRITTEN));
|
|
|
|
RESET_BIT(pextDot, sy_DESCRRELWRITTEN);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
FixupEntryInitTerm(
|
|
PEXTERNAL pextEntry,
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
const char *szName;
|
|
DWORD codeOffset;
|
|
|
|
if (pextEntry != NULL) {
|
|
/* Fixup entry point */
|
|
|
|
codeOffset = pextEntry->ImageSymbol.Value +
|
|
pextEntry->pcon->rva - mppc_baseOfCode;
|
|
|
|
if (fIncrDbFile) {
|
|
MppcFixIncrDotExternFlags(pextEntry, pimage);
|
|
}
|
|
|
|
szName = SzNamePext(pextEntry, pimage->pst);
|
|
|
|
FixupDescriptor(szName, pextEntry, codeOffset, pimage, FALSE);
|
|
}
|
|
|
|
|
|
if (pimage->SwitchInfo.szMacInit != NULL) {
|
|
/* Fixup init routine */
|
|
|
|
PEXTERNAL pextInit = LookupExternSz(pimage->pst, pimage->SwitchInfo.szMacInit, NULL);
|
|
|
|
codeOffset = pextInit->ImageSymbol.Value +
|
|
pextInit->pcon->rva - mppc_baseOfCode;
|
|
|
|
if (fIncrDbFile) {
|
|
MppcFixIncrDotExternFlags(pextInit, pimage);
|
|
}
|
|
|
|
FixupDescriptor(pimage->SwitchInfo.szMacInit, pextInit, codeOffset, pimage, FALSE);
|
|
}
|
|
|
|
if (pimage->SwitchInfo.szMacTerm != NULL) {
|
|
/* Fixup term routine */
|
|
|
|
PEXTERNAL pextTerm = LookupExternSz(pimage->pst, pimage->SwitchInfo.szMacTerm, NULL);
|
|
|
|
codeOffset = pextTerm->ImageSymbol.Value +
|
|
pextTerm->pcon->rva - mppc_baseOfCode;
|
|
|
|
if (fIncrDbFile) {
|
|
MppcFixIncrDotExternFlags(pextTerm, pimage);
|
|
}
|
|
|
|
FixupDescriptor(pimage->SwitchInfo.szMacTerm, pextTerm, codeOffset, pimage, FALSE);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
MppcAssignImportIndices(
|
|
PIMAGE pimage
|
|
)
|
|
{
|
|
// Assign indices to all imports
|
|
|
|
DWORD order = 0;
|
|
|
|
CONTAINER_LIST *pcontainerlistCur = pcontainerlistHead;
|
|
|
|
pcontainerlistCur = pcontainerlistHead;
|
|
while (pcontainerlistCur != NULL) {
|
|
IMPORT_INFO *pimportinfoCur = pcontainerlistCur->pimportinfoHead;
|
|
|
|
while (pimportinfoCur != NULL) {
|
|
pimportinfoCur->order = order++;
|
|
|
|
pimportinfoCur = pimportinfoCur->pimportinfoNext;
|
|
}
|
|
|
|
pcontainerlistCur = pcontainerlistCur->pcontainerlistNext;
|
|
}
|
|
}
|
|
|
|
|
|
IMPORT_INFO *
|
|
PimportinfoLookup(
|
|
PIMAGE pimage,
|
|
PEXTERNAL pext
|
|
)
|
|
{
|
|
CONTAINER_LIST *pcontainerlistCur = pcontainerlistHead;
|
|
|
|
while (pcontainerlistCur) {
|
|
IMPORT_INFO *pimportinfoCur = pcontainerlistCur->pimportinfoHead;
|
|
|
|
while (pimportinfoCur != NULL) {
|
|
if (pimportinfoCur->pext == pext) {
|
|
|
|
return(pimportinfoCur);
|
|
}
|
|
|
|
pimportinfoCur = pimportinfoCur->pimportinfoNext;
|
|
}
|
|
|
|
pcontainerlistCur = pcontainerlistCur->pcontainerlistNext;
|
|
}
|
|
|
|
// Not found
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
STATIC
|
|
DWORD
|
|
WriteChainTableEntry(
|
|
HASH_WORD hashWord,
|
|
DWORD chainOffset
|
|
)
|
|
{
|
|
|
|
SwapBytes(&hashWord, sizeof(HASH_WORD));
|
|
FileSeek(FileWriteHandle, pconPowerMacLoader->foRawDataDest +
|
|
ExportChainTableOffset + chainOffset, SEEK_SET);
|
|
FileWrite(FileWriteHandle, &hashWord, sizeof(HASH_WORD));
|
|
|
|
return(sizeof(HASH_WORD));
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
WriteExportSymbolTableEntry(
|
|
PIMAGE pimage,
|
|
HASH_INFO_TABLE *info
|
|
)
|
|
{
|
|
EXPORT_SYMBOL_TABLE symbol;
|
|
union
|
|
{
|
|
DWORD temp;
|
|
BYTE off[4];
|
|
} x;
|
|
DWORD nameOffset;
|
|
DWORD ibSec;
|
|
|
|
nameOffset = WriteNameToStringTable(info->name);
|
|
|
|
x.temp = DwSwap(nameOffset);
|
|
symbol.nameOffset[0] = x.off[1];
|
|
symbol.nameOffset[1] = x.off[2];
|
|
symbol.nameOffset[2] = x.off[3];
|
|
|
|
if (info->fDotExtern) {
|
|
if (fPowerMacBuildShared &&
|
|
(info->pext != NULL) && FPcodeSym(info->pext->ImageSymbol)) {
|
|
// Target is a public p-code function
|
|
|
|
char *szNamePcode = (char *) PvAlloc(strlen(info->name) + 7);
|
|
|
|
strcpy(szNamePcode, "__nep");
|
|
if ((info->name[0] != '?') && (info->name[0] != '@')) {
|
|
strcat(szNamePcode, "_");
|
|
}
|
|
strcat(szNamePcode, info->name);
|
|
|
|
PEXTERNAL pextPcode = LookupExternSz(pimage->pst, szNamePcode, NULL);
|
|
assert(pextPcode != NULL);
|
|
|
|
FreePv(szNamePcode);
|
|
|
|
// BEWARE!!!. SzNamePext() may return
|
|
// a pointer to the global array ShortName[].
|
|
// LookupExternSz() may change the contents of
|
|
// ShortName[], so we have to restore the original
|
|
// name for the call to FixupDescriptor().
|
|
|
|
// The offset in the symbol is relative to the
|
|
// start of the section; add its rva and then
|
|
// subtract the base offset.
|
|
|
|
ibSec = (DWORD) pextPcode->ImageSymbol.Value +
|
|
(DWORD) pextPcode->pcon->rva - PsecPCON(pextPcode->pcon)->rva;
|
|
} else {
|
|
ibSec = info->pext->ImageSymbol.Value;
|
|
|
|
if (info->pext->pcon != NULL) {
|
|
ibSec += info->pext->pcon->rva - PsecPCON(info->pext->pcon)->rva;
|
|
}
|
|
}
|
|
|
|
FixupDescriptor(info->name, info->pextDot, ibSec, pimage, TRUE);
|
|
|
|
symbol.symClass = 2;
|
|
symbol.symOffset = info->pextDot->ImageSymbol.Value +
|
|
info->pextDot->pcon->rva -
|
|
PsecPCON(info->pextDot->pcon)->rva;
|
|
|
|
symbol.sectionNumber = (WORD) (PsecPCON(info->pextDot->pcon)->isec - 1);
|
|
} else if (READ_BIT(info->pext, sy_CROSSTOCCALL)) {
|
|
IMPORT_INFO *pimportinfo = PimportinfoLookup(pimage, info->pext);
|
|
|
|
symbol.symClass = ISFCN(info->pext->ImageSymbol.Type) ? 2 : 1;
|
|
symbol.symOffset = (DWORD) pimportinfo->order;
|
|
symbol.sectionNumber = (WORD) -3; // Re-export of import
|
|
|
|
Warning(NULL, REEXPORT, SzNamePext(info->pext, pimage->pst));
|
|
} else {
|
|
ibSec = info->pext->ImageSymbol.Value;
|
|
|
|
if (info->pext->pcon != NULL) {
|
|
ibSec += info->pext->pcon->rva - PsecPCON(info->pext->pcon)->rva;
|
|
|
|
// Set class to kCodeSymbol or kDataSymbol
|
|
|
|
symbol.symClass = ISFCN(info->pext->ImageSymbol.Type) ? 0 : 1;
|
|
symbol.symOffset = ibSec;
|
|
symbol.sectionNumber = (WORD) (PsecPCON(info->pext->pcon)->isec - 1);
|
|
} else {
|
|
symbol.symClass = 1; // kDataSymbol
|
|
symbol.symOffset = ibSec;
|
|
symbol.sectionNumber = (WORD) -2; // Absolute value
|
|
}
|
|
}
|
|
|
|
SwapBytes(&symbol.symOffset, 4);
|
|
SwapBytes(&symbol.sectionNumber, 2);
|
|
|
|
FileSeek(FileWriteHandle, pconPowerMacLoader->foRawDataDest +
|
|
ExportSymbolTableOffset, SEEK_SET);
|
|
FileWrite(FileWriteHandle, &symbol, EXPORT_SYMBOL_TABLESZ);
|
|
|
|
ExportSymbolTableOffset += EXPORT_SYMBOL_TABLESZ;
|
|
}
|
|
|
|
|
|
STATIC
|
|
DWORD
|
|
WriteChainAndSymbolTable(
|
|
DWORD slotNum,
|
|
DWORD chainOffset,
|
|
PIMAGE pimage
|
|
)
|
|
{
|
|
HASH_INFO_TABLE *current;
|
|
|
|
current = ExportInfoTable + slotNum;
|
|
|
|
if (current->pext != NULL) {
|
|
while (current) {
|
|
// Write Chain
|
|
|
|
chainOffset += WriteChainTableEntry(current->hashWord,
|
|
chainOffset);
|
|
|
|
// Write the Export Symbol
|
|
|
|
WriteExportSymbolTableEntry(pimage, current);
|
|
|
|
current = current->next;
|
|
}
|
|
}
|
|
|
|
return(chainOffset);
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
WriteSlotTable(
|
|
DWORD slotTableOffset,
|
|
DWORD count,
|
|
DWORD index
|
|
)
|
|
{
|
|
HASH_SLOT_TABLE entry;
|
|
|
|
index /= sizeof(HASH_WORD);
|
|
|
|
entry.chainCount = count;
|
|
entry.nFirstExport = index;
|
|
|
|
SwapBytes(&entry, sizeof(HASH_SLOT_TABLE));
|
|
FileSeek(FileWriteHandle, pconPowerMacLoader->foRawDataDest +
|
|
loaderHeader.hashSlotTableOffset +
|
|
slotTableOffset, SEEK_SET);
|
|
FileWrite(FileWriteHandle, &entry, sizeof(HASH_SLOT_TABLE));
|
|
}
|
|
|
|
|
|
void
|
|
MppcBuildExportTables(
|
|
PIMAGE pimage
|
|
)
|
|
{
|
|
DWORD numExports;
|
|
DWORD slotsInSlotTable;
|
|
DWORD slotNum;
|
|
|
|
numExports = loaderHeader.nExportedSymbols;
|
|
|
|
if (numExports == 0) {
|
|
return;
|
|
}
|
|
|
|
slotsInSlotTable = (1 << loaderHeader.hashSlotCount);
|
|
|
|
ExportChainTableOffset = loaderHeader.hashSlotTableOffset +
|
|
(slotsInSlotTable * sizeof(HASH_SLOT_TABLE));
|
|
|
|
ExportSymbolTableOffset = ExportChainTableOffset +
|
|
(numExports * sizeof(HASH_CHAIN_TABLE));
|
|
|
|
// Build the export slot table
|
|
|
|
DWORD chainOffset = 0;
|
|
|
|
for (slotNum = 0; slotNum < slotsInSlotTable; slotNum++) {
|
|
DWORD prevOffset;
|
|
DWORD count;
|
|
|
|
// Build the Export Chain and Export Symbol tables
|
|
|
|
prevOffset = chainOffset;
|
|
|
|
chainOffset = WriteChainAndSymbolTable(slotNum, chainOffset, pimage);
|
|
|
|
count = (chainOffset - prevOffset) / sizeof(HASH_WORD);
|
|
|
|
if (count != 0) {
|
|
DWORD slotTableOffset;
|
|
|
|
// Build the Export Slot Table
|
|
|
|
slotTableOffset = slotNum * sizeof(HASH_SLOT_TABLE);
|
|
|
|
WriteSlotTable(slotTableOffset, count, prevOffset);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#if DBG
|
|
|
|
void
|
|
PrintRelocTable(
|
|
RELOCATION_INFO *pRelocTable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Loop for the number of relocation instructions printing them.
|
|
|
|
Arguments:
|
|
None.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD i;
|
|
RELOCATION_INFO *curRelocTable;
|
|
|
|
printf("i\trelInst\trelCnt\tsecOff\n");
|
|
|
|
curRelocTable = pRelocTable;
|
|
for (i = 0; i < cRelocsAdded; i++) {
|
|
printf("%6d ", i);
|
|
|
|
switch (curRelocTable->type) {
|
|
case DDAT_RELO :
|
|
printf("DDAT");
|
|
break;
|
|
|
|
case DESC_RELO :
|
|
printf("DESC");
|
|
break;
|
|
|
|
case SYMB_RELO :
|
|
printf("SYMB");
|
|
break;
|
|
|
|
case CODE_RELO :
|
|
printf("CODE");
|
|
break;
|
|
|
|
default:
|
|
printf("%3u?", curRelocTable->type);
|
|
break;
|
|
}
|
|
|
|
printf(" %4d %08lx\n", curRelocTable->relocInstr.count,
|
|
curRelocTable->sectionOffset);
|
|
|
|
curRelocTable++;
|
|
}
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
|
|
void
|
|
FinalizePconLoaderHeaders(
|
|
PEXTERNAL pextEntry,
|
|
PIMAGE pimage
|
|
)
|
|
|
|
{
|
|
WORD i; // Loop counter to go thru the WeakImportsFunction and Container Lists
|
|
PARGUMENT_LIST pal; // Pointer to the argument list
|
|
PNUM_ARGUMENT_LIST pnal; // Pointer to the number argument list
|
|
CONTAINER_LIST *pcontainerlistCur;
|
|
DWORD nameOffset;
|
|
DWORD curImportCount = 0;
|
|
DWORD relocInstrTableOffset;
|
|
PEXTERNAL pext;
|
|
union
|
|
{
|
|
DWORD temp;
|
|
BYTE off[4];
|
|
} x;
|
|
|
|
|
|
if (fPowerMacBuildShared) {
|
|
// We are building a DLL. Set the version numbers up
|
|
|
|
pimage->ImgOptHdr.MajorImageVersion = (WORD) ((dwMaxCurrentVer >> 16) & 0xFFFF);
|
|
pimage->ImgOptHdr.MinorImageVersion = (WORD) (dwMaxCurrentVer & 0xFFFF);
|
|
|
|
x.temp = (dwMinOldAPIVer == UINT_MAX ? 0 : dwMinOldAPIVer);
|
|
pimage->ImgOptHdr.MajorSubsystemVersion = (WORD) ((x.temp >> 16) & 0xFFFF);
|
|
pimage->ImgOptHdr.MinorSubsystemVersion = (WORD) (x.temp & 0xFFFF);
|
|
x.temp = 0;
|
|
}
|
|
|
|
if (pextEntry != NULL) {
|
|
// Initialize the loader header with the entry point
|
|
|
|
const char *szName = SzNamePext(pextEntry, pimage->pst);
|
|
|
|
pext = GetDotExtern(szName, pimage, TRUE);
|
|
|
|
loaderHeader.entryPointDescrOffset =
|
|
pext->ImageSymbol.Value + pext->pcon->rva - mppc_baseOfInitData;
|
|
loaderHeader.entryPointSectionNumber = PPC_PEF_DATA_SECTION;
|
|
} else {
|
|
loaderHeader.entryPointSectionNumber = -1;
|
|
loaderHeader.entryPointDescrOffset = 0;
|
|
}
|
|
|
|
if (pimage->SwitchInfo.szMacInit != NULL) {
|
|
pext = GetDotExtern(pimage->SwitchInfo.szMacInit, pimage, TRUE);
|
|
|
|
loaderHeader.initRoutineSectionNumber = PPC_PEF_DATA_SECTION;
|
|
loaderHeader.initRoutineDescrOffset =
|
|
pext->ImageSymbol.Value + pext->pcon->rva - mppc_baseOfInitData;
|
|
} else {
|
|
loaderHeader.initRoutineSectionNumber = -1;
|
|
loaderHeader.initRoutineDescrOffset = 0;
|
|
}
|
|
|
|
if (pimage->SwitchInfo.szMacTerm != NULL) {
|
|
pext = GetDotExtern(pimage->SwitchInfo.szMacTerm, pimage, TRUE);
|
|
|
|
loaderHeader.termRoutineSectionNumber = PPC_PEF_DATA_SECTION;
|
|
loaderHeader.termRoutineDescrOffset =
|
|
pext->ImageSymbol.Value + pext->pcon->rva - mppc_baseOfInitData;
|
|
} else {
|
|
loaderHeader.termRoutineSectionNumber = -1;
|
|
loaderHeader.termRoutineDescrOffset = 0;
|
|
}
|
|
|
|
|
|
/* some of the initialization of the loaderHeader is
|
|
* done in the MppcCreatePconLoader()
|
|
*/
|
|
|
|
loaderHeader.nImportIdTableEntries = numContainers;
|
|
|
|
loaderHeader.nImportSymTableEntries = nSymbolEnt;
|
|
|
|
/* all loader relocations will be in the PPC PEF .data section */
|
|
loaderHeader.nSectionsWithRelocs = PPC_PEF_DATA_SECTION;
|
|
|
|
|
|
relocInstrTableOffset = loaderHeader.relocTableOffset;
|
|
|
|
// Write the container Id names into the Loader string table
|
|
|
|
FileSeek(FileWriteHandle,
|
|
pconPowerMacLoader->foRawDataDest + StringTableOffset,
|
|
SEEK_SET);
|
|
|
|
nameOffset = 0;
|
|
|
|
pcontainerlistCur = pcontainerlistHead;
|
|
while (pcontainerlistCur != NULL) {
|
|
// Make sure the nameOffset in the container is correct
|
|
|
|
pcontainerlistCur->header->nameOffset = nameOffset;
|
|
|
|
size_t cb = strlen(pcontainerlistCur->szName) + 1;
|
|
|
|
FileWrite(FileWriteHandle, pcontainerlistCur->szName, cb);
|
|
|
|
nameOffset += cb;
|
|
|
|
pcontainerlistCur = pcontainerlistCur->pcontainerlistNext;
|
|
}
|
|
|
|
// Write the loader header
|
|
|
|
SwapBytes(&loaderHeader, sizeof(LOADER_HEADER));
|
|
FileSeek(FileWriteHandle, pconPowerMacLoader->foRawDataDest, SEEK_SET);
|
|
FileWrite(FileWriteHandle, &loaderHeader, sizeof(LOADER_HEADER));
|
|
|
|
// Write the import containers headers
|
|
|
|
curImportCount = 0;
|
|
|
|
pcontainerlistCur = pcontainerlistHead;
|
|
while (pcontainerlistCur != NULL) {
|
|
// Walk the weak import list
|
|
|
|
for (i = 0, pal = WeakImportsContainerList.First;
|
|
i < WeakImportsContainerList.Count;
|
|
i++, pal = pal->Next) {
|
|
|
|
if (pal->Flags & ARG_Processed) {
|
|
// Skip already processed entries
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(pal->OriginalName, pcontainerlistCur->szName)) {
|
|
pal->Flags |= ARG_Processed;
|
|
|
|
// Set bit 0x40 in the container ID's "initialization order" field
|
|
pcontainerlistCur->header->importFlags = 0x40;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Walk the Current Version list
|
|
|
|
for (i = 0, pnal = CurrentVersionList.First;
|
|
i < CurrentVersionList.Count;
|
|
i++, pnal = pnal->Next) {
|
|
|
|
if (pnal->Flags & ARG_Processed) {
|
|
// Skip already processed entries
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(pnal->szOriginalName, pcontainerlistCur->szName)) {
|
|
pcontainerlistCur->header->currentVersion = pnal->dwNumber;
|
|
pnal->Flags |= ARG_Processed;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Walk the OldDef Version list
|
|
|
|
for (i = 0, pnal = OldCodeVersionList.First;
|
|
i < OldCodeVersionList.Count;
|
|
i++, pnal = pnal->Next) {
|
|
|
|
if (pnal->Flags & ARG_Processed) {
|
|
// Skip already processed entries
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(pnal->szOriginalName, pcontainerlistCur->szName)) {
|
|
pcontainerlistCur->header->oldImpVersion = pnal->dwNumber;
|
|
pnal->Flags |= ARG_Processed;
|
|
break;
|
|
}
|
|
}
|
|
|
|
pcontainerlistCur->header->firstImport = curImportCount;
|
|
curImportCount += pcontainerlistCur->header->nbrOfImports;
|
|
SwapBytes(pcontainerlistCur->header, offsetof(CONTAINER_TABLE, importFlags));
|
|
FileWrite(FileWriteHandle, pcontainerlistCur->header, sizeof(CONTAINER_TABLE));
|
|
|
|
pcontainerlistCur = pcontainerlistCur->pcontainerlistNext;
|
|
}
|
|
|
|
// Write the import tables grouped and sorted for each container
|
|
|
|
curSymbolTableOffset += pconPowerMacLoader->foRawDataDest;
|
|
|
|
pcontainerlistCur = pcontainerlistHead;
|
|
while (pcontainerlistCur != NULL) {
|
|
IMPORT_INFO *pimportinfoCur = pcontainerlistCur->pimportinfoHead;
|
|
|
|
while (pimportinfoCur != NULL) {
|
|
IMPORT_TABLE symbol;
|
|
|
|
const char *szName = SzNamePext(pimportinfoCur->pext, pimage->pst);
|
|
|
|
if (szName[0] == '_') {
|
|
szName++;
|
|
}
|
|
|
|
x.temp = WriteNameToStringTable(szName);
|
|
SwapBytes(&x, 4);
|
|
|
|
symbol.nameOffset[0] = x.off[1];
|
|
symbol.nameOffset[1] = x.off[2];
|
|
symbol.nameOffset[2] = x.off[3];
|
|
symbol.symClass = ISFCN(pimportinfoCur->pext->ImageSymbol.Type) ? 2 : 1;
|
|
|
|
// If the function is a weak import, then symbol.symClass |= 128;
|
|
|
|
for (i = 0, pal = WeakImportsFunctionList.First;
|
|
i < WeakImportsFunctionList.Count;
|
|
i++, pal = pal->Next) {
|
|
if (pal->Flags & ARG_Processed) {
|
|
// Skip already processed entries
|
|
|
|
continue;
|
|
}
|
|
|
|
if (strcmp(szName, pal->OriginalName) == 0) {
|
|
pal->Flags |= ARG_Processed;
|
|
|
|
// The high order bit of the byte is set
|
|
|
|
symbol.symClass |= 128;
|
|
break;
|
|
}
|
|
}
|
|
|
|
FileSeek(FileWriteHandle, curSymbolTableOffset, SEEK_SET);
|
|
FileWrite(FileWriteHandle, &symbol, sizeof(IMPORT_TABLE));
|
|
curSymbolTableOffset += sizeof(IMPORT_TABLE);
|
|
|
|
pimportinfoCur = pimportinfoCur->pimportinfoNext;
|
|
}
|
|
|
|
pcontainerlistCur = pcontainerlistCur->pcontainerlistNext;
|
|
}
|
|
|
|
|
|
// Checking if any of the weak imports for functions is unprocessed
|
|
|
|
for (i = 0, pal = WeakImportsFunctionList.First;
|
|
i < WeakImportsFunctionList.Count;
|
|
i++, pal = pal->Next) {
|
|
|
|
// Identify the unprocessed entries
|
|
|
|
if (!(pal->Flags & ARG_Processed)) {
|
|
Warning(NULL, MACIMPORTSYMBOLNOTFOUND, pal->OriginalName);
|
|
}
|
|
}
|
|
|
|
// Checking if any of the weak imports for container is unprocessed
|
|
|
|
for (i = 0, pal = WeakImportsContainerList.First;
|
|
i < WeakImportsContainerList.Count;
|
|
i++, pal = pal->Next) {
|
|
|
|
// Identify the unprocessed entries
|
|
|
|
if (!(pal->Flags & ARG_Processed)) {
|
|
Warning(NULL, MACIMPORTCONTAINERNOTFOUND, pal->OriginalName);
|
|
}
|
|
}
|
|
|
|
// Checking if any of the CurrentVersion List is unprocessed
|
|
|
|
for (i = 0, pnal = CurrentVersionList.First;
|
|
i < CurrentVersionList.Count;
|
|
i++, pnal = pnal->Next) {
|
|
|
|
// Identify the unprocessed entries
|
|
|
|
if (!(pnal->Flags & ARG_Processed)) {
|
|
Warning(NULL, MACIMPORTCONTAINERNOTFOUND, pnal->szOriginalName);
|
|
}
|
|
}
|
|
|
|
// Checking if any of the OldCodeVersion List is unprocessed
|
|
|
|
for (i = 0, pnal = OldCodeVersionList.First;
|
|
i < OldCodeVersionList.Count;
|
|
i++, pnal = pnal->Next) {
|
|
|
|
// Identify the unprocessed entries
|
|
|
|
if (!(pnal->Flags & ARG_Processed)) {
|
|
Warning(NULL, MACIMPORTCONTAINERNOTFOUND, pnal->szOriginalName);
|
|
}
|
|
}
|
|
|
|
FreeArgumentNumberList(&CurrentVersionList);
|
|
FreeArgumentNumberList(&OldCodeVersionList);
|
|
FreeArgumentNumberList(&VerboseCurrentVersionList);
|
|
FreeArgumentNumberList(&VerboseOldCodeVersionList);
|
|
FreeArgumentNumberList(&VerboseOldAPIVersionList);
|
|
|
|
qsort((void *) pRelocTable,
|
|
(size_t) cRelocsAdded,
|
|
sizeof(RELOCATION_INFO),
|
|
PpcCompareReloc);
|
|
|
|
#if DBG
|
|
KillDuplicateRelocs();
|
|
#endif
|
|
|
|
BuildRelocTables(relocInstrTableOffset);
|
|
|
|
DBEXEC(DB_MPPC_RELOC, PrintRelocTable(pRelocTable));
|
|
|
|
// Update the pimage for ilink purposes
|
|
|
|
pimage->pcontainerlistHead = pcontainerlistHead;
|
|
}
|
|
|
|
|
|
|
|
STATIC
|
|
void
|
|
SwapIndirectGlueCode(
|
|
VOID
|
|
)
|
|
{
|
|
SwapBytes(&(indirectCallGlue.loadEntryPoint), 4);
|
|
SwapBytes(&(indirectCallGlue.saveCallersTOC), 4);
|
|
SwapBytes(&(indirectCallGlue.moveToCTR), 4);
|
|
SwapBytes(&(indirectCallGlue.loadProcsTOC), 4);
|
|
// SwapBytes(&(indirectCallGlue.loadEnvPtr), 4);
|
|
SwapBytes(&(indirectCallGlue.jumpThruCTR), 4);
|
|
}
|
|
|
|
|
|
|
|
STATIC
|
|
void
|
|
AddCrossTocGlue(
|
|
LONG ibToc,
|
|
PIMAGE pimage
|
|
)
|
|
{
|
|
// Write out the glue code
|
|
|
|
FileSeek(FileWriteHandle, pconGlueCode->foRawDataDest + pimage->glueOffset, SEEK_SET);
|
|
|
|
if (pimage->Switch.Link.fNewGlue) {
|
|
if (pimage->Switch.Link.DebugType & FixupDebug) {
|
|
DWORD rvaCur = pconGlueCode->rva + pimage->glueOffset;
|
|
DWORD rvaTarget = pextToc->FinalValue + ibToc;
|
|
|
|
SaveDebugFixup(IMAGE_REL_MPPC_TOCREL, 0, rvaCur + offsetof(NEWCROSSTOCGLUE, loadProcDesc) + 2, rvaTarget);
|
|
|
|
// UNDONE: Should we emit a relocation for the B instruction?
|
|
}
|
|
|
|
// Change the offset to the offset of the descr in the Toc. ibToc may be negative
|
|
// so we mask out the high word.
|
|
|
|
NewCrossTocGlue.loadProcDesc = DwSwap(0x81820000 | (ibToc & 0xffff));
|
|
|
|
// We have put the crossTocGlueExtension at the very top of pconGlueCode
|
|
// We now have to jump to that crossTocGlueExtension code
|
|
// The very top of pconGlueCode is where pimage->glueOffset is zero
|
|
// So we have to jump back by negative pimage->glueOffset
|
|
|
|
NewCrossTocGlue.jumpToExt = DwSwap(PPC_BRANCH | (PPC_ADDR_MASK & ~pimage->glueOffset));
|
|
|
|
FileWrite(FileWriteHandle, &NewCrossTocGlue, sizeof(NewCrossTocGlue));
|
|
|
|
pimage->glueOffset += sizeof(NewCrossTocGlue);
|
|
} else {
|
|
if (pimage->Switch.Link.DebugType & FixupDebug) {
|
|
DWORD rvaCur = pconGlueCode->rva + pimage->glueOffset;
|
|
DWORD rvaTarget = pextToc->FinalValue + ibToc;
|
|
|
|
SaveDebugFixup(IMAGE_REL_MPPC_TOCREL, 0, rvaCur + offsetof(OLDCROSSTOCGLUE, loadProcDesc) + 2, rvaTarget);
|
|
}
|
|
|
|
// Change the offset to the offset of the descr in the Toc. ibToc may be negative
|
|
// so we mask out the high word.
|
|
|
|
OldCrossTocGlue.loadProcDesc = DwSwap(0x81820000 | (ibToc & 0xffff));
|
|
|
|
FileWrite(FileWriteHandle, &OldCrossTocGlue, sizeof(OldCrossTocGlue));
|
|
|
|
pimage->glueOffset += sizeof(OldCrossTocGlue);
|
|
}
|
|
}
|
|
|
|
|
|
STATIC
|
|
DWORD
|
|
RvaBuildIndirectCallGlue(
|
|
DWORD isym,
|
|
PMOD pmod,
|
|
PIMAGE_SYMBOL rgsym,
|
|
PIMAGE pimage
|
|
)
|
|
{
|
|
PEXTERNAL pext;
|
|
|
|
pext = pmod->rgpext[isym];
|
|
|
|
assert(pext != NULL);
|
|
|
|
if (!READ_BIT(pext, sy_CROSSTOCGLUEADDED)) {
|
|
PEXTERNAL pextGlue;
|
|
|
|
pextGlue = LookupExternSz(pimage->pst, "__glueptr", NULL);
|
|
|
|
if ((pextGlue->Flags & EXTERN_DEFINED) == 0) {
|
|
SwapIndirectGlueCode();
|
|
|
|
FileSeek(FileWriteHandle, pconGlueCode->foRawDataDest + pimage->glueOffset, SEEK_SET);
|
|
FileWrite(FileWriteHandle, &indirectCallGlue, sizeof(indirectCallGlue));
|
|
|
|
SetDefinedExt(pextGlue, TRUE, pimage->pst);
|
|
pextGlue->pcon = pconGlueCode;
|
|
pextGlue->ImageSymbol.Value = pimage->glueOffset;
|
|
pextGlue->FinalValue = pconGlueCode->rva + pimage->glueOffset;
|
|
|
|
pimage->glueOffset += sizeof(indirectCallGlue);
|
|
}
|
|
|
|
pext->glueValue = pextGlue->pcon->rva + pextGlue->ImageSymbol.Value;
|
|
|
|
SET_BIT(pext, sy_CROSSTOCGLUEADDED);
|
|
}
|
|
|
|
return(pext->glueValue);
|
|
}
|
|
|
|
|
|
STATIC
|
|
DWORD
|
|
WriteNameToStringTable(
|
|
const char *szName
|
|
)
|
|
{
|
|
size_t length = strlen(szName);
|
|
|
|
DWORD currentOffset;
|
|
|
|
FileSeek(FileWriteHandle, pconPowerMacLoader->foRawDataDest +
|
|
StringTableOffset +
|
|
curStringTableOffset, SEEK_SET);
|
|
FileWrite(FileWriteHandle, szName, length + 1);
|
|
|
|
currentOffset = curStringTableOffset;
|
|
|
|
// Increment the current string table pointer
|
|
|
|
curStringTableOffset += length + 1;
|
|
|
|
return(currentOffset);
|
|
}
|
|
|
|
|
|
DWORD
|
|
bv_readBit(void *bv, unsigned int isym)
|
|
{
|
|
UINT *p, word, offset;
|
|
DWORD temp;
|
|
|
|
p = (unsigned int *) bv;
|
|
|
|
word = isym / 32;
|
|
|
|
offset = isym % 32;
|
|
|
|
temp = p[word] & (1 << offset);
|
|
|
|
return(temp);
|
|
}
|
|
|
|
|
|
DWORD
|
|
bv_setAndReadBit(void *bv, unsigned int isym)
|
|
{
|
|
UINT *p, word, offset;
|
|
DWORD temp;
|
|
|
|
p = (unsigned int *) bv;
|
|
|
|
word = isym / 32;
|
|
|
|
offset = isym % 32;
|
|
|
|
temp = p[word] & (1 << offset);
|
|
|
|
if (!temp) {
|
|
p[word] = p[word] | (1 << offset);
|
|
}
|
|
|
|
return(temp);
|
|
}
|
|
|
|
|
|
DWORD
|
|
bv_readAndUnsetBit(void *bv, unsigned int isym)
|
|
{
|
|
UINT *p, word, offset;
|
|
DWORD temp;
|
|
|
|
p = (unsigned int *) bv;
|
|
|
|
word = isym / 32;
|
|
|
|
offset = isym % 32;
|
|
|
|
temp = p[word] & (1 << offset);
|
|
|
|
if (temp) {
|
|
p[word] = p[word] & ~(1 << offset);
|
|
}
|
|
|
|
return(temp);
|
|
}
|
|
|
|
|
|
#define textCharacteristics (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ)
|
|
|
|
|
|
STATIC
|
|
DWORD
|
|
BiasAddress(DWORD addr, BOOL *pfText)
|
|
{
|
|
DWORD i;
|
|
|
|
for (i = 0; i < numSections; i++) {
|
|
PSEC psec = biasInfo[i].psec;
|
|
|
|
if (addr >= psec->rva) {
|
|
|
|
if (pfText != NULL)
|
|
{
|
|
*pfText = ((psec->flags & textCharacteristics) == textCharacteristics);
|
|
}
|
|
|
|
return(addr - psec->rva);
|
|
}
|
|
}
|
|
|
|
DBEXEC(DB_MPPC_SIZES, printf("Going to assert on addr %lx\n", addr));
|
|
assert(FALSE);
|
|
return(addr);
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
WriteTocSymbolReloc(
|
|
PIMAGE pimage,
|
|
PMOD pmod,
|
|
PIMAGE_SYMBOL rgsym,
|
|
DWORD isym,
|
|
PEXTERNAL pextDot,
|
|
PEXTERNAL pext
|
|
)
|
|
{
|
|
BOOL fExternal;
|
|
LONG ibToc;
|
|
DWORD rvaTarget;
|
|
BOOL fImport;
|
|
PEXTERNAL pextWeak = NULL;
|
|
|
|
fExternal = bv_readBit(pmod->tocBitVector, isym);
|
|
|
|
if (fExternal) {
|
|
assert(pextDot != NULL);
|
|
assert(pext != NULL);
|
|
|
|
if (READ_BIT(pext, sy_TOCENTRYFIXEDUP)) {
|
|
return;
|
|
}
|
|
|
|
if (READ_BIT(pext, sy_WEAKEXT)) {
|
|
pextWeak = PextWeakDefaultFind(pext);
|
|
assert(pextWeak != NULL);
|
|
|
|
if (READ_BIT(pextWeak, sy_TOCENTRYFIXEDUP)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
ibToc = pext->ibToc;
|
|
|
|
fImport = READ_BIT(pext, sy_CROSSTOCCALL);
|
|
|
|
SET_BIT(pext, sy_TOCENTRYFIXEDUP);
|
|
} else {
|
|
if (!bv_readAndUnsetBit(pmod->writeBitVector, isym)) {
|
|
// TOC slot has already been fixed up
|
|
|
|
return;
|
|
}
|
|
|
|
ibToc = (LONG) ((DWORD) pmod->rgpext[isym] * sizeof(DWORD) - MPPC_TOC_BIAS);
|
|
|
|
fImport = FALSE;
|
|
}
|
|
|
|
rvaTarget = rgsym[isym].Value;
|
|
|
|
if (fImport) {
|
|
// Found a indirect function pointer to a cross toc call
|
|
|
|
PEXTERNAL pextWeak = NULL;
|
|
|
|
IMPORT_INFO *pimportinfo = PimportinfoLookup(pimage, pext);
|
|
|
|
if (pimportinfo == NULL) {
|
|
// It could be that we are looking at a weak extern
|
|
|
|
pextWeak = PextWeakDefaultFind(pextDot);
|
|
|
|
if (pextWeak != NULL) {
|
|
pimportinfo = PimportinfoLookup(pimage, pextWeak);
|
|
|
|
SET_BIT(pextWeak, sy_TOCENTRYFIXEDUP);
|
|
|
|
if (READ_BIT(pext, sy_TOCRELOCADDED)) {
|
|
SET_BIT(pextWeak, sy_TOCRELOCADDED);
|
|
}
|
|
}
|
|
}
|
|
|
|
SET_BIT(pext, sy_TOCENTRYFIXEDUP);
|
|
|
|
if (!READ_BIT(pext, sy_TOCRELOCADDED)) {
|
|
// Import might be null for a function in custom glue
|
|
// that is accidentally called through a function pointer
|
|
|
|
if (pimportinfo == NULL) {
|
|
const char *szName = SzNamePext(pext, pimage->pst);
|
|
|
|
Fatal(NULL, MACNULLIMPORT, szName);
|
|
}
|
|
|
|
AddRelocation(pextToc->FinalValue + ibToc - mppc_baseOfInitData,
|
|
SYMB_RELO,
|
|
pimportinfo);
|
|
|
|
SET_BIT(pext, sy_TOCRELOCADDED);
|
|
|
|
if (pextWeak != NULL) {
|
|
SET_BIT(pextWeak, sy_TOCRELOCADDED);
|
|
}
|
|
}
|
|
} else {
|
|
// UNDONE: The following comparison is scary! What does it mean?
|
|
|
|
if ((DWORD) pextDot > mppc_numTocEntries) {
|
|
if (READ_BIT(pextDot, sy_TOCDESCRREL)) {
|
|
rvaTarget = pconTocDescriptors->rva + pextDot->ImageSymbol.Value;
|
|
}
|
|
}
|
|
|
|
BOOL fText;
|
|
DWORD ibSec = DwSwap(BiasAddress(rvaTarget, &fText));
|
|
|
|
FileSeek(FileWriteHandle, pconTocTable->foRawDataDest + MPPC_TOC_BIAS + ibToc, SEEK_SET);
|
|
FileWrite(FileWriteHandle, &ibSec, sizeof(DWORD));
|
|
|
|
// UNDONE: The following comparison is scary! What does it mean?
|
|
|
|
if ((DWORD) pextDot > mppc_numTocEntries) {
|
|
if (READ_BIT(pextDot, sy_TOCRELOCADDED)) {
|
|
return;
|
|
}
|
|
|
|
SET_BIT(pextDot, sy_TOCRELOCADDED);
|
|
}
|
|
|
|
if (pimage->Switch.Link.DebugType & FixupDebug) {
|
|
DWORD rvaCur = pextToc->FinalValue + ibToc;
|
|
|
|
SaveDebugFixup(IMAGE_REL_MPPC_DATAREL, 0, rvaCur, rvaTarget);
|
|
}
|
|
|
|
AddRelocation(pextToc->FinalValue + ibToc - mppc_baseOfInitData,
|
|
fText ? CODE_RELO : DDAT_RELO,
|
|
NULL);
|
|
|
|
// UNDONE: The following comparison is scary! What does it mean?
|
|
|
|
if ((DWORD) pextDot > mppc_numTocEntries) {
|
|
if (READ_BIT(pextDot, sy_WEAKEXT)) {
|
|
assert(pextDot == pext);
|
|
assert(pextWeak != NULL);
|
|
|
|
if (pextWeak != NULL) {
|
|
SET_BIT(pextWeak, sy_TOCENTRYFIXEDUP);
|
|
SET_BIT(pextWeak, sy_TOCRELOCADDED);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
STATIC
|
|
DWORD
|
|
RvaWriteTocCallReloc(
|
|
DWORD isym,
|
|
PMOD pmod,
|
|
PIMAGE pimage
|
|
)
|
|
{
|
|
PEXTERNAL pext = pmod->rgpext[isym];
|
|
|
|
if (pext == NULL) {
|
|
// Must be a static function
|
|
|
|
return(0);
|
|
}
|
|
|
|
if (!READ_BIT(pext, sy_CROSSTOCCALL)) {
|
|
return(0);
|
|
}
|
|
|
|
// Found a cross TOC call
|
|
|
|
if (!READ_BIT(pext, sy_CROSSTOCGLUEADDED)) {
|
|
PEXTERNAL pextWeak = NULL;
|
|
|
|
IMPORT_INFO *pimportinfo = PimportinfoLookup(pimage, pext);
|
|
|
|
if (pimportinfo == NULL) {
|
|
// It could be that we are looking at a weak extern
|
|
|
|
pextWeak = PextWeakDefaultFind(pext);
|
|
|
|
if (pextWeak != NULL) {
|
|
pimportinfo = PimportinfoLookup(pimage, pextWeak);
|
|
|
|
if (READ_BIT(pextWeak, sy_TOCENTRYFIXEDUP)) {
|
|
SET_BIT(pext, sy_TOCENTRYFIXEDUP);
|
|
}
|
|
|
|
if (READ_BIT(pextWeak, sy_TOCRELOCADDED)) {
|
|
SET_BIT(pext, sy_TOCRELOCADDED);
|
|
}
|
|
|
|
if (READ_BIT(pextWeak, sy_CROSSTOCGLUEADDED)) {
|
|
SET_BIT(pext, sy_CROSSTOCGLUEADDED);
|
|
pext->glueValue = pextWeak->glueValue;
|
|
}
|
|
}
|
|
}
|
|
|
|
LONG ibToc = pext->ibToc;
|
|
|
|
// Create an external symbol to name the glue code. This is so the debugger will
|
|
// see a public symbol and therefore the call stack display will work.
|
|
|
|
const char *szName = SzNamePext(pextWeak ? pextWeak : pext, pimage->pst);
|
|
|
|
char *szGlueName = (char *) PvAlloc(strlen(szName) + 8);
|
|
strcpy(szGlueName, "__glue_");
|
|
strcat(szGlueName, szName);
|
|
|
|
BOOL bNew = FALSE;
|
|
PEXTERNAL pextGlue = LookupExternSz(pimage->pst, szGlueName, &bNew);
|
|
|
|
if (bNew) {
|
|
// This is not user defined glue that folks like Excel use
|
|
|
|
SetDefinedExt(pextGlue, TRUE, pimage->pst);
|
|
pextGlue->pcon = pconGlueCode;
|
|
pextGlue->ImageSymbol.Value = pimage->glueOffset;
|
|
|
|
// Initialize the glue code
|
|
|
|
AddCrossTocGlue(ibToc, pimage);
|
|
}
|
|
|
|
pextGlue->FinalValue = pextGlue->pcon->rva + pextGlue->ImageSymbol.Value;
|
|
|
|
pext->glueValue = pextGlue->FinalValue;
|
|
SET_BIT(pext, sy_CROSSTOCGLUEADDED);
|
|
|
|
if (pextWeak != NULL) {
|
|
pextWeak->glueValue = pext->glueValue;
|
|
SET_BIT(pextWeak, sy_CROSSTOCGLUEADDED);
|
|
}
|
|
|
|
if (fPdb && (pimage->Switch.Link.DebugInfo != None)) {
|
|
// The linker defined glue code symbols should be passed on
|
|
// as public to PDB if the /PDB:NONE switch is not used.
|
|
|
|
AddPublicMod(pimage, szGlueName,
|
|
(WORD) (pimage->ImgFileHdr.NumberOfSections + 1),
|
|
pextGlue);
|
|
}
|
|
|
|
FreePv(szGlueName);
|
|
|
|
// Review: [glennn]
|
|
// this check seems to prevent subsequent relocs for calls by
|
|
// named import - breaks excel build
|
|
|
|
// We should rightfully check for sy_TOCALLOCATED so that
|
|
// custom glue symbols may not be accidentally called thro fn ptrs.
|
|
|
|
if (READ_BIT(pext, sy_TOCALLOCATED) &&
|
|
!READ_BIT(pext, sy_TOCENTRYFIXEDUP) &&
|
|
!READ_BIT(pext, sy_TOCRELOCADDED)) {
|
|
|
|
// This could be a custom glue where the function is
|
|
// being called through a function pointer. So we need to
|
|
// check on this
|
|
|
|
if (pimportinfo == NULL) {
|
|
Fatal(NULL, MACNULLIMPORT, szName);
|
|
}
|
|
|
|
AddRelocation(pextToc->FinalValue + ibToc - mppc_baseOfInitData,
|
|
SYMB_RELO,
|
|
pimportinfo);
|
|
|
|
SET_BIT(pext, sy_TOCENTRYFIXEDUP);
|
|
SET_BIT(pext, sy_TOCRELOCADDED);
|
|
|
|
if (pextWeak != NULL) {
|
|
SET_BIT(pextWeak, sy_TOCENTRYFIXEDUP);
|
|
SET_BIT(pextWeak, sy_TOCRELOCADDED);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(pext->glueValue);
|
|
}
|
|
|
|
|
|
STATIC BOOL biasSorted = FALSE;
|
|
|
|
|
|
void
|
|
CollectAndSort(PIMAGE pimage)
|
|
{
|
|
BOOL changed;
|
|
DWORD i;
|
|
DWORD count;
|
|
biasStructType tempBias;
|
|
ENM_SEC enmSec;
|
|
PSEC psec;
|
|
BOOL valid;
|
|
|
|
if (biasSorted) {
|
|
return;
|
|
}
|
|
|
|
/* Count the number of sections. */
|
|
|
|
count = 1;
|
|
InitEnmSec(&enmSec, &pimage->secs);
|
|
while (FNextEnmSec(&enmSec)) {
|
|
if ((enmSec.psec->rva == 0) || (enmSec.psec->cbVirtualSize == 0)) {
|
|
continue; // debug, .drectve or similar
|
|
}
|
|
count++;
|
|
}
|
|
|
|
biasInfo = (biasStructType *) PvAlloc(sizeof(biasStructType) * count);
|
|
|
|
i = 0;
|
|
InitEnmSec(&enmSec, &pimage->secs);
|
|
while (FNextEnmSec(&enmSec)) {
|
|
psec = enmSec.psec;
|
|
|
|
if ((psec->rva == 0) || (psec->cbVirtualSize == 0)) {
|
|
continue;
|
|
}
|
|
|
|
valid = TRUE;
|
|
|
|
// Find the kind of section it is.
|
|
|
|
if ((psec->flags & textCharacteristics) == textCharacteristics) {
|
|
mppc_baseOfCode = psec->rva;
|
|
} else if ((psec->flags & ~IMAGE_SCN_MEM_SHARED) == ReservedSection.Data.Characteristics) {
|
|
mppc_baseOfInitData = psec->rva;
|
|
} else if (FIsProgramPsec(psec) &&
|
|
((psec->flags & ReservedSection.PowerMacLoader.Characteristics) !=
|
|
ReservedSection.PowerMacLoader.Characteristics)) {
|
|
// This section is neither a resource nor a ppcldr section
|
|
// This is not text, data, or bss. This is being ignored
|
|
|
|
Warning(NULL, MACINVALIDSECTION, psec->szName);
|
|
|
|
valid = FALSE;
|
|
}
|
|
|
|
if (valid) {
|
|
biasInfo[i].psec = psec;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
numSections = i;
|
|
|
|
do {
|
|
changed = FALSE;
|
|
|
|
for (i = 0; i < numSections - 1; i++) {
|
|
if (biasInfo[i].psec->rva < biasInfo[i+1].psec->rva) {
|
|
tempBias = biasInfo[i];
|
|
biasInfo[i] = biasInfo[i+1];
|
|
biasInfo[i+1] = tempBias;
|
|
changed = TRUE;
|
|
}
|
|
}
|
|
}
|
|
while (changed);
|
|
|
|
biasSorted = TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
FMPPCTocSym(
|
|
PIMAGE pimage,
|
|
PIMAGE_SYMBOL psym
|
|
)
|
|
{
|
|
switch (psym->StorageClass) {
|
|
case IMAGE_SYM_CLASS_FAR_EXTERNAL :
|
|
case IMAGE_SYM_CLASS_EXTERNAL :
|
|
case IMAGE_SYM_CLASS_WEAK_EXTERNAL :
|
|
// Pass2PSYM updated sym to use the image's string table.
|
|
|
|
break;
|
|
|
|
default :
|
|
// The TOC symbol is external. This isn't it.
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
return(strcmp(SzNameSymPst(*psym, pimage->pst), "__TocTb") == 0);
|
|
}
|
|
|
|
|
|
void
|
|
ApplyMPPCFixups(
|
|
PCON pcon,
|
|
PIMAGE_RELOCATION prel,
|
|
DWORD creloc,
|
|
BYTE *pbRawData,
|
|
PIMAGE_SYMBOL rgsym,
|
|
PIMAGE pimage,
|
|
PSYMBOL_INFO rgsymInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Applys all PowerMac fixups to raw data.
|
|
|
|
Arguments:
|
|
pcon - A pointer to a contribution in the section data.
|
|
Raw - A pointer to the raw data.
|
|
rgsymAll - A pointer to the symbol table.
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PMOD pmod;
|
|
BOOL fDebugFixup;
|
|
BOOL fPdataFixup;
|
|
DWORD rvaSec;
|
|
DWORD iReloc;
|
|
|
|
pmod = PmodPCON(pcon);
|
|
|
|
fDebugFixup = (PsecPCON(pcon) == psecDebug);
|
|
fPdataFixup = (PgrpPCON(pcon) == pgrpPdata);
|
|
|
|
BOOL fSaveDebugFixup = (pimage->Switch.Link.DebugType & FixupDebug) && !fDebugFixup;
|
|
|
|
rvaSec = pcon->rva;
|
|
|
|
for (iReloc = creloc; iReloc; iReloc--, prel++) {
|
|
BOOL fromCreateDescrRel;
|
|
BOOL fTextTarget;
|
|
DWORD rvaCur;
|
|
BYTE *pb;
|
|
DWORD isym;
|
|
DWORD rvaTarget;
|
|
DWORD vaTarget;
|
|
BOOL fAbsolute;
|
|
|
|
fromCreateDescrRel = fTextTarget = FALSE;
|
|
|
|
rvaCur = rvaSec + prel->VirtualAddress - RvaSrcPCON(pcon);
|
|
|
|
pb = pbRawData + prel->VirtualAddress - RvaSrcPCON(pcon);
|
|
isym = prel->SymbolTableIndex;
|
|
|
|
rvaTarget = rgsym[isym].Value;
|
|
|
|
if (fINCR && !fDebugFixup && rgsymInfo[isym].fJmpTbl &&
|
|
(rgsym[isym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL ||
|
|
rgsym[isym].StorageClass == IMAGE_SYM_CLASS_WEAK_EXTERNAL ||
|
|
rgsym[isym].StorageClass == IMAGE_SYM_CLASS_FAR_EXTERNAL)) {
|
|
|
|
DWORD dwTemp = *(DWORD UNALIGNED *) pb;
|
|
|
|
if (!fPdataFixup && dwTemp != 0 && dwTemp != 0x01000048 && dwTemp != 0x00000048
|
|
&& prel->Type != IMAGE_REL_MPPC_CREATEDESCRREL) {
|
|
// This is also for functions that have an entry point which is an offset
|
|
// of another function. Typically done using assembly.
|
|
|
|
// Also if it is descriptor fixup, all it means that the first entry in the
|
|
// descriptor should point to the ilink jump table and not to the actual code
|
|
// This would just require the ilink jump table to be fixed and not the
|
|
// descriptor when the actual function moves. This is a typical scenario
|
|
// for code that deals with function pointers
|
|
|
|
if (!pgrpPdata) {
|
|
// However, C++ EH requires the prolog of the catch code to
|
|
// point to some offset from the beginnng of the function.
|
|
// That should neither go through the jump table nor should be
|
|
// marked extern_funcFixup.
|
|
|
|
// UNDONE: The following contradicts the if above. It also fails
|
|
// UNDONE: for pcode where dwTemp may equal 0x00000020
|
|
|
|
// assert(dwTemp == 0 || dwTemp == 0x01000048 || dwTemp == 0x00000048);
|
|
|
|
MarkExtern_FuncFixup(&rgsym[isym], pimage, pcon);
|
|
}
|
|
} else if (!fPdataFixup || (prel->Type == IMAGE_REL_MPPC_DATADESCRREL)) {
|
|
// If it is C++ EH (.pdata), none of the table entries go through
|
|
// the jump table except the third entry which points to ___CxxFrameHandler.
|
|
// The third entry is identified by the IMAGE_REL_MPPC_DATADESCRREL type.
|
|
// None of the other entries are of this type
|
|
|
|
rvaTarget = pconJmpTbl->rva + rgsymInfo[isym].Offset;
|
|
}
|
|
}
|
|
|
|
if (rgsym[isym].SectionNumber == IMAGE_SYM_ABSOLUTE) {
|
|
fAbsolute = TRUE;
|
|
vaTarget = rvaTarget;
|
|
} else {
|
|
fAbsolute = FALSE;
|
|
vaTarget = pimage->ImgOptHdr.ImageBase + rvaTarget;
|
|
|
|
// UNDONE: Check for rvaTarget == 0. Possible fixup to discarded code?
|
|
}
|
|
|
|
WORD wExtra = 0;
|
|
|
|
if (fSaveDebugFixup && !fAbsolute) {
|
|
if (rvaTarget == pextToc->FinalValue) {
|
|
// The target is either the TOC or the actual symbol at
|
|
// that location. Lets check further.
|
|
|
|
if (FMPPCTocSym(pimage, rgsym + isym)) {
|
|
// Indicate this the target symbol is the toc symbol
|
|
|
|
// UNDONE: Use mnemonic constant instead of 1
|
|
|
|
wExtra = 1;
|
|
}
|
|
}
|
|
|
|
switch (prel->Type) {
|
|
case IMAGE_REL_MPPC_LCALL :
|
|
case IMAGE_REL_MPPC_JMPADDR :
|
|
case IMAGE_REL_MPPC_ADDR24 :
|
|
case IMAGE_REL_MPPC_ADDR14 :
|
|
case IMAGE_REL_MPPC_CV :
|
|
case IMAGE_REL_MPPC_PCODENEPE :
|
|
SaveDebugFixup(prel->Type, wExtra, rvaCur, rvaTarget);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_DATAREL :
|
|
case IMAGE_REL_MPPC_DATADESCRREL :
|
|
case IMAGE_REL_MPPC_TOCREL :
|
|
case IMAGE_REL_MPPC_CREATEDESCRREL :
|
|
case IMAGE_REL_MPPC_REL24 :
|
|
case IMAGE_REL_MPPC_REL14 :
|
|
case IMAGE_REL_MPPC_TOCINDIRCALL :
|
|
case IMAGE_REL_MPPC_TOCCALLREL :
|
|
case IMAGE_REL_MPPC_PCODECALL :
|
|
case IMAGE_REL_MPPC_PCODECALLTONATIVE :
|
|
// Do these later
|
|
break;
|
|
|
|
default :
|
|
// Error
|
|
ErrorPcon(pcon, UNKNOWNFIXUP, prel->Type, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
break;
|
|
}
|
|
}
|
|
|
|
PEXTERNAL pext = pmod->rgpext[isym];
|
|
|
|
PIMAGE_SYMBOL pimageSym = rgsym + isym;
|
|
BOOL fExternal = (pimageSym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) ||
|
|
(pimageSym->StorageClass == IMAGE_SYM_CLASS_WEAK_EXTERNAL) ||
|
|
(pimageSym->StorageClass == IMAGE_SYM_CLASS_FAR_EXTERNAL);
|
|
|
|
BOOL fPcodeTarget;
|
|
|
|
if (fExternal) {
|
|
fPcodeTarget = (pext != NULL) && FPcodeSym(pext->ImageSymbol);
|
|
} else {
|
|
fPcodeTarget = FPcodeSym(*pimageSym);
|
|
}
|
|
|
|
switch (prel->Type) {
|
|
DWORD codeOffset;
|
|
DWORD dw;
|
|
LONG lT;
|
|
DWORD ibSec;
|
|
DWORD dwTemp;
|
|
BOOL fImport;
|
|
LONG ibToc;
|
|
PSEC psec;
|
|
|
|
case IMAGE_REL_MPPC_LCALL :
|
|
// UNDONE: This should be an error
|
|
|
|
WarningPcon(pcon, UNMATCHEDPAIR, "LCALL");
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_DATAREL :
|
|
fImport = (rgsym[isym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL) &&
|
|
(pext != NULL) &&
|
|
READ_BIT(pext, sy_CROSSTOCCALL);
|
|
|
|
if (!fImport) {
|
|
if (fSaveDebugFixup && !fAbsolute) {
|
|
SaveDebugFixup(IMAGE_REL_MPPC_DATAREL, wExtra, rvaCur, rvaTarget);
|
|
}
|
|
|
|
ibSec = BiasAddress(rvaTarget, &fTextTarget);
|
|
|
|
dwTemp = DwSwap(*(DWORD UNALIGNED *) pb);
|
|
|
|
dwTemp += ibSec;
|
|
|
|
*(DWORD UNALIGNED *) pb = DwSwap(dwTemp);
|
|
}
|
|
|
|
if (fIncrDbFile && (fPdataFixup || FNoPass1PMOD(pmod))) {
|
|
// Relocations are added later if needed
|
|
|
|
break;
|
|
}
|
|
|
|
codeOffset = BiasAddress(rvaCur, NULL);
|
|
|
|
if (fImport) {
|
|
// Need to put out a SYMB_RELO if the data is an import
|
|
|
|
IMPORT_INFO *pimportinfo = PimportinfoLookup(pimage, pext);
|
|
|
|
if (pimportinfo == NULL) {
|
|
// It could be that we are looking at a weak extern
|
|
|
|
PEXTERNAL pextWeak = PextWeakDefaultFind(pext);
|
|
|
|
if (pextWeak != NULL) {
|
|
pimportinfo = PimportinfoLookup(pimage, pextWeak);
|
|
}
|
|
|
|
if (pimportinfo == NULL) {
|
|
const char *szName = SzNamePext(pext, pimage->pst);
|
|
|
|
Fatal(NULL, MACNULLIMPORT, szName);
|
|
}
|
|
}
|
|
|
|
AddRelocation(codeOffset, SYMB_RELO, pimportinfo);
|
|
} else {
|
|
AddRelocation(codeOffset, fTextTarget ? CODE_RELO : DDAT_RELO, NULL);
|
|
}
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_JMPADDR :
|
|
// This is used for PowerMac Exception Handling Function table
|
|
|
|
dwTemp = DwSwap(*(DWORD UNALIGNED *) pb);
|
|
|
|
dwTemp += rvaTarget - mppc_baseOfCode;
|
|
|
|
*(DWORD UNALIGNED *) pb = DwSwap(dwTemp);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_DATADESCRREL :
|
|
{
|
|
BOOL isCrossTocCall;
|
|
char *szName;
|
|
PEXTERNAL pextDot;
|
|
|
|
isCrossTocCall = FALSE;
|
|
|
|
// UNDONE: Shouldn't there be a check if this is external?
|
|
|
|
szName = SzNamePext(pext, pimage->pst);
|
|
|
|
if (fPcodeTarget) {
|
|
// If this is a p-code function, we must use the offset
|
|
// of it's native entry point to fixup the descriptor.
|
|
|
|
if (fExternal) {
|
|
char *szName;
|
|
char *szNameNep;
|
|
PEXTERNAL pextNep;
|
|
|
|
// Target is a public p-code function
|
|
|
|
if (pext->ImageSymbol.StorageClass == IMAGE_SYM_CLASS_WEAK_EXTERNAL) {
|
|
PEXTERNAL pextWeakDefault = PextWeakDefaultFind(pext);
|
|
|
|
// Target is Weak External as well as a PCode symbol
|
|
|
|
szName = SzNamePext(pextWeakDefault, pimage->pst);
|
|
} else {
|
|
szName = SzNamePext(pext, pimage->pst);
|
|
}
|
|
|
|
szNameNep = (char *) PvAlloc(strlen(szName) + 6);
|
|
strcpy(szNameNep, "__nep");
|
|
strcat(szNameNep, szName);
|
|
|
|
pextNep = LookupExternSz(pimage->pst, szNameNep, NULL);
|
|
assert(pextNep != NULL);
|
|
|
|
FreePv(szNameNep);
|
|
|
|
rvaTarget = pextNep->pcon->rva + pextNep->ImageSymbol.Value;
|
|
} else {
|
|
// Target is a static p-code function
|
|
|
|
pimageSym = PsymAlternateStaticPcodeSym(pimage,
|
|
pcon,
|
|
FALSE,
|
|
pimageSym,
|
|
FALSE);
|
|
|
|
rvaTarget = pimageSym->Value;
|
|
}
|
|
}
|
|
|
|
codeOffset = rvaTarget - mppc_baseOfCode;
|
|
|
|
szName = SzNamePext(pext, pimage->pst);
|
|
|
|
if (READ_BIT(pext, sy_ISDOTEXTERN)) {
|
|
FixupDescriptor(szName,
|
|
pext,
|
|
codeOffset,
|
|
pimage,
|
|
TRUE);
|
|
|
|
pextDot = pext;
|
|
} else {
|
|
FixupDescriptor(szName,
|
|
pext,
|
|
codeOffset,
|
|
pimage,
|
|
FALSE);
|
|
|
|
if (READ_BIT(pext, sy_CROSSTOCCALL)) {
|
|
isCrossTocCall = TRUE;
|
|
} else {
|
|
szName = SzNamePext(pext, pimage->pst);
|
|
|
|
pextDot = GetDotExtern(szName, pimage, TRUE);
|
|
}
|
|
}
|
|
|
|
if (isCrossTocCall) {
|
|
// Found an indirect function call to a cross toc
|
|
|
|
IMPORT_INFO *pimportinfo = PimportinfoLookup(pimage, pext);
|
|
|
|
if (pimportinfo == NULL) {
|
|
// It could be that we are looking at a weak extern
|
|
|
|
PEXTERNAL pextWeak = PextWeakDefaultFind(pext);
|
|
|
|
if (pextWeak != NULL) {
|
|
pimportinfo = PimportinfoLookup(pimage, pextWeak);
|
|
}
|
|
|
|
if (pimportinfo == NULL) {
|
|
szName = SzNamePext(pext, pimage->pst);
|
|
|
|
Fatal(NULL, MACNULLIMPORT, szName);
|
|
}
|
|
}
|
|
|
|
if (fIncrDbFile && (fPdataFixup || FNoPass1PMOD(pmod))) {
|
|
// Relocations are added later if needed
|
|
|
|
if (fPdataFixup && !fEHfuncXToc) {
|
|
pFrameHandler = pimportinfo;
|
|
}
|
|
break;
|
|
}
|
|
|
|
codeOffset = BiasAddress(rvaCur, NULL);
|
|
AddRelocation(codeOffset, SYMB_RELO, pimportinfo);
|
|
} else {
|
|
DWORD rvaDot = pconTocDescriptors->rva + pextDot->ImageSymbol.Value;
|
|
|
|
if (fSaveDebugFixup && !fAbsolute) {
|
|
SaveDebugFixup(IMAGE_REL_MPPC_DATADESCRREL, 0, rvaCur, rvaDot);
|
|
}
|
|
|
|
ibSec = BiasAddress(rvaDot, NULL);
|
|
|
|
dwTemp = DwSwap(*(DWORD UNALIGNED *) pb);
|
|
|
|
dwTemp += ibSec;
|
|
|
|
*(DWORD UNALIGNED *) pb = DwSwap(dwTemp);
|
|
|
|
if (fIncrDbFile && (fPdataFixup || FNoPass1PMOD(pmod))) {
|
|
// Relocations are added later if needed
|
|
|
|
if (fPdataFixup) {
|
|
assert(fEHfuncXToc == FALSE);
|
|
// This step is unnecessary because global statics
|
|
// are always initialized to zero
|
|
|
|
fEHfuncXToc = FALSE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
BOOL fText;
|
|
|
|
codeOffset = BiasAddress(rvaCur, &fText);
|
|
|
|
AddRelocation(codeOffset, fText ? CODE_RELO : DDAT_RELO, NULL);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_CREATEDESCRREL :
|
|
if (fPcodeTarget) {
|
|
// If this is a p-code function, we must use the offset
|
|
// of it's native entry point to fixup the descriptor.
|
|
|
|
if (fExternal) {
|
|
char *szName;
|
|
char *szNameNep;
|
|
PEXTERNAL pextNep;
|
|
|
|
// Target is a public p-code function
|
|
|
|
// UNDONE: Why no check for weak extern like IMAGE_REL_MPPC_DATADESCRREL?
|
|
|
|
szName = SzNamePext(pext, pimage->pst);
|
|
|
|
szNameNep = (char *) PvAlloc(strlen(szName) + 6);
|
|
strcpy(szNameNep, "__nep");
|
|
strcat(szNameNep, szName);
|
|
|
|
pextNep = LookupExternSz(pimage->pst, szNameNep, NULL);
|
|
assert(pextNep != NULL);
|
|
|
|
FreePv(szNameNep);
|
|
|
|
rvaTarget = pextNep->pcon->rva + pextNep->ImageSymbol.Value;
|
|
} else {
|
|
// Target is a static p-code function
|
|
|
|
pimageSym = PsymAlternateStaticPcodeSym(pimage,
|
|
pcon,
|
|
FALSE,
|
|
pimageSym,
|
|
FALSE);
|
|
|
|
rvaTarget = pimageSym->Value;
|
|
}
|
|
}
|
|
|
|
if (!READ_BIT(pext, sy_CROSSTOCCALL)) {
|
|
char *szName;
|
|
|
|
fTextTarget = READ_BIT(pext, sy_ISDOTEXTERN);
|
|
|
|
szName = SzNamePext(pext, pimage->pst);
|
|
|
|
codeOffset = rvaTarget - mppc_baseOfCode;
|
|
|
|
FixupDescriptor(szName, pext, codeOffset, pimage, fTextTarget);
|
|
}
|
|
|
|
// A CREATEDESCRREL is always followed by a TOCREL. Here we fall through into the
|
|
// TOCREL case and eat both relocation records. The reason for falling through
|
|
// (instead of handling them independently) is that we need to match up the
|
|
// non-dotted symbol (CREATEDESCRREL) with the dotted symbol (TOCREL) ... for
|
|
// externals we can do this by name, but not for statics.
|
|
|
|
if ((iReloc == 0) || (prel[1].Type != IMAGE_REL_MPPC_TOCREL)) {
|
|
// UNDONE: This should be an error
|
|
|
|
WarningPcon(pcon, UNMATCHEDPAIR, "IMAGE_REL_MPPC_CREATEDESCRREL");
|
|
break;
|
|
}
|
|
|
|
fromCreateDescrRel = TRUE;
|
|
|
|
// Fall through
|
|
|
|
case IMAGE_REL_MPPC_TOCREL :
|
|
if (bv_readBit(pmod->tocBitVector, isym)) {
|
|
assert(pext != NULL);
|
|
|
|
ibToc = pext->ibToc;
|
|
} else {
|
|
ibToc = (LONG) ((DWORD) pmod->rgpext[isym] * sizeof(DWORD) - MPPC_TOC_BIAS);
|
|
}
|
|
|
|
pb[0] = (BYTE) (ibToc >> 8);
|
|
pb[1] = (BYTE) ibToc;
|
|
|
|
if (fSaveDebugFixup && !fAbsolute) {
|
|
SaveDebugFixup(IMAGE_REL_MPPC_TOCREL, 0, rvaCur, pextToc->FinalValue + ibToc);
|
|
}
|
|
|
|
// Write the Toc stuff.
|
|
|
|
if (fromCreateDescrRel && !fTextTarget) {
|
|
iReloc--;
|
|
prel++;
|
|
|
|
// Parm 5 = pext of the function descriptor
|
|
// Parm 6 = pext of the function
|
|
|
|
WriteTocSymbolReloc(pimage,
|
|
pmod,
|
|
rgsym,
|
|
prel->SymbolTableIndex,
|
|
pmod->rgpext[prel->SymbolTableIndex],
|
|
pext);
|
|
|
|
} else {
|
|
// if fromCreateDescrRel: Parm 5 and 6 = pext of the CREATEDESCRREL target
|
|
// if !fromCreateDescrRel: Parm 5 and 6 = Target
|
|
|
|
WriteTocSymbolReloc(pimage,
|
|
pmod,
|
|
rgsym,
|
|
isym,
|
|
pext,
|
|
pext);
|
|
|
|
if (fromCreateDescrRel) {
|
|
iReloc--;
|
|
prel++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_ADDR24 :
|
|
if (!fAbsolute) {
|
|
// Absolute address fixups are only allowed for absolute targets
|
|
|
|
ErrorPcon(pcon, RELOCATABLETARGET, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
break;
|
|
}
|
|
|
|
if ((vaTarget & 3) != 0) {
|
|
ErrorPcon(pcon, UNALIGNEDFIXUP, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
|
|
vaTarget &= ~3;
|
|
}
|
|
|
|
dw = *(DWORD UNALIGNED *) pb;
|
|
|
|
lT = (LONG) (dw & 0x03FFFFFC);
|
|
|
|
if ((lT & 0x2000000) != 0) {
|
|
lT |= 0xFC000000; // Sign extend
|
|
}
|
|
|
|
lT += vaTarget;
|
|
|
|
if (((lT & 0xFE000000) != 0) &&
|
|
((lT & 0xFE000000) != 0xFE000000)) {
|
|
ErrorPcon(pcon, TOOFAR, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
}
|
|
|
|
*(DWORD UNALIGNED *) pb = DwSwap((dw & 0xFC000003) | (lT & 0x03FFFFFC));
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_ADDR14 :
|
|
if (!fAbsolute) {
|
|
// Absolute address fixups are only allowed for absolute targets
|
|
|
|
ErrorPcon(pcon, RELOCATABLETARGET, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
break;
|
|
}
|
|
|
|
if ((vaTarget & 3) != 0) {
|
|
ErrorPcon(pcon, UNALIGNEDFIXUP, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
|
|
vaTarget &= ~3;
|
|
}
|
|
|
|
dw = DwSwap(*(DWORD UNALIGNED *) pb);
|
|
|
|
lT = (LONG) (dw & 0x0000FFFC);
|
|
|
|
if ((lT & 0x8000) != 0) {
|
|
lT |= 0xFFFF0000; // Sign extend
|
|
}
|
|
|
|
lT += vaTarget;
|
|
|
|
if ((lT > 32767) || (lT < -32768)) {
|
|
ErrorPcon(pcon, TOOFAR, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
}
|
|
|
|
#ifdef LATER
|
|
if (prel->Type & IMAGE_REL_MPPC_BRTAKEN) {
|
|
if (lT >= 0) {
|
|
`dw |= 0x00200000;
|
|
} else {
|
|
dw &= 0xFFDFFFFF;
|
|
}
|
|
} else if (prel->Type & IMAGE_REL_MPPC_BRNTAKEN) {
|
|
if (lT < 0) {
|
|
dw |= 0x00200000;
|
|
} else {
|
|
dw &= 0xFFDFFFFF;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
*(DWORD UNALIGNED *) pb = DwSwap((dw & 0xFFFF0003) | (lT & 0x0000FFFC));
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_REL24 :
|
|
if (fPcodeTarget) {
|
|
if (fExternal) {
|
|
const char *name = SzNamePext(pext, pimage->pst);
|
|
|
|
char *pcodeName = (char *) PvAlloc(strlen(name) + 6);
|
|
|
|
strcpy(pcodeName, "__nep");
|
|
strcat(pcodeName, name);
|
|
|
|
PEXTERNAL pextPcode = LookupExternSz(pimage->pst,
|
|
pcodeName,
|
|
NULL);
|
|
assert(pextPcode != NULL);
|
|
|
|
FreePv(pcodeName);
|
|
|
|
// The offset in the symbol is relative to the
|
|
// start of the section; must add in the
|
|
// relative virtual address to be compatible with
|
|
// rvaCur.
|
|
|
|
rvaTarget = pextPcode->pcon->rva + pextPcode->ImageSymbol.Value;
|
|
} else {
|
|
pimageSym = PsymAlternateStaticPcodeSym(pimage,
|
|
pcon,
|
|
FALSE,
|
|
pimageSym,
|
|
FALSE);
|
|
|
|
rvaTarget = pimageSym->Value;
|
|
}
|
|
} else {
|
|
DWORD rvaGlue = RvaWriteTocCallReloc(isym, pmod, pimage);
|
|
|
|
if (rvaGlue != 0) {
|
|
WarningPcon(pcon, NOTOCRELOAD, SzNameFixupSym(pimage, rgsym + isym));
|
|
|
|
rvaTarget = rvaGlue;
|
|
}
|
|
}
|
|
|
|
if (fSaveDebugFixup && !fAbsolute) {
|
|
SaveDebugFixup(IMAGE_REL_MPPC_REL24, 0, rvaCur, rvaTarget);
|
|
}
|
|
|
|
if ((rvaTarget & 3) != 0) {
|
|
ErrorPcon(pcon, UNALIGNEDFIXUP, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
|
|
rvaTarget &= ~3;
|
|
}
|
|
|
|
// Relocation relative to this instruction
|
|
|
|
rvaTarget -= rvaCur;
|
|
|
|
dw = DwSwap(*(DWORD UNALIGNED *) pb);
|
|
|
|
lT = (LONG) (dw & 0x03FFFFFC);
|
|
|
|
if ((lT & 0x2000000) != 0) {
|
|
lT |= 0xFC000000; // Sign extend
|
|
}
|
|
|
|
lT += rvaTarget;
|
|
|
|
if (((lT & 0xFE000000) != 0) &&
|
|
((lT & 0xFE000000) != 0xFE000000)) {
|
|
ErrorPcon(pcon, TOOFAR, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
}
|
|
|
|
*(DWORD UNALIGNED *) pb = DwSwap((dw & 0xFC000003) | (lT & 0x03FFFFFC));
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_REL14 :
|
|
if (fPcodeTarget) {
|
|
if (fExternal) {
|
|
const char *name = SzNamePext(pext, pimage->pst);
|
|
|
|
char *pcodeName = (char *) PvAlloc(strlen(name) + 6);
|
|
|
|
strcpy(pcodeName, "__nep");
|
|
strcat(pcodeName, name);
|
|
|
|
PEXTERNAL pextPcode = LookupExternSz(pimage->pst,
|
|
pcodeName,
|
|
NULL);
|
|
assert(pextPcode != NULL);
|
|
|
|
FreePv(pcodeName);
|
|
|
|
// The offset in the symbol is relative to the
|
|
// start of the section; must add in the
|
|
// relative virtual address to be compatible with
|
|
// rvaCur.
|
|
|
|
rvaTarget = pextPcode->pcon->rva + pextPcode->ImageSymbol.Value;
|
|
} else {
|
|
pimageSym = PsymAlternateStaticPcodeSym(pimage,
|
|
pcon,
|
|
FALSE,
|
|
pimageSym,
|
|
FALSE);
|
|
|
|
rvaTarget = pimageSym->Value;
|
|
}
|
|
} else {
|
|
DWORD rvaGlue = RvaWriteTocCallReloc(isym, pmod, pimage);
|
|
|
|
if (rvaGlue != 0) {
|
|
WarningPcon(pcon, NOTOCRELOAD, SzNameFixupSym(pimage, rgsym + isym));
|
|
|
|
rvaTarget = rvaGlue;
|
|
}
|
|
}
|
|
|
|
if (fSaveDebugFixup && !fAbsolute) {
|
|
SaveDebugFixup(IMAGE_REL_MPPC_REL14, 0, rvaCur, rvaTarget);
|
|
}
|
|
|
|
if ((rvaTarget & 3) != 0) {
|
|
ErrorPcon(pcon, UNALIGNEDFIXUP, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
|
|
rvaTarget &= ~3;
|
|
}
|
|
|
|
// Relocation relative to this instruction
|
|
|
|
rvaTarget -= rvaCur;
|
|
|
|
dw = DwSwap(*(DWORD UNALIGNED *) pb);
|
|
|
|
lT = (LONG) (dw & 0x0000FFFC);
|
|
|
|
if ((lT & 0x8000) != 0) {
|
|
lT |= 0xFFFF0000; // Sign extend
|
|
}
|
|
|
|
lT += rvaTarget;
|
|
|
|
if ((lT > 32767) || (lT < -32768)) {
|
|
ErrorPcon(pcon, TOOFAR, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
}
|
|
|
|
#ifdef LATER
|
|
if (prel->Type & IMAGE_REL_MPPC_BRTAKEN) {
|
|
if (lT >= 0) {
|
|
dw |= 0x00200000;
|
|
} else {
|
|
dw &= 0xFFDFFFFF;
|
|
}
|
|
} else if (prel->Type & IMAGE_REL_MPPC_BRNTAKEN) {
|
|
if (lT < 0) {
|
|
dw |= 0x00200000;
|
|
} else {
|
|
dw &= 0xFFDFFFFF;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
*(DWORD UNALIGNED *) pb = DwSwap((dw & 0xFFFF0003) | (lT & 0x0000FFFC));
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_CV :
|
|
if (fAbsolute) {
|
|
// Max section # + 1 is the sstSegMap entry for absolute
|
|
// symbols.
|
|
|
|
*(WORD UNALIGNED *) (pb + sizeof(DWORD)) += (WORD) (pimage->ImgFileHdr.NumberOfSections + 1);
|
|
} else {
|
|
psec = PsecFindIsec(rgsym[isym].SectionNumber, &pimage->secs);
|
|
|
|
if (psec != NULL) {
|
|
rvaTarget -= psec->rva;
|
|
|
|
*(WORD UNALIGNED *) (pb + sizeof(DWORD)) += psec->isec;
|
|
} else {
|
|
// This occurs when a discarded comdat is the target of
|
|
// a relocation in the .debug section.
|
|
|
|
assert(rvaTarget == 0);
|
|
}
|
|
}
|
|
|
|
*(DWORD UNALIGNED *) pb += rvaTarget;
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_TOCINDIRCALL :
|
|
{
|
|
DWORD rvaGlue;
|
|
DWORD ib;
|
|
DWORD instr;
|
|
|
|
rvaGlue = RvaBuildIndirectCallGlue(prel->SymbolTableIndex,
|
|
pmod,
|
|
rgsym,
|
|
pimage);
|
|
|
|
if (fSaveDebugFixup && !fAbsolute) {
|
|
SaveDebugFixup(IMAGE_REL_MPPC_TOCINDIRCALL, 0, rvaCur, rvaGlue);
|
|
}
|
|
|
|
assert((rvaGlue & 3) == 0);
|
|
|
|
ib = ((rvaGlue - rvaCur) >> 2) << 2;
|
|
|
|
if (!TEST32MBCODERANGE(ib)) {
|
|
ErrorPcon(pcon, TOOFAR, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
}
|
|
|
|
// Change the instr to jump to the glue code
|
|
|
|
instr = DwSwap(*(DWORD UNALIGNED *) pb);
|
|
|
|
instr |= ib & 0x3FFFFFC;
|
|
|
|
*(DWORD UNALIGNED *) pb = DwSwap(instr);
|
|
|
|
// Replace the NOP following the branch with a TOC reload
|
|
|
|
pb += INSTR_SIZE;
|
|
|
|
if (*(DWORD UNALIGNED *) pb != 0x00000060) {
|
|
ErrorPcon(pcon, FIXUPNONOP, "TOCINDIRCALL", SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
} else {
|
|
*(DWORD UNALIGNED *) pb = DwSwap(0x80410014); // lwz r2,20(r1)
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_TOCCALLREL :
|
|
{
|
|
DWORD rvaGlue;
|
|
|
|
if (fPcodeTarget) {
|
|
if (fExternal) {
|
|
const char *name = SzNamePext(pext, pimage->pst);
|
|
|
|
char *pcodeName = (char *) PvAlloc(strlen(name) + 6);
|
|
|
|
strcpy(pcodeName, "__nep");
|
|
strcat(pcodeName, name);
|
|
|
|
PEXTERNAL pextPcode = LookupExternSz(pimage->pst,
|
|
pcodeName,
|
|
NULL);
|
|
assert(pextPcode != NULL);
|
|
|
|
FreePv(pcodeName);
|
|
|
|
// The offset in the symbol is relative to the
|
|
// start of the section; must add in the
|
|
// relative virtual address to be compatible with
|
|
// rvaCur.
|
|
|
|
rvaTarget = pextPcode->pcon->rva + pextPcode->ImageSymbol.Value;
|
|
} else {
|
|
pimageSym = PsymAlternateStaticPcodeSym(pimage,
|
|
pcon,
|
|
FALSE,
|
|
pimageSym,
|
|
FALSE);
|
|
|
|
rvaTarget = pimageSym->Value;
|
|
}
|
|
|
|
rvaGlue = 0;
|
|
} else {
|
|
rvaGlue = RvaWriteTocCallReloc(isym, pmod, pimage);
|
|
}
|
|
|
|
if (rvaGlue == 0) {
|
|
DWORD ib;
|
|
DWORD instr;
|
|
|
|
// A jump and link within the text
|
|
|
|
if (fSaveDebugFixup && !fAbsolute) {
|
|
SaveDebugFixup(IMAGE_REL_MPPC_TOCCALLREL, 0, rvaCur, rvaTarget);
|
|
}
|
|
|
|
if (fPcodeTarget) {
|
|
// UNDONE: Why aren't the low bits handled properly for PCODE
|
|
|
|
dwTemp = 0x03FFFFFF;
|
|
} else {
|
|
if ((rvaTarget & 3) != 0) {
|
|
ErrorPcon(pcon, UNALIGNEDFIXUP, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
|
|
rvaTarget &= ~3;
|
|
}
|
|
|
|
dwTemp = PPC_ADDR_MASK;
|
|
}
|
|
|
|
ib = rvaTarget - rvaCur;
|
|
|
|
instr = DwSwap(*(DWORD UNALIGNED *) pb);
|
|
|
|
if ((instr & 0xFC000000) == 0x48000000) {
|
|
// This is a Bx instruction
|
|
|
|
if (!TEST32MBCODERANGE(ib)) {
|
|
ErrorPcon(pcon, TOOFAR, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
}
|
|
|
|
instr |= ib & dwTemp;
|
|
} else {
|
|
// This is a BCx instruction
|
|
|
|
if (!TEST32KBCODERANGE(ib)) {
|
|
ErrorPcon(pcon, TOOFAR, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
}
|
|
|
|
instr |= ib & 0x0000FFFC;
|
|
}
|
|
|
|
*(DWORD UNALIGNED *) pb = DwSwap(instr);
|
|
} else {
|
|
DWORD ib;
|
|
DWORD instr;
|
|
|
|
// A cross TOC call
|
|
|
|
if (fSaveDebugFixup && !fAbsolute) {
|
|
SaveDebugFixup(IMAGE_REL_MPPC_TOCCALLREL, 0, rvaCur, rvaGlue);
|
|
}
|
|
|
|
assert((rvaGlue & 3) == 0);
|
|
|
|
// Change the instr to jump to the glue code
|
|
|
|
ib = rvaGlue - rvaCur;
|
|
|
|
instr = DwSwap(*(DWORD UNALIGNED *) pb);
|
|
|
|
if ((instr & 0xFC000000) == 0x48000000) {
|
|
// This is a Bx instruction
|
|
|
|
if (!TEST32MBCODERANGE(ib)) {
|
|
ErrorPcon(pcon, TOOFAR, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
}
|
|
|
|
instr |= ib & 0x3FFFFFC;
|
|
|
|
*(DWORD UNALIGNED *) pb = DwSwap(instr);
|
|
|
|
// Replace the NOP following the branch with a TOC reload
|
|
|
|
pb += INSTR_SIZE;
|
|
|
|
if (*(DWORD UNALIGNED *) pb != 0x00000060) {
|
|
ErrorPcon(pcon, FIXUPNONOP, "TOCCALLREL", SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
} else {
|
|
*(DWORD UNALIGNED *) pb = DwSwap(0x80410014); // lwz r2,20(r1)
|
|
}
|
|
} else {
|
|
// This is a BCx instruction
|
|
|
|
if (!TEST32KBCODERANGE(ib)) {
|
|
ErrorPcon(pcon, TOOFAR, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
}
|
|
|
|
instr |= ib & 0x0000FFFC;
|
|
}
|
|
}
|
|
|
|
if ((iReloc == 0) || (prel[1].Type != IMAGE_REL_MPPC_LCALL)) {
|
|
// UNDONE: This should be an error
|
|
|
|
WarningPcon(pcon, UNMATCHEDPAIR, "TOCCALLREL");
|
|
break;
|
|
}
|
|
|
|
iReloc--;
|
|
prel++;
|
|
}
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_PCODECALL :
|
|
case IMAGE_REL_MPPC_PCODECALLTONATIVE :
|
|
{
|
|
BOOL fNativeCall;
|
|
DWORD instr;
|
|
DWORD ib;
|
|
LONG ibToc;
|
|
PEXTERNAL pextTarget;
|
|
|
|
instr = DwSwap(*(DWORD UNALIGNED *) pb);
|
|
|
|
fNativeCall = ((instr & 0x10000000) != 0);
|
|
|
|
if (fPcodeTarget) {
|
|
if (fExternal) {
|
|
const char *name = SzNamePext(pext, pimage->pst);
|
|
|
|
char *pcodeName = (char *) PvAlloc(strlen(name) + 6);
|
|
|
|
if (fNativeCall) {
|
|
strcpy(pcodeName, "__nep");
|
|
} else {
|
|
assert(prel->Type != IMAGE_REL_MPPC_PCODECALLTONATIVE);
|
|
|
|
strcpy(pcodeName, "__fh");
|
|
}
|
|
strcat(pcodeName, name);
|
|
|
|
pextTarget = LookupExternSz(pimage->pst, pcodeName, NULL);
|
|
|
|
assert(pextTarget != NULL);
|
|
|
|
FreePv(pcodeName);
|
|
} else {
|
|
pimageSym = PsymAlternateStaticPcodeSym(pimage,
|
|
pcon,
|
|
FALSE,
|
|
pimageSym,
|
|
!fNativeCall);
|
|
|
|
rvaTarget = pimageSym->Value;
|
|
}
|
|
} else {
|
|
instr |= 0x10000000; // Set fNative bit
|
|
|
|
if (fExternal) {
|
|
if (READ_BIT(pext, sy_CROSSTOCCALL)) {
|
|
PEXTERNAL pextWeak = NULL;
|
|
|
|
// Get offset in toc.
|
|
|
|
ibToc = pext->ibToc;
|
|
|
|
// For a cross-toc call, add import (if not already
|
|
// done) and relocation (if not already done).
|
|
|
|
IMPORT_INFO *pimportinfo = PimportinfoLookup(pimage, pext);
|
|
|
|
if (pimportinfo == NULL) {
|
|
// It could be that we are looking at a weak extern
|
|
|
|
pextWeak = PextWeakDefaultFind(pext);
|
|
|
|
if (pextWeak != NULL) {
|
|
pimportinfo = PimportinfoLookup(pimage, pextWeak);
|
|
|
|
if (READ_BIT(pextWeak, sy_TOCENTRYFIXEDUP)) {
|
|
SET_BIT(pext, sy_TOCENTRYFIXEDUP);
|
|
}
|
|
|
|
if (READ_BIT(pextWeak, sy_TOCRELOCADDED)) {
|
|
SET_BIT(pext, sy_TOCRELOCADDED);
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: Take care of this bloke for PCode Ilink - ShankarV
|
|
|
|
if (READ_BIT(pext, sy_TOCALLOCATED) &&
|
|
!READ_BIT(pext, sy_TOCENTRYFIXEDUP) &&
|
|
!READ_BIT(pext, sy_TOCRELOCADDED))
|
|
{
|
|
if (pimportinfo == NULL) {
|
|
const char *szName = SzNamePext(pext, pimage->pst);
|
|
|
|
Fatal(NULL, MACNULLIMPORT, szName);
|
|
}
|
|
|
|
AddRelocation(pextToc->FinalValue + ibToc - mppc_baseOfInitData,
|
|
SYMB_RELO,
|
|
pimportinfo);
|
|
|
|
SET_BIT(pext, sy_TOCENTRYFIXEDUP);
|
|
SET_BIT(pext, sy_TOCRELOCADDED);
|
|
|
|
if (pextWeak != NULL) {
|
|
SET_BIT(pextWeak, sy_TOCENTRYFIXEDUP);
|
|
SET_BIT(pextWeak, sy_TOCRELOCADDED);
|
|
}
|
|
}
|
|
|
|
if (fSaveDebugFixup && !fAbsolute) {
|
|
// UNDONE: What is appropriate here
|
|
|
|
// SaveDebugFixup(prel->Type, 0, rvaCur, rvaTarget);
|
|
}
|
|
|
|
// Adjust offset to base of toc and update instr.
|
|
|
|
instr |= 0x08000000 | (ibToc & 0x03FFFFFF);
|
|
|
|
*(DWORD UNALIGNED *) pb = DwSwap(instr);
|
|
break;
|
|
}
|
|
|
|
pextTarget = pext;
|
|
} else {
|
|
rvaTarget = rgsym[prel->SymbolTableIndex].Value;
|
|
}
|
|
}
|
|
|
|
if (fExternal) {
|
|
rvaTarget = pextTarget->pcon->rva + pextTarget->ImageSymbol.Value;
|
|
}
|
|
|
|
if (fSaveDebugFixup && !fAbsolute) {
|
|
SaveDebugFixup(prel->Type, 0, rvaCur, rvaTarget);
|
|
}
|
|
|
|
ib = rvaTarget - rvaCur;
|
|
|
|
if (!TEST32MBCODERANGE(ib)) {
|
|
ErrorPcon(pcon, TOOFAR, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
}
|
|
|
|
instr |= ib & 0x03FFFFFF;
|
|
|
|
*((DWORD UNALIGNED *) pb) = DwSwap(instr);
|
|
}
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_PCODENEPE :
|
|
{
|
|
/*++
|
|
|
|
PCODE FUNCTION STRUCTURE:
|
|
--------------------------------------------
|
|
FIELD : | Call Table | mflr r12 | bl | N | FH |
|
|
--------------------------------------------
|
|
SIZE : | N-2 Longs | 8 (NEP) | 1 | 1 |
|
|
--------------------------------------------
|
|
^ ^
|
|
| |<------ doff ------>|
|
|
pimageSym->Value rvaCur
|
|
|
|
--*/
|
|
|
|
PIMAGE_SYMBOL pimageSym;
|
|
WORD cLongs;
|
|
DWORD doff;
|
|
|
|
pimageSym = rgsym + isym;
|
|
|
|
cLongs = *pb;
|
|
assert(rvaCur >= pimageSym->Value);
|
|
doff = rvaCur -
|
|
(pimageSym->Value + cLongs * cbMACLONG - cbPPCNEP);
|
|
|
|
if (doff == 0) {
|
|
// NEP has been eliminated. Adjust the offset value
|
|
// (N) in the FH (cbPPCNEP must be a multiple of
|
|
// cbMACLONG).
|
|
|
|
assert((cbPPCNEP % cbMACLONG) == 0);
|
|
*pb = (BYTE) (cLongs - (cbPPCNEP/cbMACLONG));
|
|
} else {
|
|
// NEP has not been eliminated. doff should be the
|
|
// size of the NEP.
|
|
|
|
assert(doff == cbPPCNEP);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default :
|
|
ErrorPcon(pcon, UNKNOWNFIXUP, prel->Type, SzNameFixupSym(pimage, rgsym + isym));
|
|
CountFixupError(pimage);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
STATIC
|
|
void
|
|
ProcessMppcCmdLineImport(
|
|
PIMAGE pimage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine processes the cmdline import list
|
|
and calls AddCmdLineImport for each of its arguments
|
|
The cmdline import list - MppcImportList contains
|
|
only the ones that are from command line where PCON is
|
|
NULL. If the /IMPORT directive is from a import library,
|
|
then AddCmdLineImport is directly called from lnkmain.c
|
|
because it has a valid pcon. Here a dummy PCON is created
|
|
which is pmodlinkerdefined.
|
|
|
|
Arguments:
|
|
pimage - pointer to image
|
|
|
|
Return Value:
|
|
Returns void
|
|
|
|
--*/
|
|
|
|
{
|
|
WORD i;
|
|
PARGUMENT_LIST pal;
|
|
|
|
// We need to create a dummy PCON so that the symbol
|
|
// is considered pmodlinkerdefined. This is helpful
|
|
// when we remove the unreferenced mods from libraries
|
|
|
|
PCON pconDummy = PconNew(ReservedSection.Text.Name,
|
|
0, // Size is 0
|
|
0,
|
|
ReservedSection.Text.Characteristics,
|
|
pmodLinkerDefined,
|
|
&pimage->secs, pimage);
|
|
|
|
if (pimage->Switch.Link.fTCE) {
|
|
// So that this goes through TCE processing
|
|
|
|
InitNodPcon(pconDummy, NULL, TRUE);
|
|
}
|
|
|
|
for (i = 0, pal = MppcImportList.First;
|
|
i < MppcImportList.Count;
|
|
i++, pal = pal->Next) {
|
|
if (!AddCmdLineImport(pal->OriginalName,
|
|
pal->ModifiedName,
|
|
pconDummy,
|
|
pimage)) {
|
|
Warning(pal->ModifiedName, MACIMPORTSYMBOLNOTFOUND, pal->OriginalName);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void MPPCLinkerInit(PIMAGE pimage, BOOL *pfIlinkSupported)
|
|
{
|
|
fPowerMac = TRUE;
|
|
|
|
AllowInserts(pimage->pst);
|
|
|
|
*pfIlinkSupported = TRUE;
|
|
|
|
ApplyFixups = ApplyMPPCFixups;
|
|
|
|
#ifdef MFILE_PAD
|
|
if (!FUsedOpt(pimage->SwitchInfo, OP_MFILEPAD)) {
|
|
fMfilePad = (pimage->Switch.Link.DebugInfo != None);
|
|
}
|
|
|
|
// Turn off MFilePad if we are doing iLink
|
|
|
|
if (fINCR) {
|
|
// UNDONE: Generate a warning here - ShankarV
|
|
|
|
fMfilePad = FALSE;
|
|
}
|
|
#endif
|
|
|
|
// If section alignment switch not used, set the default.
|
|
|
|
if (!FUsedOpt(pimage->SwitchInfo, OP_ALIGN)) {
|
|
pimage->ImgOptHdr.SectionAlignment = _4K;
|
|
}
|
|
|
|
pimage->ImgOptHdr.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
|
|
pimage->ImgOptHdr.FileAlignment = 32;
|
|
|
|
// Set default mac opt behavior to noref
|
|
// UNDONE: Why?
|
|
|
|
if (!fExplicitOptRef) {
|
|
pimage->Switch.Link.fTCE = FALSE;
|
|
}
|
|
|
|
if (fINCR && !fReproducible) {
|
|
// The unique number is initialized by calling the time function
|
|
// so that the statics will get a unique name during iLinks as well
|
|
|
|
// UNDONE: This makes linking not-reproducible
|
|
|
|
UniqueNumber = ((INT) time(NULL)) & 0xFF;
|
|
}
|
|
|
|
if (!fIncrDbFile) {
|
|
// Setting the number of TOC Entries in the first FULL build
|
|
// Apple requires 16 entries to be reserved for them
|
|
// We are reserving the 17th entry for C++ Execption Handling
|
|
// data structure! So...
|
|
|
|
mppc_numTocEntries += 17;
|
|
|
|
mppc_numOfCodeFrag = 1;
|
|
|
|
// For every code fragment we have two additional load-time relocs:
|
|
// One that would point to the beginning of Code and the other to point
|
|
// to the Function table. Additionally, there is one more relocation
|
|
// which is the 17th entry of TOC pointing to __FTInfo
|
|
|
|
mppc_numRelocations += 1 + 2 * mppc_numOfCodeFrag;
|
|
|
|
// Count the TOC entry for __FTInfo and the relocations on __FTInfo
|
|
|
|
crelocTotal += 1 + 2 * mppc_numOfCodeFrag;
|
|
|
|
// First time around initialize pimage->glueOffset
|
|
// This retains the current offset within pconGlueCode where
|
|
// the next glue can be written.
|
|
|
|
pimage->glueOffset = 0;
|
|
|
|
// Generate the finder info as a RESN
|
|
|
|
GenFinderInfo(pimage->Switch.Link.fMacBundle,
|
|
pimage->Switch.Link.szMacType, pimage->Switch.Link.szMacCreator);
|
|
|
|
// This is done only for the first Link and not for
|
|
// subsequent iLinks. This taked the command line imports
|
|
// and processes them. This list does not contain imports that
|
|
// come from import libraries.
|
|
|
|
ProcessMppcCmdLineImport(pimage);
|
|
}
|
|
|
|
FreeArgumentList(&MppcImportList);
|
|
|
|
// Swap OldCrossTocGlue
|
|
|
|
SwapBytes(&OldCrossTocGlue, sizeof(OldCrossTocGlue));
|
|
}
|
|
|
|
|
|
void
|
|
ResolveSymbol_icsym(
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Resolve the symbol ".icsym"
|
|
|
|
Arguments:
|
|
pimage - Pointer to image
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PEXTERNAL pext;
|
|
|
|
pext = SearchExternSz(pimage->pst, "._icsym");
|
|
|
|
if (pext != NULL) {
|
|
SetDefinedExt(pext, TRUE, pimage->pst);
|
|
|
|
// We need to create a dummy PCON so that the symbol
|
|
// is considered pmodlinkerdefined. This is helpful
|
|
// when we remove the unreferenced mods from libraries
|
|
|
|
if (pext->pcon == NULL) {
|
|
pext->pcon = PconNew(ReservedSection.Text.Name,
|
|
0, // Size is 0
|
|
0,
|
|
ReservedSection.Text.Characteristics,
|
|
pmodLinkerDefined,
|
|
&pimage->secs, pimage);
|
|
}
|
|
|
|
if (pimage->Switch.Link.fTCE) {
|
|
// So that this goes through TCE processing
|
|
InitNodPcon(pext->pcon, NULL, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BOOL
|
|
AddCmdLineImport(
|
|
const char *szFuncName,
|
|
const char *szContainerName,
|
|
PCON pcon,
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
This routine replaces SearchSharedLibraries which used
|
|
to search the shared libraries for all of the undefined
|
|
externals. Instead, the function name and the dll name
|
|
are passed to this new function from the Command Line, and
|
|
the relevant symbol is marked as defined in the symbol
|
|
table. Also the import information is added to the container.
|
|
|
|
Arguments:
|
|
szFuncName - Function Name
|
|
szContainerName - Container Name
|
|
pcon - contribution
|
|
pimage - pointer to image
|
|
|
|
Return Value:
|
|
Returns TRUE if it succeeds and FALSE if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
PEXTERNAL pext;
|
|
IMPORT_INFO *pimportinfo;
|
|
|
|
pext = LookupExternSz(pimage->pst, szFuncName, NULL);
|
|
|
|
if ((szFuncName[0] == '.') && (szFuncName[1] != '.')) {
|
|
SetDefinedExt(pext, TRUE, pimage->pst);
|
|
pext->pcon = pcon;
|
|
return(FALSE);
|
|
}
|
|
|
|
if (pext->Flags & EXTERN_DEFINED) {
|
|
char szModule[_MAX_PATH * 2];
|
|
char szComFileName[_MAX_PATH * 2];
|
|
|
|
if (pext->pcon == NULL) {
|
|
strcpy(szModule, "a previous module");
|
|
} else {
|
|
SzComNamePMOD(PmodPCON(pext->pcon), szModule);
|
|
}
|
|
|
|
MultiplyDefinedSym(&pimage->Switch,
|
|
SzComNamePCON(pcon, szComFileName),
|
|
szFuncName,
|
|
szModule);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
pext->pcon = pcon;
|
|
SET_BIT(pext, sy_CROSSTOCCALL);
|
|
SetDefinedExt(pext, TRUE, pimage->pst);
|
|
|
|
if (szContainerName == NULL) {
|
|
// sy_CROSSTOCCALL has been set so that it will trigger
|
|
// the requirement of glue. Then we will actually figure
|
|
// out there was custom glue available. But remember
|
|
// we are not setting sy_TOCALLOCATED
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
pimportinfo = (IMPORT_INFO *) Calloc(1, sizeof(IMPORT_INFO));
|
|
pimportinfo->pext = pext;
|
|
|
|
AddContainerInfo(pimage, szContainerName, pimportinfo);
|
|
|
|
// Mark it. We'll need this information later.
|
|
|
|
if (!READ_BIT(pext, sy_TOCALLOCATED)) {
|
|
pext->ibToc = (SHORT) (mppc_numTocEntries * sizeof(DWORD) - MPPC_TOC_BIAS);
|
|
|
|
mppc_numTocEntries++;
|
|
|
|
if (mppc_numTocEntries > (_32K / sizeof(DWORD))) {
|
|
Fatal(NULL, TOCTOOLARGE);
|
|
}
|
|
|
|
mppc_numRelocations++;
|
|
|
|
crelocTotal++;
|
|
|
|
SET_BIT(pext, sy_TOCALLOCATED);
|
|
|
|
if (pimage->Switch.Link.fMap) {
|
|
SaveTocForMapFile(pext);
|
|
}
|
|
}
|
|
|
|
pimage->nUniqueCrossTocCalls++;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
void
|
|
AddVersionList(
|
|
const char *szContainerName,
|
|
const char *szCurrentVer,
|
|
const char *szOldCodeVer,
|
|
const char *szOldAPIVer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
If szContainerName is NULL, then we are building a DLL.
|
|
If not it is an application.
|
|
|
|
This routine first checks if the szContainerName is
|
|
already in the version list. If it is then it uses the
|
|
largest of the two numbers for the CurrentVersion and
|
|
used smallest of the two for the OldCodeVersion.
|
|
If not already present, it simply adds it to the appropriate
|
|
list
|
|
|
|
When building a DLL, it stores the largest seen CurrentVersion
|
|
in dwMaxCurrentVersion and the smallest of the OldCode and OldAPI
|
|
in dwMinOldCodeVersion and dwMinOldAPIVersion respectively.
|
|
|
|
In verbose mode, it stores all the values seen in the Verbose lists
|
|
and emits a warning.
|
|
|
|
Arguments:
|
|
szContainerName - Container Name
|
|
szCurrentVer - Current Version string
|
|
szOldCodeVer - OldCode Version string
|
|
szOldAPIVer - OldAPI Version string
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD i; // Loop counter to go thru the VersionLists
|
|
DWORD RecentVer;
|
|
BOOL fFound = FALSE;
|
|
PNUM_ARGUMENT_LIST pnal; // Pointer to the num_argument list
|
|
|
|
if (szContainerName) {
|
|
DWORD dwTemp = 0;
|
|
|
|
// We are building an application
|
|
|
|
if (szCurrentVer) {
|
|
RecentVer = atoi(szCurrentVer);
|
|
|
|
for (i = 0, pnal = CurrentVersionList.First;
|
|
i < CurrentVersionList.Count && !fFound;
|
|
i++, pnal = pnal->Next) {
|
|
|
|
if (!_stricmp(pnal->szOriginalName, szContainerName)) {
|
|
fFound = TRUE;
|
|
|
|
if (pnal->dwNumber < RecentVer) {
|
|
pnal->dwNumber = RecentVer;
|
|
fMPPCVersionConflict = TRUE;
|
|
}
|
|
|
|
dwTemp = pnal->dwNumber;
|
|
}
|
|
}
|
|
|
|
if (fFound) {
|
|
fFound = FALSE;
|
|
} else {
|
|
// add it to the list
|
|
AddArgumentToNumList(&CurrentVersionList,
|
|
SzDup(szContainerName),
|
|
NULL,
|
|
RecentVer);
|
|
dwTemp = RecentVer;
|
|
}
|
|
|
|
if (Verbose) {
|
|
// List all the conflicts
|
|
for (i = 0, pnal = VerboseCurrentVersionList.First;
|
|
i < VerboseCurrentVersionList.Count && !fFound;
|
|
i++, pnal = pnal->Next) {
|
|
|
|
if (pnal->szOriginalName && !_stricmp(pnal->szOriginalName, szContainerName)) {
|
|
if (pnal->dwNumber == RecentVer) {
|
|
fFound = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fFound) {
|
|
fFound = FALSE;
|
|
} else {
|
|
// add it to the number argument list
|
|
AddArgumentToNumList(&VerboseCurrentVersionList,
|
|
SzDup(szContainerName),
|
|
NULL,
|
|
RecentVer);
|
|
|
|
if (dwTemp == RecentVer) {
|
|
Warning(szContainerName, MACSETVERSION, "CURRENTVER", RecentVer);
|
|
} else {
|
|
Warning(szContainerName, MACIGNOREVERSION, "CURRENTVER", RecentVer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (szOldCodeVer) {
|
|
RecentVer = atoi(szOldCodeVer);
|
|
|
|
for (i = 0, pnal = OldCodeVersionList.First;
|
|
i < OldCodeVersionList.Count && !fFound;
|
|
i++, pnal = pnal->Next) {
|
|
|
|
if (!_stricmp(pnal->szOriginalName, szContainerName)) {
|
|
fFound = TRUE;
|
|
|
|
if (pnal->dwNumber > RecentVer) {
|
|
pnal->dwNumber = RecentVer;
|
|
fMPPCVersionConflict = TRUE;
|
|
}
|
|
|
|
dwTemp = pnal->dwNumber;
|
|
}
|
|
}
|
|
|
|
if (fFound) {
|
|
fFound = FALSE;
|
|
} else {
|
|
// Add it to the list
|
|
AddArgumentToNumList(&OldCodeVersionList,
|
|
SzDup(szContainerName),
|
|
NULL,
|
|
RecentVer);
|
|
dwTemp = RecentVer;
|
|
}
|
|
|
|
if (Verbose) {
|
|
// List all the conflicts
|
|
|
|
for (i = 0, pnal = VerboseOldCodeVersionList.First;
|
|
i < VerboseOldCodeVersionList.Count && !fFound;
|
|
i++, pnal = pnal->Next) {
|
|
|
|
if (pnal->szOriginalName && !_stricmp(pnal->szOriginalName, szContainerName)) {
|
|
if (pnal->dwNumber == RecentVer) {
|
|
fFound = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fFound) {
|
|
fFound = FALSE;
|
|
} else {
|
|
// add it to the number argument list
|
|
AddArgumentToNumList(&VerboseOldCodeVersionList,
|
|
SzDup(szContainerName),
|
|
NULL,
|
|
RecentVer);
|
|
|
|
if (dwTemp == RecentVer) {
|
|
Warning(szContainerName, MACSETVERSION, "OLDCODEVER", RecentVer);
|
|
} else {
|
|
Warning(szContainerName, MACIGNOREVERSION, "OLDCODEVER", RecentVer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// We are probably building a DLL
|
|
// assert(fPowerMacBuildShared);
|
|
|
|
if (szCurrentVer) {
|
|
RecentVer = atoi(szCurrentVer);
|
|
|
|
if (RecentVer > dwMaxCurrentVer) {
|
|
fMPPCVersionConflict =
|
|
dwMaxCurrentVer == 0 ? fMPPCVersionConflict : TRUE;
|
|
dwMaxCurrentVer = RecentVer;
|
|
}
|
|
|
|
if (Verbose) {
|
|
for (i = 0, pnal = VerboseCurrentVersionList.First;
|
|
i < VerboseCurrentVersionList.Count && !fFound;
|
|
i++, pnal = pnal->Next) {
|
|
if (!pnal->szOriginalName && pnal->dwNumber == RecentVer) {
|
|
fFound = TRUE;
|
|
}
|
|
}
|
|
|
|
if (fFound) {
|
|
fFound = FALSE;
|
|
} else {
|
|
AddArgumentToNumList(&VerboseCurrentVersionList,
|
|
NULL,
|
|
NULL,
|
|
RecentVer);
|
|
|
|
if (dwMaxCurrentVer == RecentVer) {
|
|
Warning(NULL, MACSETVERSION, "CURRENTVER", RecentVer);
|
|
} else {
|
|
Warning(NULL, MACIGNOREVERSION, "CURRENTVER", RecentVer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (szOldCodeVer) {
|
|
RecentVer = atoi(szOldCodeVer);
|
|
|
|
if (RecentVer < dwMinOldCodeVer) {
|
|
fMPPCVersionConflict =
|
|
dwMinOldCodeVer == UINT_MAX ? fMPPCVersionConflict : TRUE;
|
|
dwMinOldCodeVer = RecentVer;
|
|
}
|
|
|
|
if (Verbose) {
|
|
for (i = 0, pnal = VerboseOldCodeVersionList.First;
|
|
i < VerboseOldCodeVersionList.Count && !fFound;
|
|
i++, pnal = pnal->Next) {
|
|
if (!pnal->szOriginalName && pnal->dwNumber == RecentVer) {
|
|
fFound = TRUE;
|
|
}
|
|
}
|
|
|
|
if (fFound) {
|
|
fFound = FALSE;
|
|
} else {
|
|
AddArgumentToNumList(&VerboseOldCodeVersionList,
|
|
NULL,
|
|
NULL,
|
|
RecentVer);
|
|
|
|
if (dwMinOldCodeVer == RecentVer) {
|
|
Warning(NULL, MACSETVERSION, "OLDCODEVER", RecentVer);
|
|
} else {
|
|
Warning(NULL, MACIGNOREVERSION, "OLDCODEVER", RecentVer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (szOldAPIVer) {
|
|
RecentVer = atoi(szOldAPIVer);
|
|
|
|
if (RecentVer < dwMinOldAPIVer) {
|
|
fMPPCVersionConflict =
|
|
dwMinOldAPIVer == UINT_MAX ? fMPPCVersionConflict : TRUE;
|
|
dwMinOldAPIVer = RecentVer;
|
|
}
|
|
|
|
if (Verbose) {
|
|
for (i = 0, pnal = VerboseOldAPIVersionList.First;
|
|
i < VerboseOldAPIVersionList.Count && !fFound;
|
|
i++, pnal = pnal->Next) {
|
|
if (!pnal->szOriginalName && pnal->dwNumber == RecentVer) {
|
|
fFound = TRUE;
|
|
}
|
|
}
|
|
|
|
if (fFound) {
|
|
fFound = FALSE;
|
|
} else {
|
|
AddArgumentToNumList(&VerboseOldAPIVersionList,
|
|
NULL,
|
|
NULL,
|
|
RecentVer);
|
|
|
|
if (dwMinOldAPIVer == RecentVer) {
|
|
Warning(NULL, MACSETVERSION, "OLDAPIVER", RecentVer);
|
|
} else {
|
|
Warning(NULL, MACIGNOREVERSION, "OLDAPIVER", RecentVer);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
STATIC
|
|
DWORD
|
|
ZapDeletedOldBaseRelocs(
|
|
RELOCATION_INSTR *pOldRelocInstrTable,
|
|
DWORD old_mppc_numRelocations
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Deletes the old set of Base relocations whose
|
|
CONs have disappeared during incremental linking.
|
|
This list is maintained in ZapOldBaseRelocs
|
|
NAME_LIST.
|
|
|
|
Argument:
|
|
Relocation instruction pointer to old base relocs
|
|
old_mppc_numRelocations which is the number of old relocs
|
|
|
|
Return Value:
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
DWORD i, j, num_deletions = 0;
|
|
PARGUMENT_LIST pal; // Pointer to the argument list
|
|
DWORD dwBeginOffset;
|
|
DWORD dwEndOffset;
|
|
|
|
for (i = 0, pal = ZappedBaseRelocList.First;
|
|
i < ZappedBaseRelocList.Count;
|
|
i++, pal = pal->Next) {
|
|
|
|
// skip already processed entries
|
|
//if (pal->Flags & ARG_Processed) {
|
|
// continue;
|
|
//}
|
|
|
|
// Relocations are only in the .DATA section
|
|
dwBeginOffset = atoi(pal->OriginalName) - mppc_baseOfInitData;
|
|
dwEndOffset = dwBeginOffset + atoi(pal->ModifiedName);
|
|
|
|
// TODO: Doing a sequential search for the time being and
|
|
// Change it to binary search - ShankarV
|
|
|
|
for ( j = 0; j < old_mppc_numRelocations; j++) {
|
|
|
|
if (OFFSET(pOldRelocInstrTable[j].instr) < dwBeginOffset) {
|
|
continue;
|
|
} else if (OFFSET(pOldRelocInstrTable[j].instr) >= dwEndOffset) {
|
|
break;
|
|
} else {
|
|
// opCODE should not be already zero.
|
|
// If it is, then just assert for testing purposes
|
|
assert(pOldRelocInstrTable[j].instr & 0xE0000000);
|
|
#ifdef INSTRUMENT
|
|
LogNoteEvent(Log, SZILINK, SZBASERELOCS, letypeEvent,
|
|
"Deleting Base Relocs: at offset %d and RelocType %d",
|
|
OFFSET(pOldRelocInstrTable[j].instr),
|
|
(pOldRelocInstrTable[j].instr) >> 29);
|
|
#endif // INSTRUMENT
|
|
// Make the opCODE illegal by putting 0
|
|
pOldRelocInstrTable[j].instr = OFFSET(pOldRelocInstrTable[j].instr);
|
|
num_deletions++;
|
|
}
|
|
}
|
|
|
|
pal->Flags |= ARG_Processed;
|
|
}
|
|
|
|
return num_deletions;
|
|
}
|
|
|
|
|
|
void
|
|
MppcUpdateRelocTable(
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Updates the Relocation table during subsequent
|
|
Incremental Linking. The way this works is as
|
|
follows: First the new relocs are sorted, Then the old reloc
|
|
table is read from memory and all the relocs whose CONs have
|
|
gone away are deleted. This list is maintained in the
|
|
ZappedBaseRelocList. Then we do a merge sort of the old
|
|
and new reloc list and write it into memory.
|
|
|
|
--*/
|
|
{
|
|
RELOCATION_HEADER relocHeader;
|
|
DWORD old_mppc_numRelocations;
|
|
DWORD num_deletions;
|
|
RELOCATION_INSTR *pOldRelocInstrTable;
|
|
DWORD i = 0;
|
|
DWORD j = 0;
|
|
DWORD ulWrittenSoFar = 0;
|
|
LONG count;
|
|
DWORD sOffset;
|
|
DWORD opcode;
|
|
RELOCATION_INFO *nextRel;
|
|
IMPORT_INFO *pimportinfo;
|
|
|
|
|
|
// First qsort the new relocations
|
|
qsort((void *) pRelocTable, (size_t) cRelocsAdded,
|
|
sizeof(RELOCATION_INFO), PpcCompareReloc);
|
|
|
|
#if DBG
|
|
KillDuplicateRelocs();
|
|
#endif
|
|
|
|
// Read the relocation header
|
|
// pbri->cblk contains the relocationHeaderOffset
|
|
|
|
FileSeek(FileWriteHandle,
|
|
pconPowerMacLoader->foRawDataDest + pimage->bri.cblk,
|
|
SEEK_SET);
|
|
FileRead(FileWriteHandle, &relocHeader, sizeof(RELOCATION_HEADER));
|
|
|
|
// Find out the number of relocations already in the pimage
|
|
|
|
old_mppc_numRelocations = DwSwap(relocHeader.nbrOfRelocs);
|
|
|
|
// Allocate memory for the old relocation table
|
|
|
|
pOldRelocInstrTable = (RELOCATION_INSTR *) PvAllocZ
|
|
(old_mppc_numRelocations * sizeof(RELOCATION_INSTR));
|
|
|
|
// Seek to the old relocation table in the image and read the table
|
|
// pbri->rvaBase contains the relocInstrTableOffset
|
|
|
|
FileSeek(FileWriteHandle, pconPowerMacLoader->foRawDataDest +
|
|
pimage->bri.rvaBase, SEEK_SET);
|
|
FileRead(FileWriteHandle, pOldRelocInstrTable,
|
|
old_mppc_numRelocations * sizeof(RELOCATION_INSTR));
|
|
|
|
// Now zap the deleted relocations
|
|
|
|
num_deletions = ZapDeletedOldBaseRelocs(pOldRelocInstrTable,
|
|
old_mppc_numRelocations);
|
|
|
|
// Calculate the total number of combined relocations
|
|
|
|
relocHeader.nbrOfRelocs = cRelocsAdded +
|
|
old_mppc_numRelocations - num_deletions;
|
|
|
|
// Check for possible overflow in the relocation table
|
|
|
|
if (relocHeader.nbrOfRelocs * sizeof(RELOCATION_INSTR) >= pimage->bri.crelFree) {
|
|
// assert(relocHeader.nbrOfRelocs * sizeof(RELOCATION_INSTR) < pimage->bri.crelFree);
|
|
|
|
errInc = errBaseReloc;
|
|
#ifdef INSTRUMENT
|
|
LogNoteEvent(Log, SZILINK, SZPASS2, letypeEvent, "not enough space for base relocs");
|
|
#endif // INSTRUMENT
|
|
return;
|
|
}
|
|
|
|
// At this time we don't know the actual number of relocations we are going to write
|
|
// because of duplicates. So the relocation header is written on to the exe at the end
|
|
// of this function, after identifying the actual number through ulWrittenSoFar
|
|
|
|
// Now once again seek to the beginning of the relocation table in the image
|
|
// and start writing the new table. Remember pbri->rvaBase contains the
|
|
// relocInstrTableOffset.
|
|
FileSeek(FileWriteHandle, pconPowerMacLoader->foRawDataDest +
|
|
pimage->bri.rvaBase, SEEK_SET);
|
|
|
|
// Now do a merge sort of new and old relocations
|
|
curRelocTable = pRelocTable;
|
|
while (i < (DWORD) cRelocsAdded) {
|
|
|
|
sOffset = curRelocTable->sectionOffset;
|
|
while (j < old_mppc_numRelocations &&
|
|
!(pOldRelocInstrTable[j].instr & 0xE0000000) ) {
|
|
j++;
|
|
}
|
|
|
|
if (j < old_mppc_numRelocations &&
|
|
OFFSET(pOldRelocInstrTable[j].instr) == sOffset ) {
|
|
// The case where both the relocation addresses are
|
|
// the same, write the new one!
|
|
j++;
|
|
continue;
|
|
}
|
|
|
|
if (j < old_mppc_numRelocations &&
|
|
OFFSET(pOldRelocInstrTable[j].instr) < sOffset ) {
|
|
FileWrite(FileWriteHandle, &pOldRelocInstrTable[j],
|
|
sizeof(RELOCATION_INSTR));
|
|
ulWrittenSoFar++;
|
|
j++;
|
|
continue;
|
|
}
|
|
|
|
// Else process the new relocations
|
|
switch (curRelocTable->type) {
|
|
case DDAT_RELO :
|
|
opcode = opDDAT | OFFSET(sOffset);
|
|
count = 1;
|
|
nextRel = curRelocTable + 1;
|
|
curRelocTable->relocInstr.instr = opcode;
|
|
curRelocTable->relocInstr.count = count;
|
|
break;
|
|
|
|
case DESC_RELO :
|
|
opcode = opDESC | OFFSET(sOffset);
|
|
nextRel = curRelocTable + 1;
|
|
curRelocTable->relocInstr.instr = opcode;
|
|
curRelocTable->relocInstr.count = 1;
|
|
break;
|
|
|
|
case SYMB_RELO :
|
|
opcode = opSYMB | OFFSET(sOffset);
|
|
nextRel = curRelocTable + 1;
|
|
curRelocTable->relocInstr.instr = opcode;
|
|
pimportinfo = curRelocTable->pimportinfo;
|
|
curRelocTable->relocInstr.count = pimportinfo->order;
|
|
break;
|
|
|
|
case CODE_RELO :
|
|
opcode = opCODE | OFFSET(sOffset);
|
|
nextRel = curRelocTable + 1;
|
|
curRelocTable->relocInstr.instr = opcode;
|
|
curRelocTable->relocInstr.count = 1;
|
|
break;
|
|
|
|
default :
|
|
nextRel = curRelocTable + 1;
|
|
break;
|
|
}
|
|
|
|
FileWrite(FileWriteHandle, &curRelocTable->relocInstr,
|
|
sizeof(RELOCATION_INSTR));
|
|
ulWrittenSoFar++;
|
|
i++;
|
|
|
|
curRelocTable = nextRel; /* increment to the next relocation */
|
|
}
|
|
|
|
// Finish writing the remainder of j (old_mppc_base_relocs)
|
|
|
|
while (j < old_mppc_numRelocations) {
|
|
if (pOldRelocInstrTable[j].instr & 0xE0000000) {
|
|
FileWrite(FileWriteHandle, &pOldRelocInstrTable[j],
|
|
sizeof(RELOCATION_INSTR));
|
|
ulWrittenSoFar++;
|
|
}
|
|
|
|
j++;
|
|
}
|
|
|
|
// Zero out the pad (remaining space).
|
|
// Only up to the old relocations point
|
|
// TODO: do memset - ShankarV
|
|
|
|
j = 0;
|
|
i = ulWrittenSoFar * sizeof(RELOCATION_INSTR);
|
|
while (i < old_mppc_numRelocations * sizeof(RELOCATION_INSTR)) {
|
|
FileWrite(FileWriteHandle, &j, sizeof(DWORD));
|
|
i += sizeof(DWORD);
|
|
}
|
|
|
|
// Write the total number of combined relocations back to pimage
|
|
|
|
relocHeader.nbrOfRelocs = DwSwap(ulWrittenSoFar);
|
|
|
|
// pbri->cblk contains the relocationHeaderOffset
|
|
|
|
FileSeek(FileWriteHandle, pconPowerMacLoader->foRawDataDest +
|
|
pimage->bri.cblk, SEEK_SET);
|
|
FileWrite(FileWriteHandle, &relocHeader, sizeof(RELOCATION_HEADER));
|
|
|
|
// TODO: Make it nice by printing the reloc table - ShankarV
|
|
// DBEXEC(DB_PPC_RELOC, PrintRelocTable(pRelocTable));
|
|
}
|
|
|
|
|
|
|
|
void
|
|
MppcDoIncrInit(
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Do PowerMac specific initialization. Get the pcons
|
|
for Toc Table, Descriptors, and Glue Code
|
|
|
|
Argument:
|
|
pointer to image.
|
|
|
|
Return Value:
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
PSEC psec;
|
|
PGRP pgrp;
|
|
ENM_DST enm_dst;
|
|
|
|
pextToc = SearchExternSz(pimage->pst, "__TocTb");
|
|
assert(pextToc != NULL);
|
|
|
|
pextFTInfo = SearchExternSz(pimage->pst, "__FTInfo");
|
|
assert(pextFTInfo != NULL);
|
|
|
|
// Get the pconPowerMacLoader.
|
|
|
|
psecPowerMacLoader = PsecFind(NULL,
|
|
ReservedSection.PowerMacLoader.Name,
|
|
ReservedSection.PowerMacLoader.Characteristics,
|
|
&pimage->secs,
|
|
&pimage->ImgOptHdr);
|
|
assert(psecPowerMacLoader);
|
|
pgrp = PgrpFind(psecPowerMacLoader, ReservedSection.PowerMacLoader.Name);
|
|
assert(pgrp);
|
|
|
|
// If there are more than one Pcon, then assert!
|
|
InitEnmDst(&enm_dst, pgrp);
|
|
if (FNextEnmDst(&enm_dst)) {
|
|
pconPowerMacLoader = enm_dst.pcon;
|
|
}
|
|
assert(!FNextEnmDst(&enm_dst));
|
|
|
|
// Get the pconGlueCode
|
|
|
|
psec = PsecFind(NULL,
|
|
ReservedSection.Text.Name,
|
|
ReservedSection.Text.Characteristics,
|
|
&pimage->secs,
|
|
&pimage->ImgOptHdr);
|
|
assert(psec);
|
|
pgrp = PgrpFind(psec, GLUE_GROUP_NAME);
|
|
assert(pgrp);
|
|
|
|
// If there are more than one Pcon, then assert!
|
|
|
|
InitEnmDst(&enm_dst, pgrp);
|
|
if (FNextEnmDst(&enm_dst)) {
|
|
pconGlueCode = enm_dst.pcon;
|
|
}
|
|
assert(!FNextEnmDst(&enm_dst));
|
|
|
|
psecData = PsecFind(NULL,
|
|
ReservedSection.Data.Name,
|
|
ReservedSection.Data.Characteristics,
|
|
&pimage->secs,
|
|
&pimage->ImgOptHdr);
|
|
assert(psecData);
|
|
|
|
// Identify the C++ EH pdata group inside the .data section
|
|
// This may be null
|
|
|
|
pgrpPdata = PgrpFind(psecData, ReservedSection.Exception.Name);
|
|
|
|
// Identify .data group within .data section
|
|
|
|
pgrp = PgrpFind(psecData, ReservedSection.Data.Name);
|
|
assert(pgrp);
|
|
|
|
// Get the pcon for the TOC table, TOC descriptors, and C++ EH Func Table
|
|
// They are the first three pcon of their groups (.data)
|
|
// (ReservedSection.Data.Name).
|
|
// Should we move these cons into their own group? - ShankarV
|
|
|
|
InitEnmDst(&enm_dst, pgrp);
|
|
if (FNextEnmDst(&enm_dst)) {
|
|
pconTocTable = enm_dst.pcon;
|
|
}
|
|
if (FNextEnmDst(&enm_dst)) {
|
|
pconTocDescriptors = enm_dst.pcon;
|
|
}
|
|
if (FNextEnmDst(&enm_dst)) {
|
|
pconMppcFuncTable = enm_dst.pcon;
|
|
// With this we can find out the number of code Fragments
|
|
}
|
|
|
|
mppc_numTocEntries =
|
|
(pconTocTable->cbRawData - pconTocTable->cbPad) / sizeof(DWORD);
|
|
|
|
mppc_numDescriptors =
|
|
(pconTocDescriptors->cbRawData - pconTocDescriptors->cbPad) / 12;
|
|
|
|
// The new number of base relocations is set to Zero
|
|
// The original number of base relocations are read from the image
|
|
// during MppcUpdateRelocTable
|
|
|
|
mppc_numRelocations = 0;
|
|
|
|
pcontainerlistHead = pimage->pcontainerlistHead;
|
|
}
|
|
|
|
|
|
void
|
|
MppcCheckIncrTables(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
To check if the TOC table or TOC descriptors overflow.
|
|
Also to allocate space for the new relocations
|
|
|
|
Argument:
|
|
None.
|
|
|
|
Return Value:
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
if (mppc_numTocEntries * sizeof(DWORD) > pconTocTable->cbRawData) {
|
|
errInc = errTocTblOverflow;
|
|
|
|
#ifdef INSTRUMENT
|
|
LogNoteEvent(Log, SZILINK, SZPASS1, letypeEvent, "not enough space for Toc Table entries");
|
|
#endif // INSTRUMENT
|
|
return;
|
|
}
|
|
|
|
if ((DWORD) mppc_numDescriptors * 12 > pconTocDescriptors->cbRawData) {
|
|
errInc = errDescOverflow;
|
|
|
|
#ifdef INSTRUMENT
|
|
LogNoteEvent(Log, SZILINK, SZPASS1, letypeEvent, "not enough space for Descriptors");
|
|
#endif // INSTRUMENT
|
|
return;
|
|
}
|
|
|
|
// We have to reset the size of the PconTocTable
|
|
// to reflect the newly added entries
|
|
pconTocTable->cbPad = pconTocTable->cbRawData -
|
|
mppc_numTocEntries * sizeof(DWORD);
|
|
|
|
// We have to reset the size of the PconTocDescriptors
|
|
// to reflect the newly added entries
|
|
pconTocDescriptors->cbPad = pconTocDescriptors->cbRawData -
|
|
mppc_numDescriptors * 12;
|
|
|
|
// Allocating memory for the new set of relocations
|
|
// The extra one is for .icsym
|
|
pRelocTable = (RELOCATION_INFO *)
|
|
PvAllocZ((mppc_numRelocations + 1) * sizeof(RELOCATION_INFO));
|
|
|
|
curRelocTable = pRelocTable;
|
|
|
|
}
|
|
|
|
|
|
#if DBG
|
|
|
|
void
|
|
DumpMppcEHFunctionTable (
|
|
PIMAGE_RUNTIME_FUNCTION_ENTRY pdata,
|
|
DWORD dwPDataCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads and prints each pdata table entry.
|
|
|
|
Arguments:
|
|
|
|
PIMAGE_RUNTIME_FUNCTION_ENTRY and its count.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwBegin;
|
|
|
|
printf("\nFunction Table (%ld)\n\n", dwPDataCount);
|
|
printf(" Begin End Excptn ExcpDat Prolog \n\n");
|
|
|
|
dwBegin = (DWORD) pdata;
|
|
for (; dwPDataCount; dwPDataCount--, pdata++) {
|
|
DWORD ib;
|
|
|
|
ib = (DWORD) pdata - dwBegin;
|
|
|
|
printf("%08x %08x %08x %08x %08x %08x \n",
|
|
ib,
|
|
pdata->BeginAddress,
|
|
pdata->EndAddress,
|
|
(DWORD) pdata->ExceptionHandler,
|
|
(DWORD) pdata->HandlerData,
|
|
pdata->PrologEndAddress);
|
|
|
|
// How do I get the function name?
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
INT __cdecl
|
|
ComparePData (
|
|
void const *p1,
|
|
void const *p2
|
|
)
|
|
{
|
|
if (((PIMAGE_RUNTIME_FUNCTION_ENTRY)p1)->BeginAddress <
|
|
((PIMAGE_RUNTIME_FUNCTION_ENTRY)p2)->BeginAddress) {
|
|
return(-1);
|
|
}
|
|
|
|
if (((PIMAGE_RUNTIME_FUNCTION_ENTRY)p1)->BeginAddress >
|
|
((PIMAGE_RUNTIME_FUNCTION_ENTRY)p2)->BeginAddress) {
|
|
return(1);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
STATIC
|
|
void
|
|
SortPData(
|
|
DWORD dwPDataSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Sort the contents of the .pdata group
|
|
within the .data section
|
|
|
|
--*/
|
|
{
|
|
// pgrpPData->cb has the padding also.
|
|
|
|
DWORD i;
|
|
DWORD dwPDataCount = dwPDataSize / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY);
|
|
PIMAGE_RUNTIME_FUNCTION_ENTRY pdata;
|
|
|
|
pdata = (PIMAGE_RUNTIME_FUNCTION_ENTRY) PvAlloc(dwPDataSize);
|
|
|
|
// Read the entire pdata
|
|
|
|
FileSeek(FileWriteHandle, pgrpPdata->foRawData, SEEK_SET);
|
|
FileRead(FileWriteHandle, pdata, dwPDataSize);
|
|
|
|
// Swap bytes for the begin address alone before sorting
|
|
|
|
for (i = 0; i < dwPDataCount; i++) {
|
|
SwapBytes(&pdata[i], 4);
|
|
}
|
|
|
|
qsort((void *) pdata, dwPDataCount, sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY), ComparePData);
|
|
|
|
// Re-Swap bytes for the begin address alone before writing it back to the exe
|
|
|
|
for (i = 0; i < dwPDataCount; i++) {
|
|
SwapBytes(&pdata[i], 4);
|
|
}
|
|
|
|
// Write the pdata back into the executable
|
|
|
|
FileSeek(FileWriteHandle, pgrpPdata->foRawData, SEEK_SET);
|
|
FileWrite(FileWriteHandle, pdata, dwPDataSize);
|
|
}
|
|
|
|
|
|
void
|
|
MppcDoCxxEHFixUps(
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Do the function table fixups
|
|
for C++ Exception Handling
|
|
|
|
--*/
|
|
{
|
|
// First write the address of the Function Table in the 16th Index of TOC Table
|
|
|
|
LONG ibToc = FUNC_TABLE_TOC_INDEX * 4 - MPPC_TOC_BIAS;
|
|
|
|
if (pimage->Switch.Link.DebugType & FixupDebug) {
|
|
DWORD rvaCur = pextToc->FinalValue + ibToc;
|
|
DWORD rvaTarget = pextFTInfo->FinalValue;
|
|
|
|
SaveDebugFixup(IMAGE_REL_MPPC_DATAREL, 0, rvaCur, rvaTarget);
|
|
}
|
|
|
|
FileSeek(FileWriteHandle, pconTocTable->foRawDataDest + MPPC_TOC_BIAS + ibToc, SEEK_SET);
|
|
|
|
BOOL fText;
|
|
DWORD dwAddress = BiasAddress(pextFTInfo->FinalValue, &fText);
|
|
assert(!fText);
|
|
|
|
SwapBytes(&dwAddress, 4);
|
|
FileWrite(FileWriteHandle, &dwAddress, sizeof(DWORD));
|
|
|
|
SET_BIT(pextFTInfo, sy_TOCENTRYFIXEDUP);
|
|
SET_BIT(pextFTInfo, sy_TOCRELOCADDED);
|
|
|
|
// Next add the 16th entry of TOC Table as a relocation
|
|
|
|
AddRelocation(pextToc->FinalValue + ibToc - mppc_baseOfInitData,
|
|
DDAT_RELO,
|
|
NULL);
|
|
|
|
// Now start writing data inside the Function Table Info structure
|
|
|
|
FTINFO ftinfo;
|
|
ftinfo.dwMagicNumber = 0;
|
|
ftinfo.pFrameInfo = NULL;
|
|
|
|
if (pgrpPdata != NULL) {
|
|
// This condition is necessary because DLLs may not have PData but
|
|
// would require the rest of the entries fixed up!
|
|
|
|
if (pimage->Switch.Link.DebugType & FixupDebug) {
|
|
DWORD rvaCur = pconMppcFuncTable->rva + offsetof(FTINFO, rgFuncTable);
|
|
DWORD rvaTarget = pgrpPdata->rva;
|
|
|
|
// A wExtra of 2 indicates that this relocation occurs on __FTINFO
|
|
|
|
SaveDebugFixup(IMAGE_REL_MPPC_DATAREL, 2, rvaCur, rvaTarget);
|
|
}
|
|
|
|
// Find out the offset of the pdata from the beginning of the init data
|
|
|
|
ftinfo.rgFuncTable = pgrpPdata->rva - mppc_baseOfInitData;
|
|
|
|
// Now find out the size of the (pdata) compiler generated Function Table
|
|
// from the total raw data size of the group
|
|
|
|
ftinfo.cbFuncTable = fINCR ? pimage->pdatai.ipdataMac :
|
|
pgrpPdata->cb / sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY);
|
|
|
|
// Also make the address of the Function Table (pointer to PData) a load time fix-up
|
|
|
|
AddRelocation(pconMppcFuncTable->rva + offsetof(FTINFO, rgFuncTable) - mppc_baseOfInitData,
|
|
DDAT_RELO,
|
|
NULL);
|
|
|
|
if (!fINCR) {
|
|
// Sort PData entries if it is not an iLink.
|
|
// The sorting is done by WritePdataRecords in the case of iLink
|
|
|
|
SortPData(pgrpPdata->cb);
|
|
}
|
|
} else {
|
|
// No .pdata
|
|
|
|
ftinfo.rgFuncTable = NULL;
|
|
ftinfo.cbFuncTable = 0;
|
|
}
|
|
|
|
// Find out the beginning of the code Fragment
|
|
|
|
ftinfo.dwEntryCF = 0; // It is 0 because we will soon add this as a load time reloc
|
|
|
|
// Now find out the size of the code section. Another way to do this would be
|
|
// to subtract mppc_baseOfCode from mppc_baseOfInitData
|
|
|
|
PSEC psec = PsecFind(NULL,
|
|
ReservedSection.Text.Name,
|
|
ReservedSection.Text.Characteristics,
|
|
&pimage->secs,
|
|
&pimage->ImgOptHdr);
|
|
assert(psec);
|
|
ftinfo.dwSizeCF = psec->cbRawData;
|
|
|
|
// Take care of this sizeof business when we do multiple code fragments
|
|
|
|
SwapBytes(&ftinfo, sizeof(FTINFO));
|
|
|
|
assert(pconMppcFuncTable->foRawDataDest);
|
|
|
|
// Write out the FTInfo structure
|
|
|
|
FileSeek(FileWriteHandle, pconMppcFuncTable->foRawDataDest, SEEK_SET);
|
|
FileWrite(FileWriteHandle, &ftinfo, sizeof(FTINFO));
|
|
|
|
// Also make the address of starting of the code fragment a load time fix-up
|
|
|
|
if (pimage->Switch.Link.DebugType & FixupDebug) {
|
|
DWORD rvaCur = pconMppcFuncTable->rva + offsetof(FTINFO, dwEntryCF);
|
|
DWORD rvaTarget = mppc_baseOfCode;
|
|
|
|
// A wExtra of 2 indicates that this relocation occurs on __FTINFO
|
|
|
|
SaveDebugFixup(IMAGE_REL_MPPC_DATAREL, 2, rvaCur, rvaTarget);
|
|
}
|
|
|
|
AddRelocation(pconMppcFuncTable->rva + offsetof(FTINFO, dwEntryCF) - mppc_baseOfInitData,
|
|
CODE_RELO,
|
|
NULL);
|
|
|
|
}
|
|
|
|
void
|
|
MppcZeroOutCONs(
|
|
PIMAGE pimage
|
|
)
|
|
{
|
|
DWORD cbMem;
|
|
|
|
if (fIncrDbFile) {
|
|
return;
|
|
}
|
|
|
|
cbMem = __max(pconTocTable->cbRawData, pconMppcFuncTable->cbRawData);
|
|
cbMem = __max(cbMem, pconTocDescriptors->cbRawData);
|
|
cbMem = __max(cbMem, pconGlueCode->cbRawData);
|
|
cbMem = __max(cbMem, pconPowerMacLoader->cbRawData);
|
|
|
|
void *pvZero = (char *) PvAllocZ(cbMem);
|
|
|
|
FileSeek(FileWriteHandle, pconTocTable->foRawDataDest, SEEK_SET);
|
|
FileWrite(FileWriteHandle, pvZero, pconTocTable->cbRawData);
|
|
FileSeek(FileWriteHandle, pconMppcFuncTable->foRawDataDest, SEEK_SET);
|
|
FileWrite(FileWriteHandle, pvZero, pconMppcFuncTable->cbRawData);
|
|
FileSeek(FileWriteHandle, pconTocDescriptors->foRawDataDest, SEEK_SET);
|
|
FileWrite(FileWriteHandle, pvZero, pconTocDescriptors->cbRawData);
|
|
FileSeek(FileWriteHandle, pconGlueCode->foRawDataDest, SEEK_SET);
|
|
FileWrite(FileWriteHandle, pvZero, pconGlueCode->cbRawData);
|
|
FileSeek(FileWriteHandle, pconPowerMacLoader->foRawDataDest, SEEK_SET);
|
|
FileWrite(FileWriteHandle, pvZero, pconPowerMacLoader->cbRawData);
|
|
|
|
FreePv(pvZero);
|
|
}
|
|
|
|
|
|
#ifdef MFILE_PAD
|
|
|
|
DWORD
|
|
CalculateMFilePad(
|
|
DWORD cbConSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Given the size of CON
|
|
size of the pad is calculated
|
|
If 120% of the contribution is < 1024,
|
|
it will be rounded up to the nearest power of 2.
|
|
If 120% of the contribution is >= 1024,
|
|
it will be rounded up to the nearest multiple of 1024.
|
|
All contributions that are less than 14 bytes
|
|
will be rounded up to 16 bytes.
|
|
|
|
Argument:
|
|
con size
|
|
|
|
Return Value:
|
|
pad
|
|
|
|
--*/
|
|
{
|
|
DWORD cb120percent = (cbConSize * 12) / 10;
|
|
|
|
if (cbConSize == 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (cb120percent < 16) {
|
|
return (16 - cbConSize);
|
|
}
|
|
|
|
if (cb120percent < _1K) {
|
|
DWORD cbTemp = 1;
|
|
|
|
while (cb120percent) {
|
|
cb120percent >>= 1;
|
|
cbTemp <<= 1;
|
|
}
|
|
|
|
return cbTemp - cbConSize;
|
|
}
|
|
|
|
return (1 + cb120percent / _1K) * _1K - cbConSize;
|
|
// or return 1024 - (cbConSize & 1023)
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
void
|
|
MppcFixCxxEHTableOnILink(
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Fix the FTInfo structure during iLink
|
|
|
|
Argument:
|
|
PIMAGE
|
|
|
|
Return Value:
|
|
none
|
|
|
|
--*/
|
|
{
|
|
DWORD dwNewEntries = pimage->pdatai.ipdataMac;
|
|
union {
|
|
DWORD dwOldEntries;
|
|
DWORD rgFuncTable;
|
|
};
|
|
|
|
// Check the number of old entries
|
|
|
|
FileSeek(FileWriteHandle, 12 + pconMppcFuncTable->foRawDataDest, SEEK_SET);
|
|
FileRead(FileWriteHandle, &dwOldEntries, sizeof(DWORD));
|
|
SwapBytes(&dwOldEntries, 4);
|
|
|
|
if (dwOldEntries < dwNewEntries) {
|
|
// We need to add relocations
|
|
|
|
BOOL fText;
|
|
|
|
DWORD PdataAddrBias = BiasAddress(pgrpPdata->rva, &fText);
|
|
|
|
assert(!fText);
|
|
|
|
// The mppc_numRelocations have already been incremented in
|
|
// CountRelocsInSection in shared.cpp
|
|
|
|
for (DWORD i = dwOldEntries; i < dwNewEntries; i++) {
|
|
// This is for the DATADESCREL (the middle entry of the pdata table
|
|
|
|
if (fEHfuncXToc) {
|
|
assert(pFrameHandler != NULL);
|
|
|
|
AddRelocation(PdataAddrBias + i * sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY) + 8,
|
|
SYMB_RELO,
|
|
pFrameHandler);
|
|
} else {
|
|
AddRelocation(PdataAddrBias + i * sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY) + 8,
|
|
DDAT_RELO,
|
|
NULL);
|
|
}
|
|
|
|
// This is for the DATAREL
|
|
|
|
AddRelocation(PdataAddrBias + i * sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY) + 12,
|
|
DDAT_RELO,
|
|
NULL);
|
|
|
|
// The JMPADDR do not have any relocations to be added
|
|
}
|
|
} else if (dwOldEntries > dwNewEntries) {
|
|
CHAR szBuffer[12];
|
|
|
|
// Let us zap the unnecessary relocs
|
|
|
|
AddArgumentToList(&ZappedBaseRelocList,
|
|
SzDup(_itoa(pgrpPdata->rva + dwNewEntries * sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY), szBuffer, 10)),
|
|
SzDup(_itoa((dwOldEntries - dwNewEntries) * sizeof(IMAGE_RUNTIME_FUNCTION_ENTRY), szBuffer, 10)) );
|
|
}
|
|
|
|
// Time to byte swap
|
|
SwapBytes(&dwNewEntries, 4);
|
|
// Write the total number of new Function Table entries
|
|
FileSeek(FileWriteHandle, 12 + pconMppcFuncTable->foRawDataDest, SEEK_SET);
|
|
FileWrite(FileWriteHandle, &dwNewEntries, sizeof(DWORD));
|
|
|
|
// Now make sure that the pgrpPdata starts at the same location
|
|
FileSeek(FileWriteHandle, 8 + pconMppcFuncTable->foRawDataDest, SEEK_SET);
|
|
FileRead(FileWriteHandle, &rgFuncTable, sizeof(DWORD));
|
|
SwapBytes(&rgFuncTable, 4);
|
|
assert(rgFuncTable == pgrpPdata->rva - mppc_baseOfInitData);
|
|
|
|
// TODO: Should we also write the total size of the code section? - ShankarV
|
|
}
|
|
|
|
|
|
const char *SzMPPCRelocationType(WORD wType, WORD *pcb, BOOL *pfSymValid)
|
|
{
|
|
const char *szName;
|
|
WORD cb;
|
|
BOOL fSymValid = TRUE;
|
|
|
|
switch (wType) {
|
|
case IMAGE_REL_MPPC_TOCCALLREL :
|
|
szName = "TOCCALLREL";
|
|
cb = 2 * sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_LCALL :
|
|
szName = "LCALL";
|
|
cb = 0;
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_DATAREL :
|
|
szName = "DATAREL";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_TOCINDIRCALL :
|
|
szName = "TOCINDIRCALL";
|
|
cb = 2 * sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_TOCREL :
|
|
szName = "TOCREL";
|
|
cb = sizeof(WORD);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_DESCREL :
|
|
szName = "DESCREL";
|
|
cb = 2 * sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_DATADESCRREL :
|
|
szName = "DATADESCRREL";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_CREATEDESCRREL :
|
|
szName = "CREATEDESCRREL";
|
|
cb = sizeof(WORD);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_JMPADDR :
|
|
szName = "JMPADDR";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_SECTION :
|
|
szName = "SECTION";
|
|
cb = sizeof(SHORT);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_SECREL :
|
|
szName = "SECREL";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_ADDR24 :
|
|
szName = "ADDR24";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_ADDR14 :
|
|
szName = "ADDR14";
|
|
cb = sizeof(WORD);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_REL24 :
|
|
szName = "REL24";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_REL14 :
|
|
szName = "REL14";
|
|
cb = sizeof(WORD);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_CV :
|
|
szName = "CV";
|
|
cb = sizeof(DWORD) + sizeof(SHORT);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_PCODECALL :
|
|
szName = "PCODECALL";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_PCODECALLTONATIVE :
|
|
szName = "PCODECALLTONATIVE";
|
|
cb = sizeof(DWORD);
|
|
break;
|
|
|
|
case IMAGE_REL_MPPC_PCODENEPE :
|
|
szName = "PCODENEPE";
|
|
cb = sizeof(BYTE);
|
|
break;
|
|
|
|
default :
|
|
szName = NULL;
|
|
cb = 0;
|
|
fSymValid = FALSE;
|
|
break;
|
|
}
|
|
|
|
*pcb = cb;
|
|
*pfSymValid = fSymValid;
|
|
|
|
return(szName);
|
|
}
|
|
|
|
|
|
void
|
|
MppcIncrFixExportDescriptors(
|
|
PIMAGE pimage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
Fix the descriptors of the exported
|
|
functions just in case they had moved
|
|
|
|
--*/
|
|
{
|
|
DWORD foCurrent;
|
|
|
|
// Read the loader header
|
|
|
|
FileSeek(FileWriteHandle, pconPowerMacLoader->foRawDataDest, SEEK_SET);
|
|
FileRead(FileWriteHandle, &loaderHeader, sizeof(LOADER_HEADER));
|
|
SwapBytes(&loaderHeader, sizeof(LOADER_HEADER));
|
|
|
|
if (!loaderHeader.nExportedSymbols) {
|
|
return;
|
|
}
|
|
|
|
// Read the string table
|
|
char *rgchStringTable = (char *) PvAlloc(loaderHeader.hashSlotTableOffset
|
|
- loaderHeader.stringTableOffset);
|
|
FileSeek(FileWriteHandle, pconPowerMacLoader->foRawDataDest +
|
|
loaderHeader.stringTableOffset, SEEK_SET);
|
|
FileRead(FileWriteHandle, rgchStringTable,
|
|
loaderHeader.hashSlotTableOffset - loaderHeader.stringTableOffset);
|
|
|
|
// Calculate the hash (export) chain table offset from the beginning of loader section
|
|
foCurrent = loaderHeader.hashSlotTableOffset +
|
|
((1 << loaderHeader.hashSlotCount) * sizeof(HASH_SLOT_TABLE));
|
|
|
|
#if 0
|
|
// The hash table gives the length of the strings. However
|
|
// we have incorrectly implemented the string table with terminating
|
|
// zero for symbols. So this code will be required if we are correcting the problem
|
|
// Now read the hash (export) chain table
|
|
HASH_CHAIN_TABLE *chainTable = (HASH_CHAIN_TABLE *)
|
|
PvAlloc(loaderHeader.nExportedSymbols * sizeof(HASH_CHAIN_TABLE));
|
|
FileSeek(FileWriteHandle, pconPowerMacLoader->foRawDataDest + foCurrent, SEEK_SET);
|
|
FileRead(FileWriteHandle, chainTable,
|
|
loaderHeader.nExportedSymbols * sizeof(HASH_CHAIN_TABLE));
|
|
// We don't need to swap bytes here because they are strings
|
|
#endif
|
|
|
|
// Calculate the hash (export) symbol table offset from the beginning of loader section
|
|
foCurrent += (loaderHeader.nExportedSymbols * sizeof(HASH_CHAIN_TABLE));
|
|
// Next read the export symbol table
|
|
|
|
// This assert is no good because of padding for the contribution
|
|
// assert(pconPowerMacLoader->cbRawData - foCurrent ==
|
|
// EXPORT_SYMBOL_TABLESZ * loaderHeader.nExportedSymbols);
|
|
BYTE *pbExport = (BYTE *) PvAlloc(EXPORT_SYMBOL_TABLESZ *
|
|
loaderHeader.nExportedSymbols);
|
|
FileSeek(FileWriteHandle, pconPowerMacLoader->foRawDataDest + foCurrent, SEEK_SET);
|
|
FileRead(FileWriteHandle, pbExport,
|
|
EXPORT_SYMBOL_TABLESZ * loaderHeader.nExportedSymbols);
|
|
|
|
for (DWORD i = 0; i < loaderHeader.nExportedSymbols; i++) {
|
|
DWORD ichName;
|
|
const char *szName;
|
|
char szSymbol[200];
|
|
PEXTERNAL pext;
|
|
PEXTERNAL pextDot;
|
|
|
|
#if 0
|
|
HASH_CHAIN_TABLE hash;
|
|
hash = *(chainTable + i);
|
|
SwapBytes((BYTE *) &hash, 4);
|
|
#endif
|
|
|
|
ichName = *(DWORD *) (pbExport + i * EXPORT_SYMBOL_TABLESZ);
|
|
SwapBytes((BYTE *) &ichName, 4);
|
|
|
|
ichName &= 0xFFFFFF;
|
|
|
|
szName = rgchStringTable + ichName;
|
|
if (*szName != '?') {
|
|
strcpy(szSymbol, "_");
|
|
strcat(szSymbol, szName);
|
|
} else {
|
|
strcpy(szSymbol, szName);
|
|
}
|
|
pext = SearchExternSz(pimage->pst, szSymbol);
|
|
pextDot = GetDotExtern(szName, pimage, FALSE);
|
|
|
|
if (pextDot) {
|
|
DWORD codeOffset;
|
|
|
|
// We can't call MppcFixIncrDotExternFlags(szName, pimage) here
|
|
// because the export descriptors are .foo and not ._foo
|
|
// TODO: Fix this bloke - ShankarV
|
|
|
|
RESET_BIT(pextDot, sy_DESCRRELWRITTEN);
|
|
|
|
// TODO: Check for PCode as in WriteExportSymbolTableEntry - ShankarV
|
|
|
|
codeOffset = pext->ImageSymbol.Value;
|
|
if (pext->pcon) {
|
|
codeOffset += (pext->pcon->rva - mppc_baseOfCode);
|
|
}
|
|
|
|
FixupDescriptor(szSymbol, pextDot, codeOffset, pimage, TRUE);
|
|
} else {
|
|
EXPORT_SYMBOL_TABLE symbol;
|
|
union
|
|
{
|
|
DWORD temp;
|
|
BYTE off[4];
|
|
} x;
|
|
|
|
// This is caused by a data export which does not have a descriptor
|
|
// See code in WriteExportSymbolTableEntry for better understanding
|
|
|
|
x.temp = DwSwap(ichName); // This is the offset into the stringtable
|
|
symbol.nameOffset[0] = x.off[1];
|
|
symbol.nameOffset[1] = x.off[2];
|
|
symbol.nameOffset[2] = x.off[3];
|
|
symbol.symClass = 2; /* UNDONE: FIX ME */
|
|
|
|
symbol.symOffset = pext->ImageSymbol.Value;
|
|
if (pext->pcon != NULL) {
|
|
symbol.symOffset += pext->pcon->rva - PsecPCON(pext->pcon)->rva;
|
|
}
|
|
symbol.sectionNumber = PPC_PEF_DATA_SECTION;
|
|
|
|
DBEXEC(DB_MPPC_EXPORT,
|
|
{
|
|
printf("ILink: Exp %d %16s offset %08lx\n",
|
|
ExportSymbolTableOffset, szName, symbol.symOffset);
|
|
});
|
|
|
|
SwapBytes(&symbol.symOffset, 4);
|
|
SwapBytes(&symbol.sectionNumber, 2);
|
|
|
|
FileSeek(FileWriteHandle, pconPowerMacLoader->foRawDataDest +
|
|
foCurrent +
|
|
i * EXPORT_SYMBOL_TABLESZ, SEEK_SET);
|
|
FileWrite(FileWriteHandle, &symbol, EXPORT_SYMBOL_TABLESZ);
|
|
}
|
|
}
|
|
|
|
FreePv(rgchStringTable);
|
|
#if 0
|
|
FreePv(chainTable);
|
|
#endif
|
|
FreePv(pbExport);
|
|
}
|
|
|
|
|
|
void
|
|
MppcFixIncrDataMove(
|
|
PEXTERNAL pext,
|
|
PIMAGE pimage
|
|
)
|
|
{
|
|
if (READ_BIT(pext, sy_TOCALLOCATED) &&
|
|
!READ_BIT(pext, sy_TOCENTRYFIXEDUP) &&
|
|
!READ_BIT(pext, sy_CROSSTOCCALL) &&
|
|
!READ_BIT(pext, sy_TOCDESCRREL) &&
|
|
!READ_BIT(pext, sy_ISDOTEXTERN)) {
|
|
// TODO: Do we have to exclude some cases? - ShankarV
|
|
// It should be a simple TOCREL in that case.
|
|
// Data has moved but not fixed up because nothing
|
|
// that referred the data moved.
|
|
|
|
assert(pext->pcon);
|
|
DWORD addr = pext->pcon->rva + pext->ImageSymbol.Value;
|
|
BOOL fText;
|
|
|
|
addr = DwSwap(BiasAddress(addr, &fText));
|
|
assert(!fText);
|
|
|
|
FileSeek(FileWriteHandle,
|
|
pconTocTable->foRawDataDest + MPPC_TOC_BIAS + pext->ibToc,
|
|
SEEK_SET);
|
|
FileWrite(FileWriteHandle, &addr, sizeof(DWORD));
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
MppcWriteGlueCodeExtension(
|
|
PIMAGE pimage
|
|
)
|
|
/* ++
|
|
make use of crossTocGlueExtension
|
|
++ */
|
|
{
|
|
if (!pimage->Switch.Link.fNewGlue) {
|
|
return;
|
|
}
|
|
|
|
if (!fINCR && !pimage->nUniqueCrossTocCalls) {
|
|
// if this is not debug (non-incremental mode) and
|
|
// there are no crossTocCalls, then bail out
|
|
|
|
return;
|
|
}
|
|
|
|
// Swap crossTocGlueExtension
|
|
|
|
SwapBytes(&crossTocGlueExtension, sizeof(crossTocGlueExtension));
|
|
|
|
// We are putting the crossTocGlueExtension at the very top of pconGlueCode
|
|
|
|
assert(pimage->glueOffset == 0);
|
|
|
|
// Stick a public symbol here to make the debugger happy.
|
|
|
|
PEXTERNAL pextGlueExtension = LookupExternSz(pimage->pst, "__glueExtension", NULL);
|
|
SetDefinedExt(pextGlueExtension, TRUE, pimage->pst);
|
|
pextGlueExtension->pcon = pconGlueCode;
|
|
pextGlueExtension->ImageSymbol.Value = pimage->glueOffset;
|
|
pextGlueExtension->FinalValue = pconGlueCode->rva + pimage->glueOffset;
|
|
|
|
// Write out the crossTocGlueExtension
|
|
|
|
FileSeek(FileWriteHandle, pconGlueCode->foRawDataDest + pimage->glueOffset,
|
|
SEEK_SET);
|
|
FileWrite(FileWriteHandle, &crossTocGlueExtension, sizeof(crossTocGlueExtension));
|
|
|
|
pimage->glueOffset += sizeof(crossTocGlueExtension);
|
|
}
|