Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

6155 lines
162 KiB

/***********************************************************************
* Microsoft (R) 32-Bit Incremental Linker
*
* Copyright (C) Microsoft Corp 1992-1996. All rights reserved.
*
* File: shared.cpp
*
* File Comments:
*
* Functions which are common to the COFF Linker/Librarian/Dumper.
*
***********************************************************************/
#include "link.h"
BOOL FIncludeComdat(PIMAGE, PCON, PIMAGE_SYMBOL, SHORT, const char **);
static BLK blkSymbolTable;
static BOOL fSymbolTableInUse;
static BOOL fMappedSyms;
static BLK blkStringTable;
static BOOL fStringTableInUse;
static BOOL fMappedStrings;
static BLK blkRelocs;
static BOOL fRelocsInUse;
static BOOL fMappedRelocs;
static BOOL fWeakToRegular = FALSE;
typedef struct _COMDAT_ISYMS {
DWORD isymSec;
DWORD isymComdat;
} COMDAT_ISYMS;
static COMDAT_ISYMS *rgComdatIsyms = NULL;
// Token parser. Same usage as strtok() but it also handles quotation marks.
// Munges the source buffer.
//
// Return value *pfQuoted indicates whether the string had quotes in it.
char *
SzGetArgument(
char *szText,
BOOL *pfQuoted
)
{
static unsigned char *pchCur = NULL;
unsigned char *szResult;
if (pfQuoted != NULL) {
*pfQuoted = FALSE;
}
if (szText != NULL) {
pchCur = (unsigned char *)szText;
}
assert(pchCur != NULL);
// skip blanks
while (*pchCur != '\0' && _istspace(*pchCur)) {
pchCur++;
}
if (*pchCur == '\0') {
return(char *)(pchCur = NULL);
}
szResult = pchCur;
while (*pchCur != '\0' && !_istspace(*pchCur)) {
if (*pchCur == '"') {
// Found a quote mark ... delete it, delete its match if any,
// and add all characters in between to the current token.
unsigned char *pchOtherQuote;
memmove(pchCur, pchCur + 1, strlen((char *)pchCur + 1) + 1);
if ((pchOtherQuote = (unsigned char *)_tcschr((char *)pchCur, '"')) != NULL) {
memmove(pchOtherQuote, pchOtherQuote + 1,
strlen((char *)pchOtherQuote + 1) + 1);
pchCur = pchOtherQuote;
if (pfQuoted != NULL) {
*pfQuoted = TRUE;
}
}
} else {
pchCur++;
}
}
// pchCur is now pointing to a NULL or delimiter.
if (*pchCur != '\0') {
*pchCur++ = '\0';
}
return szResult[0] == '\0' ? SzGetArgument(NULL, pfQuoted)
: (char *)szResult;
}
PCHAR
_find (
PCHAR szPattern
)
/*++
Routine Description:
Given a wildcard pattern, expand it and return one at a time.
Arguments:
szPattern - Wild card argument.
--*/
{
static HANDLE _WildFindHandle;
static LPWIN32_FIND_DATA pwfd;
if (szPattern) {
if (pwfd == NULL) {
pwfd = (LPWIN32_FIND_DATA) PvAlloc(MAX_PATH + sizeof(*pwfd));
}
if (_WildFindHandle != NULL) {
FindClose(_WildFindHandle);
_WildFindHandle = NULL;
}
_WildFindHandle = FindFirstFile(szPattern, pwfd);
if (_WildFindHandle == INVALID_HANDLE_VALUE) {
_WildFindHandle = NULL;
return NULL;
}
} else {
Retry:
if (!FindNextFile(_WildFindHandle, pwfd)) {
FindClose(_WildFindHandle);
_WildFindHandle = NULL;
return NULL;
}
}
if (pwfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
// Skip directories
goto Retry;
}
return(pwfd->cFileName);
}
void
ProcessWildCards (
const char *Argument
)
/*++
Routine Description:
Expands wild cards in the argument and treats each matching file as
an argument.
Arguments:
Argument - Wild card argument.
CommandFile - If TRUE, then argument was read from a command file, and
argument needs to be copied before adding to list.
Return Value:
None.
--*/
{
char szDrive[_MAX_DRIVE];
char szDir[_MAX_DIR];
const char *pFilename;
char szFullpath[_MAX_PATH];
_splitpath(Argument, szDrive, szDir, NULL, NULL);
while ((pFilename = _find((char *) Argument)) != NULL) {
_makepath(szFullpath, szDrive, szDir, pFilename, NULL);
ProcessArgument(szFullpath, TRUE);
Argument = NULL;
}
}
char *
SzSearchEnv (
const char *szEnv,
const char *szFilename,
const char *szDefaultExt
)
/*++
Routine Description:
Searches for szFilename, first in the current directory, then (if no
explicit path specified) along the LIB path. If szDefaultExt is non-NULL
it should start with a ".". It will be the extension if the original file
doesn't have one.
Arguments:
szEnv - Name of environment variable containing path
szFilename - file name
szDefaultExt - default file extension to use, eg. ".lib"
Return Value:
Returns a malloc'ed buffer containing the pathname of the file which was
found. If the file is not found, returns szFilename.
--*/
{
char szDrive[_MAX_DRIVE];
char szDir[_MAX_DIR];
char szFname[_MAX_FNAME];
char szExt[_MAX_EXT];
char szFullFilename[_MAX_PATH];
_splitpath(szFilename, szDrive, szDir, szFname, szExt);
if ((szExt[0] == '\0') && (szDefaultExt != NULL)) {
assert(szDefaultExt[0] == '.');
assert(strlen(szDefaultExt) <= _MAX_EXT);
_makepath(szFullFilename, szDrive, szDir, szFname, szDefaultExt);
szFilename = szFullFilename;
}
if (_access(szFilename, 0) == 0) {
return SzDup(szFilename);
}
// Don't search if drive or dir specified
if ((szDrive[0] == '\0') && (szDir[0] == '\0')) {
char szPath[_MAX_PATH];
_searchenv(szFilename, szEnv, szPath);
if (szPath[0] != '\0') {
return SzDup(szPath);
}
}
return SzDup(szFilename); // didn't find it on lib path
}
void
ProcessArgument (
char *Argument,
BOOL CommandFile
)
/*++
Routine Description:
Determines if an argument is either a switch or a filename argument.
Adds argument to either switch or filename list.
Arguments:
Argument - The argument to process.
CommandFile - If TRUE, then argument was read from a command file, and
argument needs to be copied before adding to list.
Return Value:
None.
--*/
{
char c;
char *name;
PNAME_LIST ptrList;
// Fetch first character of argument.
c = Argument[0];
// If argument is a switch, then add it to
// the switch list (but don't include the switch character).
if ((c == '/') || (c == '-')) {
ptrList = &SwitchArguments;
name = Argument+1;
if (name[0] == '?' && name[1] != '\0') {
name++; // ignore '?' before non-null arg (temporary)
}
// Dup the string if it came from a file. Since dup allocates
// memory, this memory is never freed by the program.
// It is only recovered when the program terminates.
if (CommandFile) {
name = SzDup(name);
}
} else if (_tcspbrk(Argument, "?*")) {
ProcessWildCards(Argument);
return;
} else {
const char *szExt;
// If not a switch, then treat the argument as a filename.
// The linker has a default extension of ".obj";
if (Tool == Linker) {
szExt = ".obj";
} else {
szExt = NULL;
}
// Search for file in current directory and along LIB path
name = SzSearchEnv("LIB", Argument, szExt);
// Add filename to list. In the case of the linker it adds
// it to filename list. For the rest the files get classified
// as objs/libs and get added to corresponding lists.
if ((Tool == Linker) || (Tool == Dumper)) {
ptrList = &FilenameArguments;
} else {
FileReadHandle = FileOpen(name, O_RDONLY | O_BINARY, 0);
// If file is an archive, then add filename to archive list.
if (IsArchiveFile(name, FileReadHandle)) {
ptrList = &ArchiveFilenameArguments;
} else {
// Not an archive, so treat it as an object
// and add filename to object list.
ptrList = &ObjectFilenameArguments;
}
// Close the file.
FileClose(FileReadHandle, FALSE);
}
}
// Add the argument to list.
AddArgument(ptrList, name);
}
void
ParseCommandString(
char *szCommands
)
// Parses a string of commands (calling ProcessArgument on each token).
//
// Note: clobbers SzGetArgument's static data.
{
char *token;
BOOL fQuoted;
if ((token = SzGetArgument(szCommands, &fQuoted)) != NULL) {
while (token) {
if (fQuoted) {
IbAppendBlk(&blkResponseFileEcho, "\"", 1);
}
IbAppendBlk(&blkResponseFileEcho, token, strlen(token));
if (fQuoted) {
IbAppendBlk(&blkResponseFileEcho, "\"", 1);
}
IbAppendBlk(&blkResponseFileEcho, " ", 1);
ProcessArgument(token, TRUE);
token = SzGetArgument(NULL, &fQuoted);
}
IbAppendBlk(&blkResponseFileEcho, "\n", 1);
}
}
void
ParseCommandLine(
int Argc,
char *Argv[],
const char *szEnvVar
)
/*++
Routine Description:
Parse the command line (or command file) placing all switches into
SwitchArguments list, all object files into ObjectFilenameArguments list,
and all archives into ArchiveFilenameArguments list. Switches start with
either a hypen (-) or slash (/). A command file is specified with
the first character being an at (@) sign.
Arguments:
Argc - Argument count.
Argv - Array of argument strings.
Return Value:
None.
--*/
{
INT i;
char *argument;
FILE *file_read_stream;
// Process the environment variable if any.
if (szEnvVar) {
char *szEnvValue = getenv(szEnvVar);
if (szEnvValue) {
szEnvValue = SzDup(szEnvValue);
ParseCommandString(szEnvValue);
FreePv(szEnvValue);
}
}
// Process every argument.
pargFirst = NULL; // global variable to inform caller
for (i = 1; i < Argc; i++) {
// Fetch first character of argument and determine
// if argument specifies a command file.
if (*Argv[i] == '@') {
// Argument is a command file, so open it.
if (!(file_read_stream = fopen(Argv[i]+1, "rt"))) {
Fatal(NULL, CANTOPENFILE, Argv[i]+1);
}
// Allocate big buffer for read a line of text
argument = (char *) PvAlloc(4*_4K);
// Process all arguments from command file.
// fgets() fetches next argument from command file.
while (fgets(argument, (INT)(4*_4K), file_read_stream)) {
size_t len = strlen(argument);
// check if we didn't get the entire line
if (len >= ((4*_4K) - 1) && argument[len-1] != '\n') {
Fatal(Argv[i]+1, LINETOOLONG,((4*_4K) - 1));
}
if (argument[len-1] == '\n') {
// Replace \n with \0.
argument[len-1] = '\0';
}
ParseCommandString(argument);
}
// Free memory use for line buffer
FreePv(argument);
// flush stdout. has effect only on the linker.
fflush(stdout);
// Processed all arguments from the command file,
// so close the command file.
fclose(file_read_stream);
} else {
// No command file.
ProcessArgument(Argv[i], FALSE);
}
}
}
void
AddArgumentToNumList (
PNUMBER_LIST PtrNumList,
char *szOriginalName,
char *szModifiedName,
DWORD dwNumber
)
/*++
Routine Description:
Adds name and number to a simple linked list.
Arguments:
PtrNumList - List to add to.
szName - Original name of argument to add to list.
dwNumber - The number to add
Return Value:
None.
--*/
{
PNUM_ARGUMENT_LIST ptrNumList;
// Allocate next member of list.
ptrNumList = (PNUM_ARGUMENT_LIST) PvAllocZ(sizeof(NUM_ARGUMENT_LIST));
// Set the fields of the new member.
ptrNumList->szOriginalName = szOriginalName;
ptrNumList->szModifiedName = szModifiedName;
ptrNumList->dwNumber = dwNumber;
// If first member in list, remember first member.
if (!PtrNumList->First) {
PtrNumList->First = ptrNumList;
} else {
// Not first member, so append to end of list.
PtrNumList->Last->Next = ptrNumList;
}
// Increment number of members in list.
PtrNumList->Count++;
// Remember last member in list.
PtrNumList->Last = ptrNumList;
// If this is the first arg seen (in whichever list), should we report to caller
// via global variable?
}
void
AddArgumentToList (
PNAME_LIST PtrList,
char *OriginalName,
char *ModifiedName
)
/*++
Routine Description:
Adds name, to a simple linked list.
Arguments:
PtrList - List to add to.
OriginalName - Original name of argument to add to list.
ModifiedName - Modified name of argument to add to list.
Return Value:
None.
--*/
{
PARGUMENT_LIST ptrList;
// Allocate next member of list.
ptrList = (PARGUMENT_LIST) PvAllocZ(sizeof(ARGUMENT_LIST));
// Set the fields of the new member.
ptrList->OriginalName = OriginalName;
ptrList->ModifiedName = ModifiedName;
// If first member in list, remember first member.
if (!PtrList->First) {
PtrList->First = ptrList;
} else {
// Not first member, so append to end of list.
PtrList->Last->Next = ptrList;
}
// Increment number of members in list.
PtrList->Count++;
// Remember last member in list.
PtrList->Last = ptrList;
// If this is the first arg seen (in whichever list), report to caller
// via global variable.
if (pargFirst == NULL && PtrList != &SwitchArguments) {
pargFirst = ptrList;
}
}
BOOL
FArgumentInList (
const char *szName,
PNAME_LIST PtrList
)
/*++
Routine Description:
Checks for name in a simple linked list.
Arguments:
szName - Name to be checked
PtrList - List to check with.
Return Value:
TRUE if present and FALSE if not.
--*/
{
PARGUMENT_LIST pal;
DWORD i;
for (i = 0, pal = PtrList->First;
i < PtrList->Count;
i++, pal = pal->Next) {
// Case in-sensitive comparison
// UNDONE: Should this be _tcsicmp
if (!_stricmp(pal->OriginalName, szName)) {
return TRUE;
}
}
return FALSE;
}
void
AddArgument (
PNAME_LIST PtrList,
char *Name
)
/*++
Routine Description:
Arguments:
PtrList - List to add to.
Name - Original name of argument to add to list.
Return Value:
None.
--*/
{
AddArgumentToList(PtrList, Name, Name);
}
void
FreeArgumentNumberList (
PNUMBER_LIST PtrNumList
)
/*++
Routine Description:
Frees up list elements.
Arguments:
PtrList - List to free.
Return Value:
None.
--*/
{
PNUM_ARGUMENT_LIST ptrListCurr, ptrListNext;
if (!PtrNumList->Count) {
return;
}
ptrListCurr = PtrNumList->First;
while (ptrListCurr) {
ptrListNext = ptrListCurr->Next;
FreePv(ptrListCurr);
ptrListCurr = ptrListNext;
}
PtrNumList->Count = 0;
PtrNumList->First = PtrNumList->Last = NULL;
}
void
FreeArgumentList (
PNAME_LIST PtrList
)
/*++
Routine Description:
Frees up list elements.
Arguments:
PtrList - List to free.
Return Value:
None.
--*/
{
PARGUMENT_LIST ptrListCurr, ptrListNext;
if (!PtrList->Count) {
return;
}
ptrListCurr = PtrList->First;
while (ptrListCurr) {
ptrListNext = ptrListCurr->Next;
FreePv(ptrListCurr);
ptrListCurr = ptrListNext;
}
PtrList->Count = 0;
PtrList->First = PtrList->Last = NULL;
}
BOOL
IsArchiveFile (
const char *szName,
INT Handle
)
/*++
Routine Description:
Determines if a file is an object or archive file.
Arguments:
szName - name of file.
Handle - An open file handle. File pointer should be positioned
at beginning of file before calling this routine.
Return Value:
TRUE if file is an archive.
FALSE if file isn't an archive.
If TRUE, then global variable MemberSeekBase is set to next
file position after archive header.
--*/
{
BYTE archive_header[IMAGE_ARCHIVE_START_SIZE];
if (FileRead(Handle, archive_header, IMAGE_ARCHIVE_START_SIZE) !=
IMAGE_ARCHIVE_START_SIZE) {
Fatal(szName, CANTREADFILE, FileTell(Handle));
}
// If strings match, then this is an archive file, so advance
// MemberSeekBase.
if (!memcmp(archive_header, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE)) {
MemberSeekBase = IMAGE_ARCHIVE_START_SIZE;
return(TRUE);
}
return(FALSE);
}
void
VerifyMachine (
const char *Filename,
WORD MachineType,
PIMAGE_FILE_HEADER pImgFileHdr
)
/*++
Routine Description:
Verifys target machine type. Assumes ImageFileHdr.Machine has
been set.
Arguments:
Filename - Filename of file to verify.
MachineType - Machine value to verify.
Return Value:
None.
--*/
{
const char *szTargetMachine;
const char *szCurrentMachine;
if (pImgFileHdr->Machine == MachineType) {
return;
}
switch (MachineType) {
case IMAGE_FILE_MACHINE_I386:
szCurrentMachine = "IX86";
break;
case IMAGE_FILE_MACHINE_R3000:
if (pImgFileHdr->Machine == IMAGE_FILE_MACHINE_R4000) {
// R3000 code is acceptable for R4000 image
return;
}
// Fall through
case IMAGE_FILE_MACHINE_R4000 :
if (pImgFileHdr->Machine == IMAGE_FILE_MACHINE_R10000) {
// R3000/R4000 code is acceptable for a R10000 image
return;
}
szCurrentMachine = "MIPS";
break;
case IMAGE_FILE_MACHINE_R10000 :
if (pImgFileHdr->Machine == IMAGE_FILE_MACHINE_R4000) {
// A T5 object requires a T5 image
Warning(NULL, PROMOTEMIPS);
pImgFileHdr->Machine = IMAGE_FILE_MACHINE_R10000;
return;
}
szCurrentMachine = "MIPSR10";
break;
case IMAGE_FILE_MACHINE_ALPHA :
szCurrentMachine = "ALPHA";
break;
case IMAGE_FILE_MACHINE_POWERPC :
szCurrentMachine = "PPC";
break;
case IMAGE_FILE_MACHINE_M68K :
szCurrentMachine = "M68K";
break;
case IMAGE_FILE_MACHINE_MPPC_601 :
szCurrentMachine = "MPPC";
break;
default :
Fatal(Filename, UNKNOWNMACHINETYPE, MachineType);
}
switch (pImgFileHdr->Machine) {
case IMAGE_FILE_MACHINE_I386:
szTargetMachine = "IX86";
break;
case IMAGE_FILE_MACHINE_R4000 :
szTargetMachine = "MIPS";
break;
case IMAGE_FILE_MACHINE_R10000 :
szTargetMachine = "MIPSR10"; // UNDONE: Same message as MIPS?
break;
case IMAGE_FILE_MACHINE_ALPHA :
szTargetMachine = "ALPHA";
break;
case IMAGE_FILE_MACHINE_POWERPC :
szTargetMachine = "PPC";
break;
case IMAGE_FILE_MACHINE_M68K :
szTargetMachine = "M68K";
break;
case IMAGE_FILE_MACHINE_MPPC_601 :
szTargetMachine = "MPPC";
break;
}
Fatal(Filename, CONFLICTINGMACHINETYPE, szCurrentMachine, szTargetMachine);
}
void
ReadSpecialLinkerInterfaceMembers(
PLIB plib,
PIMAGE pimage
)
/*++
Routine Description:
Reads the linker interface member out of an archive file, and adds
its extern symbols to the archive list. A linker member must exist in an
archive file, or the archive file will not be searched for undefined
externals. A warning is given if no linker member exits. The optional
header from the first member is read to determine what machine and
subsystem the library is targeted for.
An achive file may contain 2 linker members. The first would be that
of standard coff. The offsets are sorted, the strings aren't. The
second linker member is a slightly different format, and is sorted
by symbol names. If the second linker member is present, it will be
used for symbol lookup since it is faster.
The members long file name table is also read if it exits.
Arguments:
plib - library node for the driver map to be updated
pimage - ptr to image
Return Value:
None.
--*/
{
PIMAGE_ARCHIVE_MEMBER_HEADER pImArcMemHdr;
IMAGE_ARCHIVE_MEMBER_HEADER ImArcMemHdrPos;
IMAGE_OPTIONAL_HEADER ImObjOptFileHdr;
IMAGE_FILE_HEADER ImObjFileHdr;
BYTE *pbST;
DWORD csymIntMem;
DWORD cMemberOffsets;
DWORD foNewMem, foOldMem;
DWORD foSymNew;
DWORD cbST;
DWORD isym;
DWORD cblib;
MemberSeekBase = IMAGE_ARCHIVE_START_SIZE;
MemberSize = 0;
// Read member and verify it is a linker member.
pImArcMemHdr = ReadArchiveMemberHeader();
if (memcmp(pImArcMemHdr->Name, IMAGE_ARCHIVE_LINKER_MEMBER, 16)) {
if (Tool != Librarian) {
Warning(plib->szName, NOLINKERMEMBER);
}
return;
}
// Read the number of public symbols defined in linker member.
FileRead(FileReadHandle, &csymIntMem, sizeof(DWORD));
// All fields in member headers are stored machine independent
// integers (4 bytes). Convert numbers to current machine long word.
csymIntMem = plib->csymIntMem = sgetl(&csymIntMem);
// remember where we were in the file
foOldMem = FileTell(FileReadHandle);
// Peek ahead and see if there is a second linker member.
// Remember member headers always start on an even byte.
foNewMem = EvenByteAlign(MemberSeekBase + MemberSize);
FileSeek(FileReadHandle, foNewMem, SEEK_SET);
FileRead(FileReadHandle, &ImArcMemHdrPos, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
cblib = FileLength(FileReadHandle);
if (!memcmp(ImArcMemHdrPos.Name, IMAGE_ARCHIVE_LINKER_MEMBER, 16)) {
// Second linker member was found so read it.
pImArcMemHdr = ReadArchiveMemberHeader();
plib->flags |= LIB_NewIntMem;
// Free offsets for first linker member and malloc new offsets
// for the second linker member. Can't store new offsets over
// the old offsets because even though the second linker
// member offsets are unique and are not repeated like they are
// for the first linker member, you can't assume there will
// never be more offsets in the second linker member that there
// are in the first. This wouldn't be true if there were four
// members, the first and last members each had a public symbol,
// but the second and third had no public symbols. Of course there
// is no way the linker would extract the second and third members,
// but it would still be a valid library.
FileRead(FileReadHandle, &cMemberOffsets, sizeof(DWORD));
plib->rgulSymMemOff = (DWORD *) PvAlloc((size_t) (cMemberOffsets + 1) * sizeof(DWORD));
if (cblib < ((cMemberOffsets * sizeof(DWORD)) + FileTell(FileReadHandle))) {
Fatal(plib->szName, BADLIBRARY, NULL);
}
FileRead(FileReadHandle, &plib->rgulSymMemOff[1], cMemberOffsets * sizeof(DWORD));
// Unlike the first linker member, the second linker member has an
// additional table. This table is used to index into the offset table.
// So make space for the offset index table and read it in.
FileRead(FileReadHandle, &csymIntMem, sizeof(DWORD));
plib->rgusOffIndex = (WORD *) PvAlloc((size_t) csymIntMem * sizeof(WORD));
if (cblib < ((csymIntMem * sizeof(WORD)) + FileTell(FileReadHandle))) {
Fatal(plib->szName, BADLIBRARY, NULL);
}
FileRead(FileReadHandle, plib->rgusOffIndex, csymIntMem * sizeof(WORD));
// Read the sorted string table over the top of the string table stored
// for the first linker member. Unlike the first linker member, strings
// aren't repeated, thus the table will never be larger than that of
// the first linker member.
cbST = MemberSize - (FileTell(FileReadHandle) - (foNewMem + sizeof(IMAGE_ARCHIVE_MEMBER_HEADER)));
plib->rgbST = (BYTE *) PvAlloc((size_t) cbST);
FileRead(FileReadHandle, plib->rgbST, cbST);
} else {
// There was no new member; so set the filepointer to back where it was
FileSeek(FileReadHandle, foOldMem, SEEK_SET);
// Create space to store linker member offsets and read it in.
plib->rgulSymMemOff = (DWORD *) PvAlloc((size_t) (csymIntMem + 1) * sizeof(DWORD));
FileRead(FileReadHandle, plib->rgulSymMemOff, csymIntMem * sizeof(DWORD));
// Calculate size of linker member string table. The string table is
// the last part of a linker member and follows the offsets (which
// were just read in), thus the total size of the strings is the
// total size of the member minus the current position of the file
// pointer.
cbST = IMAGE_ARCHIVE_START_SIZE + sizeof(IMAGE_ARCHIVE_MEMBER_HEADER) +
(MemberSize - FileTell(FileReadHandle));
// Now that we know the size of the linker member string table, lets
// make space for it and read it in.
plib->rgbST = (BYTE *) PvAlloc((size_t) cbST);
FileRead(FileReadHandle, plib->rgbST, cbST);
}
// Since we are going to use an index to reference into the
// offset table, we will make a string table, in which the
// same index can be used to find the symbol name or visa versa.
plib->rgszSym = (char **) PvAlloc((size_t) plib->csymIntMem * sizeof(char *));
for (isym = 0, pbST = plib->rgbST; isym < plib->csymIntMem; isym++) {
plib->rgszSym[isym] = (char *) pbST;
while (*pbST++) {
}
}
// Read the member long file name table if it exits.
// Peek ahead and see if there is a long filename table.
// Remember member headers always start on an even byte.
foNewMem = EvenByteAlign(MemberSeekBase + MemberSize);
FileSeek(FileReadHandle, foNewMem, SEEK_SET);
FileRead(FileReadHandle, &ImArcMemHdrPos, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
if (!memcmp(ImArcMemHdrPos.Name, IMAGE_ARCHIVE_LONGNAMES_MEMBER, 16)) {
// Long filename table was found so read it.
pImArcMemHdr = ReadArchiveMemberHeader();
// Read the strings.
pbST = (BYTE *) PvAlloc((size_t) MemberSize);
if (cblib < (MemberSize + FileTell(FileReadHandle))) {
Fatal(plib->szName, BADLIBRARY, NULL);
}
FileRead(FileReadHandle, pbST, MemberSize);
plib->rgbLongFileNames = pbST;
} else {
plib->rgbLongFileNames = NULL;
}
// Peek ahead and see if there is an optional header in the
// first member. If there is, determine the target machine & subsystem.
if (pimage->ImgFileHdr.Machine) {
foSymNew = EvenByteAlign(MemberSeekBase + MemberSize);
FileSeek(FileReadHandle, foSymNew, SEEK_SET);
FileRead(FileReadHandle, &ImArcMemHdrPos, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
ReadFileHeader(FileReadHandle, &ImObjFileHdr);
if (ImObjFileHdr.Machine) {
VerifyMachine(plib->szName, ImObjFileHdr.Machine, &pimage->ImgFileHdr);
}
if (ImObjFileHdr.SizeOfOptionalHeader == sizeof(IMAGE_OPTIONAL_HEADER)) {
ReadOptionalHeader(FileReadHandle, &ImObjOptFileHdr,
ImObjFileHdr.SizeOfOptionalHeader);
// UNDONE: Why perform this check. Is there value in having
// UNDONE: a library tied to a subsystem?
if (ImObjOptFileHdr.Subsystem &&
(ImObjOptFileHdr.Subsystem != pimage->ImgOptHdr.Subsystem)) {
// no warning if the two differing subsystems are windows gui & console
if (!((ImObjOptFileHdr.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI && pimage->ImgOptHdr.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI) ||
(ImObjOptFileHdr.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI && pimage->ImgOptHdr.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI)))
Warning(plib->szName, CONFLICTINGSUBSYSTEM);
}
}
}
}
PIMAGE_ARCHIVE_MEMBER_HEADER
ReadArchiveMemberHeader (
VOID
)
/*++
Routine Description:
Reads the member header.
Arguments:
PtrLinkerArchive - Used to expand the member name.
Return Value:
Member name.
--*/
{
LONG seek;
static IMAGE_ARCHIVE_MEMBER_HEADER ArchiveMemberHdr;
seek = EvenByteAlign(MemberSeekBase + MemberSize);
FileSeek(FileReadHandle, seek, SEEK_SET);
FileRead(FileReadHandle, &ArchiveMemberHdr, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
// Calculate the current file pointer (same as tell(FileReadHandle)).
MemberSeekBase = seek + sizeof(IMAGE_ARCHIVE_MEMBER_HEADER);
sscanf((char *) ArchiveMemberHdr.Size, "%ld", &MemberSize);
return(&ArchiveMemberHdr);
}
const char *
ExpandMemberName (
PLIB plib,
const char *szMemberName
)
/*++
Routine Description:
Expands a member name if it has a long filename.
Arguments:
plib - Used to expand the member name.
szMemberName - Member name (padded with NULLs, no null).
Return Value:
Member name.
--*/
{
static char szName[_MAX_PATH];
char *p;
strncpy(szName, szMemberName, 16);
szName[16] = '\0';
if (szName[0] == '/') {
if (szName[1] != ' ' && szName[1] != '/') {
p = strchr(szName, ' ');
if (!p) {
return(p);
}
*p = '\0';
p = (char *) (plib->rgbLongFileNames + atoi(&szName[1]));
} else {
// UNDONE: This can be an MBCS string. Use _tcschr?
p = strchr(szName, ' ');
if (!p) {
return(p);
}
*p = '\0';
p = szName;
}
} else {
// UNDONE: This can be an MBCS string. Use _tcschr?
p = strrchr(szName, '/'); // find the last occurence
if (!p) {
return(p);
}
*p = '\0';
p = szName;
}
return(p);
}
DWORD
sgetl (
DWORD *Value
)
/*++
Routine Description:
Converts a four-byte machine independent integer into a long.
Arguments:
Value - Four-byte machine independent integer
Return Value:
Value of four-byte machine independent integer.
--*/
{
BYTE *pb;
union {
LONG new_value;
BYTE x[4];
} temp;
pb = (BYTE *) Value;
temp.x[0] = pb[3];
temp.x[1] = pb[2];
temp.x[2] = pb[1];
temp.x[3] = pb[0];
return(temp.new_value);
}
DWORD
sputl (
DWORD *Value
)
/*++
Routine Description:
Converts a long into a four-byte machine independent integer.
Arguments:
Value - value to convert.
Return Value:
Four-byte machine independent integer.
--*/
{
return(sgetl(Value));
}
WORD WSwap(WORD w)
{
WORD wSwap;
((BYTE *) &wSwap)[1] = ((BYTE *) &w)[0];
((BYTE *) &wSwap)[0] = ((BYTE *) &w)[1];
return(wSwap);
}
DWORD DwSwap(DWORD dw)
{
DWORD dwSwap;
((BYTE *) &dwSwap)[3] = ((BYTE *) &dw)[0];
((BYTE *) &dwSwap)[2] = ((BYTE *) &dw)[1];
((BYTE *) &dwSwap)[1] = ((BYTE *) &dw)[2];
((BYTE *) &dwSwap)[0] = ((BYTE *) &dw)[3];
return(dwSwap);
}
void SwapBytes(void *pv, DWORD cb)
{
BYTE *pb = (BYTE *) pv;
while (cb > 0) {
BYTE rgbT[4];
DWORD n;
DWORD i;
n = (cb > 3) ? 4 : cb;
memcpy(rgbT, pb, n);
for (i = n; i > 0; i--) {
pb[i-1] = rgbT[n - i];
}
pb += n;
cb -= n;
}
}
void
ApplyCommandLineSectionAttributes(
PSEC psec
)
/*++
Routine Description:
Apply any specified command line section attributes to a section header.
Arguments:
pimsechdr - section header
Return Value:
None.
--*/
{
PARGUMENT_LIST parg;
const char *szSecName = psec->szName;
char *pb;
WORD iarg;
size_t cb;
for (iarg = 0, parg = SectionNames.First;
iarg < SectionNames.Count;
iarg++, parg = parg->Next) {
pb = strchr(parg->OriginalName, ',');
if (pb) {
cb = (size_t) (pb - parg->OriginalName);
++pb;
// Use strncmp here for matching section names, because we want
// to ignore the comma in parg->OriginalName (which precedes
// the attributes).
if (!strncmp(parg->OriginalName, szSecName, cb) &&
szSecName[cb] == '\0')
{
parg->Flags |= ARG_Processed;
if (*pb != ',') {
BOOL fYes;
DWORD dwReset;
DWORD dwSet;
fYes = TRUE;
dwReset = 0;
dwSet = 0;
// Check for end of argument or the second comma,
// which starts the Mac resource info.
while (pb && *pb && *pb != ',') {
BOOL fReversed;
DWORD f = 0; // init because not all cases set it
fReversed = FALSE;
switch (toupper(*pb)) {
case '!':
case 'N':
fYes = !fYes;
f = 0;
break;
case 'D':
f = IMAGE_SCN_MEM_DISCARDABLE;
break;
case 'E' :
if (fYes) {
// For compatibility with VC++ 1.0
dwReset |= IMAGE_SCN_MEM_READ;
dwReset |= IMAGE_SCN_MEM_WRITE;
}
f = IMAGE_SCN_MEM_EXECUTE;
break;
case 'K':
fReversed = TRUE;
f = IMAGE_SCN_MEM_NOT_CACHED;
break;
case 'P':
fReversed = TRUE;
f = IMAGE_SCN_MEM_NOT_PAGED;
break;
case 'R' :
if (fYes) {
// For compatibility with VC++ 1.0
dwReset |= IMAGE_SCN_MEM_EXECUTE;
dwReset |= IMAGE_SCN_MEM_WRITE;
}
f = IMAGE_SCN_MEM_READ;
break;
case 'S' :
f = IMAGE_SCN_MEM_SHARED;
break;
case 'W' :
if (fYes) {
// For compatibility with VC++ 1.0
dwReset |= IMAGE_SCN_MEM_EXECUTE;
dwReset |= IMAGE_SCN_MEM_READ;
}
f = IMAGE_SCN_MEM_WRITE;
break;
// VXD specific options
case 'L':
// VXDs only
psec->fPreload = (CHAR) fYes;
break;
case 'X' :
// VXDs only
f = IMAGE_SCN_MEM_RESIDENT;
break;
case 'I':
psec->fIopl = (CHAR) fYes;
break;
case 'C':
psec->fConforming = (CHAR) fYes;
break;
default:
Fatal(NULL, BADSECTIONSWITCH, parg->OriginalName);
break;
}
dwReset |= f;
if (fYes ^ fReversed) {
dwSet |= f;
} else {
dwSet &= ~f;
}
pb++;
}
psec->flags &= ~dwReset;
psec->flags |= dwSet;
psec->fDiscardable = (CHAR) ((psec->flags & IMAGE_SCN_MEM_DISCARDABLE) != 0);
}
}
}
}
}
void
PrintUndefinedExternals(
PST pst
)
/*++
Routine Description:
Writes undefined external symbols to standard out.
Arguments:
pst - pointer to external structure
Return Value:
none
--*/
{
ENM_UNDEF_EXT enmUndefExt;
if (fPowerMac && fMPPCVersionConflict && !Verbose) {
Warning (NULL, MACVERSIONCONFLICT);
}
InitEnmUndefExt(&enmUndefExt, pst);
while (FNextEnmUndefExt(&enmUndefExt)) {
PEXTERNAL pext;
const char *szName;
char *szOutput;
BOOL fRef;
ENM_MOD_EXT enmModExt;
pext = enmUndefExt.pext;
if (pext->Flags & EXTERN_IGNORE) {
continue;
}
if (pext->Flags & EXTERN_DEFINED) {
continue;
}
UndefinedSymbols++;
if (pext->szOtherName != NULL) {
// This case can occur with a forwarder when building an import lib
if (pext->Flags & EXTERN_FORWARDER) {
szName = strchr(pext->szOtherName, '.') + 1;
if (szName[0] == '#') {
// When forwarding by ordinal, the local name is searched for.
szName = SzNamePext(pext, pst);
}
} else {
szName = pext->szOtherName;
}
} else {
szName = SzNamePext(pext, pst);
}
szOutput = SzOutputSymbolName(szName, TRUE);
fRef = FALSE;
InitEnmModExt(&enmModExt, pext);
while (FNextEnmModExt(&enmModExt)) {
char szBuf[_MAX_PATH * 2];
fRef = TRUE;
// look out for the special pch symbol
if (!strncmp(szName, "___@@_PchSym_@", 14) ||
!strncmp(szName, "__@@_PchSym_@", 13) ) {
Error(SzComNamePMOD(enmModExt.pmod, szBuf), MISSINGPCTOBJ);
EndEnmModExt(&enmModExt);
break;
}
Error(SzComNamePMOD(enmModExt.pmod, szBuf), UNDEFINED, szOutput);
}
if (!fRef) {
Error(NULL, UNDEFINED, szOutput);
}
if (szOutput != szName) {
free(szOutput);
}
// Check for ^C because this loop produce a great deal of output
if (fCtrlCSignal) {
BadExitCleanup();
}
}
EndEnmUndefExt(&enmUndefExt);
AllowInserts(pst);
}
void
SearchLib (
PIMAGE pimage,
PLIB plib,
PBOOL pfNewSymbol,
PBOOL pfUnresolved
)
/*++
Routine Description:
Searches thru a library for symbols that match any undefined external
symbols.
Arguments:
pst - pointer to external structure
plib - library to search
pfNewSymbols - any new symbols added as a result of this search
pfUnresolved - any unresolved externals left
Return Value:
None.
--*/
{
ENM_UNDEF_EXT enmUndefExt;
if (plib->flags & LIB_DontSearch) {
return;
}
if (plib->szName != NULL) {
if (fVerboseLib) {
fputs(" ", stdout);
Message(LIBSRCH, plib->szName);
}
}
*pfUnresolved = 0;
// Enumerate all undefined symbols.
InitEnmUndefExt(&enmUndefExt, pimage->pst);
while (FNextEnmUndefExt(&enmUndefExt)) {
PEXTERNAL pext;
const char *szName;
char **pszEntry;
DWORD isz;
BOOL fFound;
PEXTERNAL pextPrev;
WORD iszIntMem;
DWORD iusOffIndex;
PIMAGE_ARCHIVE_MEMBER_HEADER parcMemHdr;
IMAGE_FILE_HEADER ImObjFileHdr;
PMOD pmod;
BOOL fNewSymbol;
pext = enmUndefExt.pext;
if (pext->Flags & EXTERN_IGNORE) {
continue;
}
if (pext->Flags & (EXTERN_WEAK | EXTERN_ALIAS)) {
// Do not search for definitions of weak and alias symbols
continue;
}
if ((pext->ImageSymbol.SectionNumber != 0) ||
(pext->ImageSymbol.Value != 0)) {
continue;
}
szName = SzNamePext(pext, pimage->pst);
if (plib->flags & LIB_NewIntMem) {
pszEntry = (char **) bsearch(&szName, plib->rgszSym,
(size_t) plib->csymIntMem, sizeof(char *), Compare);
fFound = (pszEntry != NULL);
} else {
fFound = FALSE;
for (isz = 0; isz < plib->csymIntMem; isz++) {
if (!strcmp(plib->rgszSym[isz], szName)) {
fFound = TRUE;
break;
}
}
}
if (!fFound) {
// An external was not found
*pfUnresolved = TRUE;
continue;
}
if (Verbose) {
ENM_MOD_EXT enmModExt;
fputs(" ", stdout);
Message(FNDSYM, szName);
InitEnmModExt(&enmModExt, pext);
while (FNextEnmModExt(&enmModExt)) {
char szBuf[_MAX_PATH * 2];
fputs(" ", stdout);
Message(SYMREF, SzComNamePMOD(enmModExt.pmod, szBuf));
}
}
// Back up one symbol in enumerator
if (pext == pimage->pst->pextFirstUndefined) {
pextPrev = NULL;
} else {
pextPrev = (PEXTERNAL) ((char *) pext->ppextPrevUndefined - offsetof(EXTERNAL, pextNextUndefined));
}
plib->flags |= LIB_Extract;
if (plib->flags & LIB_NewIntMem) {
iszIntMem = (WORD) (pszEntry - plib->rgszSym);
iusOffIndex = plib->rgusOffIndex[iszIntMem];
MemberSeekBase = plib->rgulSymMemOff[iusOffIndex];
} else {
iszIntMem = (WORD) isz;
MemberSeekBase = sgetl(&plib->rgulSymMemOff[iszIntMem]);
}
FileReadHandle = FileOpen(plib->szName, O_RDONLY | O_BINARY, 0);
MemberSize = 0;
// check for invalid lib
DWORD cblib = FileLength(FileReadHandle);
if (cblib < MemberSeekBase) {
Fatal(plib->szName, BADLIBRARY, NULL);
}
parcMemHdr = ReadArchiveMemberHeader();
if (cblib < (MemberSeekBase + MemberSize)) {
Fatal(plib->szName, BADLIBRARY, NULL);
}
if (!(szName = ExpandMemberName(plib, (char *) parcMemHdr->Name))) {
Fatal(plib->szName, BADLIBRARY, NULL);
}
ReadFileHeader(FileReadHandle, &ImObjFileHdr);
pmod = PmodNew(NULL,
szName,
MemberSeekBase,
ImObjFileHdr.PointerToSymbolTable,
ImObjFileHdr.NumberOfSymbols,
ImObjFileHdr.SizeOfOptionalHeader,
ImObjFileHdr.Characteristics,
ImObjFileHdr.NumberOfSections,
plib,
NULL);
// add it to list of new mods
if (fIncrDbFile) {
AddToPLMODList(&plmodNewModsFromLibSrch, pmod);
}
if (Verbose) {
char szBuf[_MAX_PATH * 2];
fputs(" ", stdout);
Message(LOADOBJ, SzComNamePMOD(pmod, szBuf));
}
if (pimage->Switch.Link.fTCE) {
// Allocate memory for TCE data structures
InitNodPmod(pmod);
}
fNewSymbol = FALSE;
BuildExternalSymbolTable(pimage,
&fNewSymbol,
pmod,
(WORD) (ARCHIVE + iszIntMem),
ImObjFileHdr.Machine);
FileClose(FileReadHandle, FALSE);
if (fIncrDbFile && errInc != errNone) {
return;
}
// if new externs were added re-start symbol search
if (fNewSymbol) {
*pfNewSymbol = TRUE;
}
if ((pextPrev == NULL) || (pextPrev->Flags & EXTERN_DEFINED)
// if it is previously weak extern and is not anymore
// when processing ProcessSymbolsInModule
|| fWeakToRegular) {
enmUndefExt.pextNext = pimage->pst->pextFirstUndefined;
fWeakToRegular = FALSE;
} else {
enmUndefExt.pextNext = pextPrev->pextNextUndefined;
}
}
}
#if DBG
void
DumpExternals(
PST pst,
BOOL fDefined
)
/*++
Routine Description:
Writes to standard out all external symbols
(used for debugging)
Arguments:
pst - pointer to external structure
Return Value:
None.
--*/
{
PPEXTERNAL rgpexternal;
DWORD cexternal;
DWORD i;
rgpexternal = RgpexternalByName(pst);
cexternal = Cexternal(pst);
for (i = 0; i < cexternal; i++) {
PEXTERNAL pexternal;
BOOL fExternDefined;
pexternal = rgpexternal[i];
if (pexternal->Flags & EXTERN_IGNORE) {
continue;
}
if (pexternal->Flags & EXTERN_FORWARDER) {
continue;
}
fExternDefined = (pexternal->Flags & EXTERN_DEFINED) != 0;
if (fExternDefined != fDefined) {
continue;
}
printf("%8lX %s\n", pexternal->ImageSymbol.Value,
SzNamePext(pexternal, pst));
}
}
void
DumpExternTable(
PST pst
)
/*++
Routine Description:
Writes to standard out all external symbols
(used for debugging)
Arguments:
pst - pointer to external structure
Return Value:
None.
--*/
{
printf("Defined Externals\n");
DumpExternals(pst, TRUE);
printf("Undefined Externals\n");
DumpExternals(pst, FALSE);
}
#endif // DBG
void
CountRelocsInSection(
PIMAGE pimage,
PCON pcon,
PIMAGE_SYMBOL rgsym,
PMOD pmod,
WORD wMachine
)
/*++
Routine Description:
Count the number of base relocations in a section and put the result
in the optional header. This routine uses the global ImageOptionalHdr.
Arguments:
pcon - contribution
Return Value:
None.
--*/
{
DWORD creloc;
PIMAGE_RELOCATION rgrel;
PIMAGE_RELOCATION prel;
DWORD crel;
PIMAGE_RELOCATION prelNext;
PCON rgcon;
SHORT icon;
if (!FHasRelocSrcPCON(pcon)) {
return;
}
if (wMachine == IMAGE_FILE_MACHINE_UNKNOWN) {
FatalPcon(pcon, BADCOFF_NOMACHINE);
}
prel = rgrel = ReadRgrelPCON(pcon, &creloc);
// Accumulate count of relocations for size of pconFixupDebug
crelocTotal += creloc;
rgcon = RgconPMOD(pmod);
icon = (SHORT) (pcon - rgcon + 1);
// Count how many base relocations the image will have.
crel = 0;
switch (pimage->ImgFileHdr.Machine) {
case IMAGE_FILE_MACHINE_I386 :
for (prelNext = prel; creloc; prelNext++, creloc--) {
if (rgsym[prelNext->SymbolTableIndex].StorageClass ==
IMAGE_SYM_CLASS_UNDEFINED_STATIC) {
FatalPcon(pcon,
BADCOFF_BADRELOC,
SzNameSymPb(rgsym[prelNext->SymbolTableIndex], StringTable));
}
if (pimage->Switch.Link.fTCE) {
ProcessRelocForTCE(pimage, pcon, rgsym, prelNext);
}
if (pimage->imaget == imagetVXD) {
// For VXD's we count every fixup because inter-section
// relative fixups require a runtime reloc.
crel++;
continue;
}
if (pimage->Switch.Link.fFixed) {
continue;
}
switch (prelNext->Type) {
case IMAGE_REL_I386_DIR32 :
crel++;
break;
case IMAGE_REL_I386_REL32 :
if (pimage->Switch.Link.fNewRelocs) {
if (icon != rgsym[prel->SymbolTableIndex].SectionNumber) {
crel++;
}
}
break;
}
}
break;
case IMAGE_FILE_MACHINE_R3000 :
case IMAGE_FILE_MACHINE_R4000 :
case IMAGE_FILE_MACHINE_R10000 :
for (prelNext = prel; creloc; prelNext++, creloc--) {
if (prelNext->Type == IMAGE_REL_MIPS_PAIR) {
continue;
}
if (rgsym[prelNext->SymbolTableIndex].StorageClass ==
IMAGE_SYM_CLASS_UNDEFINED_STATIC) {
FatalPcon(pcon,
BADCOFF_BADRELOC,
SzNameSymPb(rgsym[prelNext->SymbolTableIndex], StringTable));
}
if (pimage->Switch.Link.fTCE) {
ProcessRelocForTCE(pimage, pcon, rgsym, prelNext);
}
if (pimage->Switch.Link.fFixed) {
continue;
}
switch (prelNext->Type) {
case IMAGE_REL_MIPS_REFHALF:
case IMAGE_REL_MIPS_REFWORD:
case IMAGE_REL_MIPS_JMPADDR:
crel++;
break;
case IMAGE_REL_MIPS_REFHI:
// The next relocation record must be a pair
assert((prelNext+1)->Type == IMAGE_REL_MIPS_PAIR);
crel += 2;
break;
case IMAGE_REL_MIPS_REFLO:
crel++;
break;
}
}
break;
case IMAGE_FILE_MACHINE_ALPHA :
for (prelNext = prel; creloc; prelNext++, creloc--) {
if ((prelNext->Type == IMAGE_REL_ALPHA_HINT) ||
(prelNext->Type == IMAGE_REL_ALPHA_PAIR) ||
(prelNext->Type == IMAGE_REL_ALPHA_MATCH)) {
continue;
}
if (rgsym[prelNext->SymbolTableIndex].StorageClass ==
IMAGE_SYM_CLASS_UNDEFINED_STATIC) {
FatalPcon(pcon,
BADCOFF_BADRELOC,
SzNameSymPb(rgsym[prelNext->SymbolTableIndex], StringTable));
}
if (pimage->Switch.Link.fTCE) {
ProcessRelocForTCE(pimage, pcon, rgsym, prelNext);
}
if (pimage->Switch.Link.fFixed) {
continue;
}
switch (prelNext->Type) {
case IMAGE_REL_ALPHA_REFLONG :
case IMAGE_REL_ALPHA_REFQUAD :
case IMAGE_REL_ALPHA_REFLO :
crel++;
break;
case IMAGE_REL_ALPHA_BRADDR :
if (icon != rgsym[prel->SymbolTableIndex].SectionNumber) {
// If this BSR is outside our CON, account for
// possible out of range handling.
pcon->AlphaBsrCount++;
// UNDONE: This is very conservative
crel += 3;
}
break;
case IMAGE_REL_ALPHA_INLINE_REFLONG :
crel += 3;
break;
case IMAGE_REL_ALPHA_REFHI :
// The next relocation record must be a pair
assert((prelNext+1)->Type == IMAGE_REL_ALPHA_PAIR);
crel += 2;
break;
}
}
break;
case IMAGE_FILE_MACHINE_POWERPC :
for (prelNext = prel; creloc; prelNext++, creloc--) {
if ((prelNext->Type & IMAGE_REL_PPC_TYPEMASK) == IMAGE_REL_PPC_PAIR) {
continue;
}
if (rgsym[prelNext->SymbolTableIndex].StorageClass ==
IMAGE_SYM_CLASS_UNDEFINED_STATIC) {
FatalPcon(pcon,
BADCOFF_BADRELOC,
SzNameSymPb(rgsym[prelNext->SymbolTableIndex], StringTable));
}
if (prelNext->Type == IMAGE_REL_PPC_IMGLUE) {
DWORD isym;
isym = prelNext->SymbolTableIndex;
if ((mpisymbToc[isym] & fImGlue) != 0) {
const char *szName;
szName = SzNameSymPb(rgsym[isym], StringTable);
ErrorPcon(pcon, DUPLICATEGLUE, szName);
}
mpisymbToc[isym] |= fImGlue;
mpisymdwRestoreToc[isym] = prelNext->VirtualAddress;
continue;
}
if (pimage->Switch.Link.fTCE) {
ProcessRelocForTCE(pimage, pcon, rgsym, prelNext);
}
if (prelNext->Type & IMAGE_REL_PPC_TOCDEFN) {
mpisymbToc[prelNext->SymbolTableIndex] |= fDataMarkToc;
}
switch (prelNext->Type & IMAGE_REL_PPC_TYPEMASK) {
case IMAGE_REL_PPC_ADDR64 :
case IMAGE_REL_PPC_ADDR32 :
case IMAGE_REL_PPC_ADDR16 :
case IMAGE_REL_PPC_REFLO :
if (!pimage->Switch.Link.fFixed) {
crel++;
}
break;
case IMAGE_REL_PPC_TOCREL16 :
case IMAGE_REL_PPC_TOCREL14 :
if (prelNext->Type & IMAGE_REL_PPC_TOCDEFN) {
mpisymbToc[prelNext->SymbolTableIndex] |= fDataReferenceToc;
} else {
mpisymbToc[prelNext->SymbolTableIndex] |= fReferenceToc;
}
break;
case IMAGE_REL_PPC_IFGLUE :
pmod->fIfGlue = TRUE;
break;
case IMAGE_REL_PPC_REFHI :
if (!pimage->Switch.Link.fFixed) {
crel += 2;
}
break;
}
}
break;
case IMAGE_FILE_MACHINE_M68K :
{
BOOL fSACode =
((PsecPCON(pcon)->flags & IMAGE_SCN_CNT_CODE) &&
!(PsecPCON(pcon)->ResTypeMac == sbeCODE ||
fDLL(pimage) || PsecPCON(pcon)->ResTypeMac == sbeDLLcode));
for (prelNext = prel; creloc; prelNext++, creloc--) {
if (fSACode) {
CheckForIllegalA5Ref(prelNext->Type);
}
if (rgsym[prelNext->SymbolTableIndex].StorageClass ==
IMAGE_SYM_CLASS_UNDEFINED_STATIC) {
FatalPcon(pcon,
BADCOFF_BADRELOC,
SzNameSymPb(rgsym[prelNext->SymbolTableIndex], StringTable));
}
if (pimage->Switch.Link.fTCE) {
ProcessRelocForTCE(pimage, pcon, rgsym, prelNext);
}
switch (prelNext->Type) {
case IMAGE_REL_M68K_DTOU32:
case IMAGE_REL_M68K_DTOC32:
if (!fSACode) {
ProcessSTRef(prelNext->SymbolTableIndex,
PsecPCON(pcon), EXTERN_ADDTHUNK);
}
break;
case IMAGE_REL_M68K_DTOABSD32:
AddRelocInfo(&DFIXRaw, pcon, prelNext->VirtualAddress - RvaSrcPCON(pcon));
break;
case IMAGE_REL_M68K_DTOABSU32:
case IMAGE_REL_M68K_DTOABSC32:
AddRelocInfo(&DFIXRaw, pcon, prelNext->VirtualAddress - RvaSrcPCON(pcon));
if (!fSACode) {
ProcessSTRef(prelNext->SymbolTableIndex,
PsecPCON(pcon), EXTERN_ADDTHUNK);
}
break;
// CTOU16 is always an A5 offset, so mark this
// symbol as needing a thunk. If the symbol turns
// out to be a data symbol it will be ignored in
// the middle pass when the thunk table is made.
case IMAGE_REL_M68K_CTOU16:
case IMAGE_REL_M68K_DTOU16:
case IMAGE_REL_M68K_DTOC16:
case IMAGE_REL_M68K_CTOT16:
if (!fSACode) {
ProcessSTRef(prelNext->SymbolTableIndex,
PsecPCON(pcon), EXTERN_ADDTHUNK | EXTERN_REF16);
}
break;
case IMAGE_REL_M68K_PCODETOT24:
if (!fSACode) {
ProcessSTRef(prelNext->SymbolTableIndex,
PsecPCON(pcon), EXTERN_ADDTHUNK);
}
break;
case IMAGE_REL_M68K_CTOC16:
if (!fSACode) {
ProcessSTRef(prelNext->SymbolTableIndex,
PsecPCON(pcon), EXTERN_REF16);
}
break;
case IMAGE_REL_M68K_CTOABST32:
if (!fSACode) {
ProcessSTRef(prelNext->SymbolTableIndex,
PsecPCON(pcon), EXTERN_ADDTHUNK);
}
AddRelocInfo(&mpsna5ri[PsecPCON(pcon)->isecTMAC],
pcon, prelNext->VirtualAddress - RvaSrcPCON(pcon));
break;
// REVIEW - make seg-rel (not unknown)
case IMAGE_REL_M68K_CTOABSCS32:
AddRawUnknownRelocInfo(pcon, prelNext->VirtualAddress - RvaSrcPCON(pcon), prelNext->SymbolTableIndex);
break;
case IMAGE_REL_M68K_PCODETONATIVE32:
case IMAGE_REL_M68K_PCODETOC32:
if (!fSACode) {
ProcessSTRef(prelNext->SymbolTableIndex,
PsecPCON(pcon), 0);
}
break;
case IMAGE_REL_M68K_CTOABSU32:
case IMAGE_REL_M68K_CTOABSC32:
if (!fSACode) {
ProcessSTRef(prelNext->SymbolTableIndex,
PsecPCON(pcon), 0);
}
AddRawUnknownRelocInfo(pcon, prelNext->VirtualAddress - RvaSrcPCON(pcon), prelNext->SymbolTableIndex);
break;
case IMAGE_REL_M68K_CTOABSD32:
AddRelocInfo(&mpsna5ri[PsecPCON(pcon)->isecTMAC],
pcon, prelNext->VirtualAddress - RvaSrcPCON(pcon));
break;
case IMAGE_REL_M68K_CSECTABLEB16:
assert(!fSACode);
ProcessSTRef(prelNext->SymbolTableIndex,
PsecPCON(pcon), EXTERN_REF16 | EXTERN_CSECTABLEB);
break;
case IMAGE_REL_M68K_CSECTABLEW16:
assert(!fSACode);
ProcessSTRef(prelNext->SymbolTableIndex,
PsecPCON(pcon), EXTERN_REF16 | EXTERN_CSECTABLEW);
break;
case IMAGE_REL_M68K_CSECTABLEL16:
assert(!fSACode);
ProcessSTRef(prelNext->SymbolTableIndex,
PsecPCON(pcon), EXTERN_REF16 | EXTERN_CSECTABLEL);
break;
case IMAGE_REL_M68K_CSECTABLEBABS32:
assert(!fSACode);
ProcessSTRef(prelNext->SymbolTableIndex,
PsecPCON(pcon), EXTERN_CSECTABLEB);
break;
case IMAGE_REL_M68K_CSECTABLEWABS32:
assert(!fSACode);
ProcessSTRef(prelNext->SymbolTableIndex,
PsecPCON(pcon), EXTERN_CSECTABLEW);
break;
case IMAGE_REL_M68K_CSECTABLELABS32:
assert(!fSACode);
ProcessSTRef(prelNext->SymbolTableIndex,
PsecPCON(pcon), EXTERN_CSECTABLEL);
break;
case IMAGE_REL_M68K_DUPCON16:
ProcessSTRef(prelNext->SymbolTableIndex,
PsecPCON(pcon), EXTERN_DUPCON);
break;
case IMAGE_REL_M68K_DUPCONABS32:
AddRelocInfo(&mpsnsri[PsecPCON(pcon)->isecTMAC],
pcon, prelNext->VirtualAddress - RvaSrcPCON(pcon));
ProcessSTRef(prelNext->SymbolTableIndex,
PsecPCON(pcon), EXTERN_DUPCON);
break;
}
}
break;
}
case IMAGE_FILE_MACHINE_MPPC_601 :
for (prelNext = prel; creloc > 0; prelNext++, creloc--) {
DWORD isym;
PEXTERNAL pext;
const char *szName;
BOOL fFromCreateDescrRel = FALSE;
BOOL fFromDataDescRel = FALSE;
if (rgsym[prelNext->SymbolTableIndex].StorageClass ==
IMAGE_SYM_CLASS_UNDEFINED_STATIC) {
FatalPcon(pcon,
BADCOFF_BADRELOC,
SzNameSymPb(rgsym[prelNext->SymbolTableIndex], StringTable));
}
if (pimage->Switch.Link.fTCE) {
ProcessRelocForTCE(pimage, pcon, rgsym, prelNext);
}
switch (prelNext->Type & 0xFF) {
case IMAGE_REL_MPPC_DATAREL :
mppc_numRelocations++;
break;
case IMAGE_REL_MPPC_DATADESCRREL :
mppc_numRelocations++;
fFromDataDescRel = TRUE;
// DataDescrRel falls through to CreateDescrRel but no further
case IMAGE_REL_MPPC_CREATEDESCRREL :
isym = prelNext->SymbolTableIndex;
pext = pmod->rgpext[isym];
if (pext != NULL) {
if (!READ_BIT(pext, sy_DESCRRELCREATED)) {
szName = SzNamePext(pext, pimage->pst);
CreateDescriptor(szName, pcon, pimage, FALSE);
SET_BIT(pext, sy_DESCRRELCREATED);
}
if (fIncrDbFile) {
// if it is subsequent iLink, then reset this bit
// so that FixUpDescriptor will update descriptor
// if the contribution had moved.
RESET_BIT(pext, sy_DESCRRELWRITTEN);
if (fFromDataDescRel) {
MppcFixIncrDotExternFlags(pext, pimage);
}
}
} else {
// Must be a static
szName = SzNameSymPb(rgsym[isym], StringTable);
pext = CreateDescriptor(szName, pcon, pimage, TRUE);
pmod->rgpext[isym] = pext;
SET_BIT(pext, sy_ISDOTEXTERN);
bv_setAndReadBit(pmod->tocBitVector, isym);
if (fIncrDbFile) {
// if it is subsequent iLink, then reset this bit
// so that FixUpDescriptor will update descriptor
// if the contribution had moved.
RESET_BIT(pext, sy_DESCRRELWRITTEN);
}
}
if (fFromDataDescRel) {
break;
}
// Fall through into TOCREL ... see the comment
// in mppc.c when the relocs are actually applied.
assert(creloc >= 1 && ((prelNext + 1)->Type & 0xFF) == IMAGE_REL_MPPC_TOCREL);
fFromCreateDescrRel = TRUE;
// Fall through
case IMAGE_REL_MPPC_TOCREL :
isym = prelNext->SymbolTableIndex;
if (bv_readBit(pmod->tocBitVector, isym)) {
pext = pmod->rgpext[isym];
assert(pext != NULL);
if (!READ_BIT(pext, sy_TOCALLOCATED)) {
pext->ibToc = (SHORT) (mppc_numTocEntries * sizeof(DWORD) - MPPC_TOC_BIAS);
mppc_numTocEntries++;
mppc_numRelocations++;
SET_BIT(pext, sy_TOCALLOCATED);
if (pimage->Switch.Link.fMap) {
SaveTocForMapFile(pext);
}
}
} else if (!bv_setAndReadBit(pmod->writeBitVector, isym)) {
pmod->rgpext[isym] = (PEXTERNAL) mppc_numTocEntries;
mppc_numTocEntries++;
mppc_numRelocations++;
}
if (fFromCreateDescrRel) {
// Eat the next reloc so we don't double-count.
prelNext++;
creloc--;
}
break;
}
}
break;
}
// Done processing sections relocations entries.
FreeRgrel(rgrel);
if (crel != 0) {
pimage->ImgOptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].Size += crel;
pmod->cReloc += crel;
DBEXEC(DB_SCAN_RELOCS, DBPRINT("SCAN_RELOCS: pcon=%p, %5d, %s\n",
pcon, crel, SzPCON(pcon)));
}
}
void
DiscardDebugSectionPCON(
PCON pcon,
SWITCH *pswitch
)
/*++
Routine Description:
Discard debug sections.
Arguments:
pcon - debug section contribution node in image\driver map
Return Value:
None.
--*/
{
if ((pswitch->Link.DebugInfo != Full) || !(pswitch->Link.DebugType & CvDebug)) {
if ((pcon->pgrpBack == pgrpCvSymbols) ||
(pcon->pgrpBack == pgrpCvTypes) ||
(pcon->pgrpBack == pgrpCvPTypes)) {
pcon->flags |= IMAGE_SCN_LNK_REMOVE;
}
}
if (pswitch->Link.DebugInfo == None || !(pswitch->Link.DebugType & FpoDebug)) {
if (pcon->pgrpBack == pgrpFpoData) {
pcon->flags |= IMAGE_SCN_LNK_REMOVE;
}
}
}
void
ProcessWeakExtern(
PST pst,
PIMAGE_SYMBOL *ppsymNext,
PIMAGE_SYMBOL psymObj,
PEXTERNAL pext,
PMOD pmod,
PBOOL pfNewSymbol,
BOOL fNewSymbol,
WORD iArcMem
)
/*++
Routine Description:
Do necessary processing for a weak external.
Arguments:
psechdr - section header
Return Value:
None.
--*/
{
char szComFileName[_MAX_PATH * 2];
PIMAGE_AUX_SYMBOL pasym;
IMAGE_SYMBOL symDef;
DWORD foDefSym;
DWORD foCur;
PEXTERNAL pextWeakDefault;
if (psymObj->NumberOfAuxSymbols != 1) {
char *szOutput = SzOutputSymbolName(SzNamePext(pext, pst), TRUE);
SzComNamePMOD(pmod, szComFileName);
Fatal(szComFileName, BADWEAKEXTERN, szOutput);
}
pasym = (PIMAGE_AUX_SYMBOL) FetchNextSymbol(ppsymNext);
// save current file offset
foCur = FileTell(FileReadHandle);
// get weak extern symbol
foDefSym = FoSymbolTablePMOD(pmod) +
(pasym->Sym.TagIndex * sizeof(IMAGE_SYMBOL));
FileSeek(FileReadHandle, foDefSym, SEEK_SET);
ReadSymbolTableEntry(FileReadHandle, &symDef);
// Ignore weak and lazy externs if we've already seen the symbol (i.e.
// got a strong reference). However, we still look at alias records
// which can override a strong reference.
if (fNewSymbol ||
!(pext->Flags & EXTERN_DEFINED) && pasym->Sym.Misc.TotalSize == 3)
{
cextWeakOrLazy++;
pext->ImageSymbol.StorageClass = IMAGE_SYM_CLASS_WEAK_EXTERNAL;
if (IsLongName(symDef)) {
pextWeakDefault =
LookupExternName(pst, LONGNAME, &StringTable[symDef.n_offset],
pfNewSymbol);
} else {
pextWeakDefault =
LookupExternName(pst, SHORTNAME, (char *) symDef.n_name, pfNewSymbol);
}
AddWeakExtToList(pext, pextWeakDefault);
// Remember archive member index. This is just for LIB which needs
// to put weak externs in the lib's directory.
pext->ArchiveMemberIndex = iArcMem;
switch (pasym->Sym.Misc.TotalSize) {
case 1: pext->Flags |= EXTERN_WEAK; break;
case 2: pext->Flags |= EXTERN_LAZY; break;
case 3: pext->Flags |= EXTERN_ALIAS; break;
}
// in the incremental case mark it as a new func if applicable
if (fIncrDbFile && fNewSymbol && ISFCN(psymObj->Type)) {
pext->Flags |= EXTERN_NEWFUNC;
}
} else {
// If the symbol exists or has already been referenced, ignore weak
// extern
if (fIncrDbFile) {
// on an ilink the syms are not new;
if (IsLongName(symDef)) {
pextWeakDefault =
LookupExternName(pst, LONGNAME, &StringTable[symDef.n_offset],
pfNewSymbol);
} else {
pextWeakDefault =
LookupExternName(pst, SHORTNAME, (char *) symDef.n_name, pfNewSymbol);
}
AddWeakExtToList(pext, pextWeakDefault);
// in the incr case mark the sym as being weak/lazy/alias
// since it is not going to be a new symbol.
switch (pasym->Sym.Misc.TotalSize) {
case 1: pext->Flags |= EXTERN_WEAK; break;
case 2: pext->Flags |= EXTERN_LAZY; break;
case 3: pext->Flags |= EXTERN_ALIAS; break;
}
}
}
// reset file offset to where we were before
FileSeek(FileReadHandle, foCur, SEEK_SET);
}
void
ProcessSectionFlags(
DWORD *pflags,
const char *szName,
PIMAGE_OPTIONAL_HEADER pImgOptHdr
)
/*++
Routine Description:
Process a COFF sections flags.
Arguments:
*pflags - a COFF section flags
szName - name of section
Return Value:
None.
--*/
{
DWORD flags;
flags = *pflags & ~(IMAGE_SCN_TYPE_NO_PAD | // ignore padding
IMAGE_SCN_LNK_COMDAT | // ignore comdat bit
IMAGE_SCN_LNK_NRELOC_OVFL | // ignore overflow bit
0x00f00000); // ignore alignment bits
// Force the DISCARDABLE flag if the section name starts with .debug.
if (strcmp(szName, ".debug") == 0) {
flags |= IMAGE_SCN_MEM_DISCARDABLE;
}
if (fImageMappedAsFile && (flags & IMAGE_SCN_CNT_UNINITIALIZED_DATA)) {
// Place the bss on the disk for packed images.
flags &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;
flags |= IMAGE_SCN_CNT_INITIALIZED_DATA;
}
// Mark resource data on native images (device drivers) as discardable.
if ((pImgOptHdr->Subsystem == IMAGE_SUBSYSTEM_NATIVE) &&
(!strcmp(szName, ReservedSection.Resource.Name))) {
flags |= IMAGE_SCN_MEM_DISCARDABLE;
}
// If unknown contents, mark INITIALIZED DATA
if (!(flags & (IMAGE_SCN_LNK_OTHER |
IMAGE_SCN_CNT_CODE |
IMAGE_SCN_CNT_INITIALIZED_DATA |
IMAGE_SCN_CNT_UNINITIALIZED_DATA))) {
flags |= IMAGE_SCN_CNT_INITIALIZED_DATA;
}
// set anything not marked with a memory protection attribute
// - code will be marked EXECUTE READ,
// - everything else will be marked READ WRITE
if (!(flags & (IMAGE_SCN_MEM_WRITE |
IMAGE_SCN_MEM_READ |
IMAGE_SCN_MEM_EXECUTE))) {
if (flags & IMAGE_SCN_CNT_CODE) {
flags |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
} else {
flags |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
}
}
*pflags = flags;
}
void
ProcessSectionInModule (
PIMAGE pimage,
PMOD pmod,
SHORT isec,
IMAGE_SECTION_HEADER *pImgSecHdr,
PIMAGE_SYMBOL rgsymAll,
WORD wMachine,
PNAME_LIST pnlDirectives
)
/*++
Routine Description:
Process all the sections in a module.
Arguments:
pst - pointer to external structure
pmod - module node in driver/image map that pcon
fIncReloc - !0 if we are to include relocatins, 0 otherwise
isec - section number of contribution to process
pImgSecHdr - ptr to section header of contribution
rgsymAll - COFF symbol table for module
wMachine - machine type of object file.
pnlDirectives - list to keep directives in.
Return Value:
None.
--*/
{
const char *szName;
DWORD dwCharacteristics;
PCON pcon;
const char *szComdatName = NULL;
DWORD cbAlign;
szName = SzObjSectionName((char *) pImgSecHdr->Name, StringTable);
// Force all sections on MIPS to at least ALIGN4 (old compilers didn't
// specify an alignment making merging/incremental impossible)
if ((pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_R4000) ||
(pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_R10000)) {
if ((!(pImgSecHdr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)) &&
(strncmp(szName, ".idata", 6) != 0) &&
(FetchContent(pImgSecHdr->Characteristics) != IMAGE_SCN_LNK_OTHER)
)
{
cbAlign = RvaAlign(1, pImgSecHdr->Characteristics);
if (cbAlign < 4) {
char szModule[_MAX_PATH*2];
SzComNamePMOD(pmod, szModule);
DBEXEC(DB_INCRCALCPTRS,
printf("Fixing legacy module with no alignment: %s %s\n", szModule, szName));
// UNDONE: Len - Why whack the NO_PAD attribute when building
// incremental?
// If you don't whack the NO_PAD then you'll get ilink padding
// that is not 0 modulo alignment and that could leave one
// xdata section unaligned following a padded section.
// see RvaAlign.
if (fINCR && !fIncrDbFile) {
pImgSecHdr->Characteristics &= 0xFF8FFFF7;
} else {
pImgSecHdr->Characteristics &= 0xFF8FFFFF;
}
pImgSecHdr->Characteristics |= IMAGE_SCN_ALIGN_4BYTES;
}
}
}
dwCharacteristics = pImgSecHdr->Characteristics;
if (fPowerMac) {
if (strcmp(szName, ".ppcshl") == 0) {
MppcSetExpFilename(SzOrigFilePMOD(pmod));
}
}
// Allocate a contribution:
pcon = PconNew(szName,
pImgSecHdr->SizeOfRawData,
dwCharacteristics,
dwCharacteristics,
pmod,
&pimage->secs,
pimage);
DiscardDebugSectionPCON(pcon, &pimage->Switch);
if (fPdb && (pcon->pgrpBack == pgrpCvPTypes)) {
AddToPLMODList(&PCTMods, pmod);
}
if (pcon->flags & IMAGE_SCN_LNK_COMDAT) {
if (!FIncludeComdat(pimage, pcon, rgsymAll, isec, &szComdatName)) {
// Don't include this comdat.
pcon->flags |= IMAGE_SCN_LNK_REMOVE;
return;
}
}
if ((pcon->flags & IMAGE_SCN_LNK_INFO) && !pimage->fIgnoreDirectives) {
if (!strcmp(szName, ReservedSection.Directive.Name)) {
char *pchDirectives;
DWORD ich;
pchDirectives = (char *) PvAlloc((size_t) pcon->cbRawData + 1);
FileSeek(FileReadHandle, FoRawDataSrcPCON(pcon), SEEK_SET);
FileRead(FileReadHandle, pchDirectives, pcon->cbRawData);
// Convert embedded '\0's to spaces
for (ich = 0; ich < pcon->cbRawData; ich++) {
if (pchDirectives[ich] == '\0') {
pchDirectives[ich] = ' ';
}
}
// Now null terminate the string
pchDirectives[pcon->cbRawData] = '\0';
if (fIncrDbFile) {
BuildArgList(pimage, pcon, pnlDirectives, pchDirectives);
} else {
ApplyDirectives(pimage, pcon, pchDirectives);
}
FreePv(pchDirectives);
}
}
if (Tool == Librarian) {
return;
}
if (pcon->flags & IMAGE_SCN_LNK_REMOVE) {
return;
}
// Make sure the group is aligned in such a way that this CON gets
// aligned correctly.
cbAlign = RvaAlign(1, dwCharacteristics);
if (pcon->pgrpBack->cbAlign < (BYTE) cbAlign) {
pcon->pgrpBack->cbAlign = (BYTE) cbAlign;
if (!fM68K && !fPowerMac) {
if (pimage->ImgOptHdr.SectionAlignment < cbAlign) {
FatalPcon(pcon, CONALIGNTOOLARGE, isec, cbAlign);
}
}
if (fM68K && (pimage->ImgOptHdr.SectionAlignment < cbAlign)) {
pimage->ImgOptHdr.SectionAlignment = cbAlign;
}
}
if (pimage->Switch.Link.fTCE) {
InitNodPcon(pcon, szComdatName, FALSE);
if ((pcon->flags & IMAGE_SCN_LNK_COMDAT) == 0) {
// Enforce the policy that non-comdat sections (and anything they
// refer to) are not eliminated. We could eventually eliminate
// some of these but first we have to worry about .CRT initialization,
// .idata, etc.
PentNew_TCE(NULL, NULL, pcon, &pentHeadImage);
} else if (pcon->pconAssoc != NULL) {
PedgNew_TCE(0, pcon->pconAssoc, pcon);
}
}
// No padding yet at end of CON. If the next CON wants padding then we
// may add some later.
// Incr pad currently disabled for
// idata cons since it will mess up those NULL THUNKs.
// do pdata padding elsewhere LFL
// For PowerMac, .pdata exists as a section now and not yet been merged into .data as a grp
if (fINCR && !fIncrDbFile &&
(PsecPCON(pcon) != psecDebug) &&
(PsecPCON(pcon) != psecException) &&
!FIsLibPMOD(pmod) &&
strcmp(PsecPCON(pcon)->szName, ".idata")) {
DWORD cbPad;
if (pcon->flags & IMAGE_SCN_CNT_CODE) {
cbPad = (pcon->cbRawData * CODE_PAD_PERCENT) / 100;
// A one byte pad causes more problems making small
// import thunks non-continuous than it solves.
if (cbPad == 1) {
cbPad = 0;
}
} else if (PsecPCON(pcon) == psecXdata) {
cbPad = (pcon->cbRawData * XDATA_PAD_PERCENT) / 100;
} else {
cbPad = (pcon->cbRawData * DATA_PAD_PERCENT) / 100;
}
pcon->cbPad = cbPad;
pcon->cbRawData += pcon->cbPad; // cbRawData includes pad size
}
#ifdef MFILE_PAD
// Put padding for MFile if it is non incremental link
if (fPowerMac && fMfilePad && (PsecPCON(pcon) != psecDebug) &&
(PsecPCON(pcon) != psecException) && !FIsLibPCON(pcon)) {
// it can't be incremental link
assert (!fINCR);
pcon->cbPad = CalculateMFilePad(pcon->cbRawData);
pcon->cbRawData += pcon->cbPad; // cbRawData includes pad size
}
#endif
// Count number of relocations that will remain part of image
// and update the optional header. Don't count debug relocations
// since we don't generate base relocs for them.
if (PsecPCON(pcon) != psecDebug) {
CountRelocsInSection(pimage, pcon, rgsymAll, pmod, wMachine);
}
}
void
MultiplyDefinedSym(
SWITCH *pswitch,
const char *szFilename2,
const char *szSym,
const char *szFilename1
)
{
char *szOutput;
szOutput = SzOutputSymbolName(szSym, TRUE);
if ((Tool == Linker) && !(pswitch->Link.Force & ftMultiple)) {
// Error if linker and /FORCE:MULTIPLE not specified
Error(szFilename2, MULTIPLYDEFINED, szOutput, szFilename1);
} else {
// Warning for the rest
Warning(szFilename2, WARNMULTIPLYDEFINED, szOutput, szFilename1);
}
if (szSym != szOutput) {
FreePv(szOutput);
}
fMultipleDefinitions = TRUE;
}
void
ProcessAbsSymForIlink (
PIMAGE pimage,
PEXTERNAL pext,
PIMAGE_SYMBOL psymObj,
const char *szSym,
BOOL fNewSymbol,
PMOD pmod
)
{
// check in the incr case
if (fIncrDbFile &&
(ChckAbsSym(szSym, psymObj, pext, fNewSymbol) != errNone)) {
return;
}
// full-link case
RecordSymDef(&pimage->psdAbsolute, pext, pmod);
}
void
ProcessInitSymReplacingCommonSym (
PEXTERNAL pext,
const char *szSym,
PMOD pmod
)
{
// on an ilink if you get a init sym replacing a bss, give up
if (fIncrDbFile) {
// This symbol was defined as COMMON at the end
// of the previous link. Don't allow it to be
// redefined now.
#ifdef INSTRUMENT
LogNoteEvent(Log, SZILINK, SZPASS1, letypeEvent, "COMMON replaced with non-COMMON: %s", szSym);
#endif // INSTRUMENT
errInc = errCommonSym;
return;
}
// init sym is defined in a cmdline obj => previously seen bss was in cmdline obj
if (!FIsLibPMOD(pmod)) {
RemovePrevDefn(pext);
pext->Flags |= EXTERN_RELINK;
}
// init sym defined in lib obj & bss being replaced in cmdline/lib obj
else {
RemovePrevDefn(pext);
pext->Flags |= EXTERN_NO_REFS;
RemoveAllRefsToPext(pext);
}
}
void
ProcessCommonSymForIlink (
PIMAGE pimage,
PEXTERNAL pext,
PIMAGE_SYMBOL psymObj,
const char *szSym,
BOOL fNewSymbol,
PMOD pmod
)
{
// Keep track of reference to this bss symbol
AddReferenceExt(pext, pmod);
// extern undefined
if (!(pext->Flags & EXTERN_DEFINED)) {
// On ilink bss replacing an init isn't allowed
if (fIncrDbFile && !fNewSymbol && !(pext->Flags & EXTERN_COMMON)) {
#ifdef INSTRUMENT
LogNoteEvent(Log, SZILINK, SZPASS1, letypeEvent, "COMMON replacing init symbol: %s", szSym);
#endif // INSTRUMENT
errInc = errCommonSym;
return;
}
// first definition of COMMON
if (FIsLibPMOD(pmod)) {
RecordSymDef(&pimage->psdCommon, pext, pmod);
}
}
// extern already defined as NOT being COMMON
else if ((pext->Flags & EXTERN_DEFINED) && !(pext->Flags & EXTERN_COMMON)) {
// Alternate defn for ext available. Need to relink if defn goes away.
pext->Flags |= EXTERN_RELINK;
// if on an ilink a bss gets added to a cmdline obj & NOT COMMON was
// defined in a lib object take out refs and let lib correctness figure
// it out.
if (!FIsLibPMOD(pmod) && FIsLibPMOD(PmodPCON(pext->pcon))) {
pext->Flags |= EXTERN_NO_REFS;
RemoveAllRefsToPext(pext);
}
}
// extern already defined as COMMON
else if ((pext->Flags & EXTERN_DEFINED) && (pext->Flags & EXTERN_COMMON)) {
// Second defn found. Relink if one defn goes away
pext->Flags |= EXTERN_RELINK;
// this COMMON is bigger than previously seen COMMON
if (psymObj->Value > (pext->pcon ?
pext->pcon->cbRawData - pext->pcon->cbPad : pext->ImageSymbol.Value)) {
if (fIncrDbFile) {
// This symbol was defined as COMMON
// at the end of the previous link.
// It isn't allowed to grow.
#ifdef INSTRUMENT
LogNoteEvent(Log, SZILINK, SZPASS1, letypeEvent, "COMMON symbol grew: %s", szSym);
#endif // INSTRUMENT
errInc = errCommonSym;
return;
} else {
// Full Link: Take out prev defn. Alternate defn available
// If 2nd defn in lib obj remove all references since this obj wasn't pulled in
// for this defn.
RemovePrevDefn(pext);
if (FIsLibPMOD(pmod)) {
pext->Flags |= EXTERN_NO_REFS;
RemoveAllRefsToPext(pext);
RecordSymDef(&pimage->psdCommon, pext, pmod);
}
}
// this COMMON is same size as previously seen COMMON
} else if (psymObj->Value == (pext->pcon ?
pext->pcon->cbRawData - pext->pcon->cbPad : pext->ImageSymbol.Value)) {
// on ilink we need to relink if previous defn was from lib
if (fIncrDbFile && FindPmodDefiningSym(pimage->psdCommon, pext)) {
errInc = errCommonSym;
return;
}
}
}
// track references made by mod (must call this last)
AddExtToModRefList(pmod, pext);
}
void
UpdateExternalSymbol(
PEXTERNAL pext,
PCON pcon,
DWORD value,
SHORT isec,
WORD symtype,
WORD iArcMem,
PMOD pmod,
PST pst
)
/*++
Routine Description:
Update the external symbol table.
Arguments:
pst - pointer to external structure
Return Value:
None.
--*/
{
SetDefinedExt(pext, TRUE, pst);
if (pext->Flags & (EXTERN_WEAK | EXTERN_LAZY | EXTERN_ALIAS)) {
// Found a definition of it, so we can forget that it was weak etc.
pext->Flags &= ~(EXTERN_WEAK | EXTERN_LAZY | EXTERN_ALIAS);
pext->ImageSymbol.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
cextWeakOrLazy--;
}
pext->pcon = pcon;
pext->ImageSymbol.Value = value;
pext->ImageSymbol.SectionNumber = isec;
pext->ImageSymbol.Type = symtype;
pext->ArchiveMemberIndex = iArcMem;
// chain up externs defined by MOD; cannot use PmodPcon(pext->pcon) because of bss
if (fINCR) {
if (pmod->pextFirstDefined) {
pext->pextNextDefined = pmod->pextFirstDefined;
}
pmod->pextFirstDefined = pext;
}
}
void
SetIdataNullThunkPMOD(
PMOD pmod
)
/*++
Routine Description:
For each contribution in the module that an .idata NULL_THUNK symbol
was present, check if the contribution is in .idata. If so, then set
the rva to !0. In ImportSemantics(), all contributions with !0 rva's
will be put at then end of their respective DLL contributions. It is
save to use the rva field in the pcon because this happens before we
calculate pointers.
Arguments:
pmod - module node in image/driver map
Return Value:
None.
--*/
{
ENM_SRC enm_src;
InitEnmSrc(&enm_src, pmod);
while (FNextEnmSrc(&enm_src)) {
PCON pcon;
pcon = enm_src.pcon;
if ((strcmp(pcon->pgrpBack->szName, ".idata$4") == 0) ||
(strcmp(pcon->pgrpBack->szName, ".idata$5") == 0)) {
pcon->rva = !0;
}
}
EndEnmSrc(&enm_src);
}
void
ProcessSymbolsInModule(
PIMAGE pimage,
PMOD pmod,
PBOOL pfNewSymbol,
PIMAGE_SYMBOL psymAll,
WORD iArcMem,
BOOL isPowerMac
)
/*++
Routine Description:
Process all the symbols in a module.
Arguments:
pst - pointer to external structure
pmod - module node in driver map to process
*pfNewSymbol - set to !0 if new symbol is added to external symbol table
psymAll - pointer to all the symbols for a module
iArcMem - if !0, specifies archive member being processed
Return Value:
None.
--*/
{
char szComFileName[_MAX_PATH * 2];
PIMAGE_SYMBOL psymNext = psymAll;
PIMAGE_SYMBOL psymObj;
PIMAGE_AUX_SYMBOL pasym;
PEXTERNAL pext;
BOOL fUpdate;
BOOL fNewSymbol;
BOOL fNullThunk;
DWORD csymT = 0;
DWORD value;
const char *szSym;
SHORT isec;
BYTE isym;
PCON pcon;
SzComNamePMOD(pmod, szComFileName);
DBEXEC(DB_SYMPROCESS, DBPRINT("\nMODULE: %s\n", szComFileName));
fNullThunk = FALSE;
while (csymT != pmod->csymbols) {
assert(psymNext == NULL || csymT == (DWORD)(psymNext - psymAll));
psymObj = FetchNextSymbol(&psymNext);
isym = 0;
if (psymObj->StorageClass == IMAGE_SYM_CLASS_EXTERNAL ||
psymObj->StorageClass == IMAGE_SYM_CLASS_WEAK_EXTERNAL ||
psymObj->StorageClass == IMAGE_SYM_CLASS_FAR_EXTERNAL) {
// Initially mark the symbol for no updating.
// Updating will occur later after we decide if
// the symbol defines/redefines an existing symbol.
fUpdate = FALSE;
fNewSymbol = FALSE;
// Add to external symbol table
if (IsLongName(*psymObj)) {
pext = LookupExternName(pimage->pst, LONGNAME,
&StringTable[psymObj->n_offset], &fNewSymbol);
// Flag that this module references a null thunk
fNullThunk |= (StringTable[psymObj->n_offset] == 0x7f);
} else {
pext = LookupExternName(pimage->pst, SHORTNAME,
(char *) psymObj->n_name, &fNewSymbol);
// Flag that this module references a null thunk
fNullThunk |= (psymObj->n_name[0] == 0x7f);
}
if (fPowerMac) {
// This function ProcessSymbolsInModule is called twice in
// PowerMac. Since the Symbol Table Lookup doesn't mark the
// symbol new the second time around, we make use of pext->ppcflags
// to carry over the information
if (isPowerMac) {
if (fNewSymbol) {
SET_BIT(pext, sy_NEWSYMBOL);
}
} else if (READ_BIT(pext, sy_NEWSYMBOL)) {
fNewSymbol = TRUE;
RESET_BIT(pext, sy_NEWSYMBOL);
}
}
// if MAC DLL, we ignore the symbol __Init32BitLoadseg,
// because it always referenced, but never called
if (fM68K && fDLL(pimage)) {
if (IsLongName(*psymObj)) {
if (strcmp(&StringTable[psymObj->n_offset], LargeModelName) == 0) {
pext->Flags |= EXTERN_IGNORE;
pext->ImageSymbol.Value = 0;
csymT++;
continue;
}
}
}
rgpExternObj[csymT] = pext;
if (fPowerMac && Tool == Linker) {
pmod->rgpext[csymT] = pext;
bv_setAndReadBit(pmod->tocBitVector, csymT);
}
// In the case of ilink it is possible to see an ignore'ed
// external variable again.
if (fIncrDbFile && !fNewSymbol && (pext->Flags & EXTERN_IGNORE)) {
fNewSymbol = TRUE;
pext->Offset = 0;
pext->ppextPrevUndefined = NULL;
pext->pextNextUndefined = NULL;
pext->Flags = EXTERN_DEFINED;
SetDefinedExt(pext, FALSE, pimage->pst);
if (fPowerMac) {
SET_BIT(pext, sy_NEWSYMBOL);
RESET_BIT(pext, sy_TOCENTRYFIXEDUP);
RESET_BIT(pext, sy_DESCRRELWRITTEN);
}
}
if (!fNewSymbol &&
(pext->Flags & (EXTERN_WEAK | EXTERN_LAZY)) &&
psymObj->StorageClass != IMAGE_SYM_CLASS_WEAK_EXTERNAL)
{
// Found a non-weak version of a weak extern. The weak extern
// should go away. This doesn't happen for aliases, which
// remain unless they are explicitly defined.
pext->Flags &= ~(EXTERN_WEAK | EXTERN_LAZY);
cextWeakOrLazy--;
fWeakToRegular = TRUE; // See note in SearchLib
}
if (fNewSymbol) {
// Propagate the symbol type ... currently this is just for
// remembering whether it's a function or not (for multiply
// defined errors).
pext->ImageSymbol.Type = psymObj->Type;
if (pfNewSymbol != NULL) {
*pfNewSymbol = TRUE;
}
}
if (fM68K && (Tool != Librarian)) {
// Add appropriate thunk info to this extern
UpdateExternThunkInfo(pext, csymT);
}
szSym = SzNamePext(pext, pimage->pst);
if (isPowerMac) {
if (!(pext->Flags & EXTERN_DEFINED) &&
psymObj->Value == 0 &&
psymObj->StorageClass == IMAGE_SYM_CLASS_WEAK_EXTERNAL)
{
csymT++;
ProcessWeakExtern(pimage->pst, &psymNext, psymObj,
pext, pmod, pfNewSymbol, fNewSymbol,
iArcMem);
isym = 1;
}
} else {
// Determine if the symbol is being defined/redefined.
isec = psymObj->SectionNumber;
if (isec > 0) {
// The symbol is being defined because it has a positive
// section number.
fUpdate = TRUE;
// get contribution symbol is defined in
pcon = PconPMOD(pmod, isec);
if ((Tool == Linker || (Tool == Librarian && pimage->Switch.Lib.DefFile))
&& pcon->flags & IMAGE_SCN_LNK_INFO) {
// Symbol is being defined in a directive section (currently that means it's
// PowerMac and we're doing an -import directive on it). Ignore it here, i.e.
// leave it as an unresolved external. The processing will all be done when
// the directive is handled.
//
// In the case of the librarian we ignore it, if a DEF file is present. We will be
// parsing the directives later. However, we don't ignore it here, but
// we continue processing it when the librarian does not have a DEF file.
// This would be the case when we want to combine two import libraries into a new one.
//
// this goto is sort of like "continue" except that the loop increment is non-trivial.
goto NextIterationOfSymbolLoop;
}
// If the symbol in the external symbol table has already
// been defined, then a redefinition is allowed if the
// new symbols is replacing a COMMON symbol. In this case,
// the common definition is replaced. Otherwise, notify
// the user we have a multiply defined symbol and don't
// update the symbol.
if (pext->Flags & EXTERN_DEFINED) {
if (pext->Flags & EXTERN_COMMON) {
if (fINCR) {
ProcessInitSymReplacingCommonSym(pext,szSym,pmod);
}
pext->Flags &= ~EXTERN_COMMON;
} else {
// UNDONE: The following is temporarily broken
// UNDONE: so that Mac PCODE can get by using
// UNDONE: two external symbols from a COMDAT
// UNDONE: section
#ifdef UNDONE
if (((pext->Flags & EXTERN_COMDAT) != 0) &&
#else
if ((pext->pcon != NULL) && ((pext->pcon->flags & IMAGE_SCN_LNK_COMDAT) != 0) &&
#endif
((pcon->flags & IMAGE_SCN_LNK_COMDAT) != 0)) {
// This symbol is a COMDAT symbol being
// redefined in a COMDAT section. Multiple
// definition errors are detected and reported
// in FIncludeComdat.
if (fINCR) {
// Keep track of COMDAT references
AddReferenceExt(pext, pmod);
AddExtToModRefList(pmod, pext);
}
} else if (fPowerMac && (szSym[0] == '.')) {
// Ignore internally created symbols for PowerMac.
// UNDONE: Why?
} else {
char szModule[_MAX_PATH * 2];
if (pext->pcon == NULL) {
// This is true for absolute symbols
strcpy(szModule, "a previous module");
} else {
SzComNamePMOD(PmodPCON(pext->pcon), szModule);
}
// on an ilink do a full link if new defn is from cmdline obj & old is from lib
if (fIncrDbFile && !FIsLibPMOD(pmod) &&
((pext->pcon && FIsLibPMOD(PmodPCON(pext->pcon)))
|| FindPmodDefiningSym(pimage->psdAbsolute, pext))) {
if (fTest) {
PostNote(NULL, MULTDEFNFOUND, szSym);
}
errInc = errMultDefFound;
return;
}
MultiplyDefinedSym(&pimage->Switch, szComFileName, szSym, szModule);
}
// Reset contribution symbol is defined in
pcon = pext->pcon;
fUpdate = FALSE;
}
}
// Assign the value, which will be the local virtual
// address of the section plus the value of the symbol.
value = psymObj->Value;
if (fIncrDbFile) {
// On an ilink change from bss to init results in full-link
if (pext->Flags & EXTERN_COMMON) {
errInc = errCommonSym;
return;
}
// On an ilink, don't update if the pcon is being thrown out. This may happen
// if a definition in an obj occurs before the defn that was picked before (our
// policy for COMDATs is to select it from the same obj as before. Needs to be
// reviewed.)
if (pcon->flags & IMAGE_SCN_LNK_REMOVE) {
fUpdate = FALSE;
}
// On an incremental build need to check for new funcs, data etc.
else if (!FIsLibPCON(pcon) &&
(ChckExtSym(szSym, psymObj, pext, fNewSymbol) != errNone)) {
return;
}
}
} else {
// The symbol doesn't have a section defining it, but
// it might be COMMON or an ABSOLUTE. Common data is
// defined by having a zero section number, but a
// non-zero value.
pcon = NULL; // we don't have a CON yet
if (isec == 0) {
if (psymObj->Value) {
// The symbol defines COMMON.
if (fINCR) {
ProcessCommonSymForIlink (pimage, pext, psymObj, szSym, fNewSymbol, pmod);
if (errInc != errNone) {
return;
}
}
if (!(pext->Flags & EXTERN_DEFINED) ||
pext->Flags & EXTERN_COMMON)
{
if (!(pext->Flags & EXTERN_COMMON)) {
// First occurrence of common data ...
// remember which module referenced it (we
// will emit it with that module when
// generating CV publics).
AddToLext(&pmod->plextCommon, pext);
pext->Flags |= EXTERN_COMMON;
}
if (fM68K) {
if (!(pext->Flags & EXTERN_DEFINED)) {
// Remember if definition is FAR_EXTERNAL or just EXTERNAL
pext->ImageSymbol.StorageClass = psymObj->StorageClass;
} else if (pext->ImageSymbol.StorageClass != psymObj->StorageClass) {
// Near/Far mismatch
Warning(szComFileName, MACCOMMON, szSym);
// Force symbol near
pext->ImageSymbol.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
}
}
if (psymObj->Value > (pext->pcon ?
pext->pcon->cbRawData - pext->pcon->cbPad : pext->ImageSymbol.Value)) {
value = psymObj->Value;
fUpdate = TRUE;
}
}
} else {
// This is a simple EXTERN reference
// add extern to list which if they have mult defns could alter link behavior
if (fIncrDbFile && (pext->Flags & EXTERN_DEFINED)) {
AddExtToMultDefList(pext, pimage);
}
AddReferenceExt(pext, pmod); // adds MOD to reference list of EXTERN
if (fINCR) {
AddExtToModRefList(pmod, pext); // adds EXTERN to reference list of MOD
}
if (!(pext->Flags & EXTERN_DEFINED)) {
if (fIncrDbFile && fNewSymbol) {
// mark the extern as new function
if (ISFCN(psymObj->Type)) {
pext->Flags |= EXTERN_NEWFUNC;
// reference to new data item
} else {
pext->Flags |= EXTERN_NEWDATA;
}
}
if (psymObj->StorageClass == IMAGE_SYM_CLASS_WEAK_EXTERNAL) {
csymT++;
ProcessWeakExtern(pimage->pst, &psymNext, psymObj,
pext, pmod, pfNewSymbol, fNewSymbol,
iArcMem);
if (fIncrDbFile && (errInc != errNone)) {
return;
}
isym = 1;
}
}
}
} else if (isec == IMAGE_SYM_ABSOLUTE) {
// ABSOLUTE. Value is absolute, thus no virtual
// address needs to be assigned, just the value itself.
value = psymObj->Value;
fUpdate = TRUE;
// If the symbol in the external symbol table is already
// defined and the absolute values don't match,
// notify the user we have a multiply defined symbol
// but don't update the symbol, otherwise update
// the symbol.
if ((pext->Flags & EXTERN_DEFINED) &&
(value != pext->ImageSymbol.Value)) {
char szModule[_MAX_PATH * 2];
if (pext->pcon) {
SzComNamePMOD(PmodPCON(pext->pcon), szModule);
} else {
strcpy(szModule, "a previous module");
}
MultiplyDefinedSym(&pimage->Switch, szComFileName, szSym, szModule);
fUpdate = FALSE;
}
if (fINCR) {
ProcessAbsSymForIlink(pimage, pext, psymObj, szSym, fNewSymbol, pmod);
if (errInc != errNone) {
return;
}
}
}
}
if (fUpdate) {
UpdateExternalSymbol(pext, pcon, value, isec, psymObj->Type,
iArcMem, pmod, pimage->pst);
}
}
if ((pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) &&
(Tool == Linker)) {
// Record the external symbol.
if (!bv_setAndReadBit(pmod->tocBitVector, csymT)) {
pmod->rgpext[csymT] = pext;
}
if (mpisymbToc[csymT] & (fReferenceToc |
fDataReferenceToc |
fDataMarkToc)) {
ProcessTocSymbol(pimage, pmod, pext, csymT, mpisymbToc[csymT]);
}
if ((mpisymbToc[csymT] & fImGlue) != 0) {
if (READ_BIT(pext, fImGlue)) {
Error(szComFileName, DUPLICATEGLUE, szSym);
}
pext->dwRestoreToc = mpisymdwRestoreToc[csymT];
}
SET_BIT(pext, mpisymbToc[csymT]);
}
} else if (Tool == Linker) {
if (fM68K && (psymObj->SectionNumber > 0)) {
UpdateLocalThunkInfo(pimage, PconPMOD(pmod, psymObj->SectionNumber), psymObj, csymT);
}
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
if (mpisymbToc[csymT] & (fReferenceToc |
fDataReferenceToc |
fDataMarkToc)) {
ProcessTocSymbol(pimage, pmod, NULL, csymT, mpisymbToc[csymT]);
}
}
}
NextIterationOfSymbolLoop:
csymT++;
if (!isPowerMac) {
// Accumulate estimated count of symbols to be emitted to the COFF debug symbol table
if (IsDebugSymbol(psymObj->StorageClass, &pimage->Switch) ) {
csymDebugEst += 1 + psymObj->NumberOfAuxSymbols;
}
}
// Skip any auxiliary symbol table entries.
// isym is initialized to 0 and set to one when ProcessWeakExtern is called
for (; isym < psymObj->NumberOfAuxSymbols; isym++) {
pasym = (PIMAGE_AUX_SYMBOL) FetchNextSymbol(&psymNext);
csymT++;
}
}
if ((Tool == Linker) && fNullThunk) {
// This module contains a NULL thunk
SetIdataNullThunkPMOD(pmod);
}
}
void
BuildExternalSymbolTable (
PIMAGE pimage,
PBOOL pfNewSymbol,
PMOD pmod,
WORD iArcMem,
WORD wMachine
)
/*++
Routine Description:
Reads thru an object, building the external symbols table,
and optionally counts number of relocations that will end up in image.
Arguments:
pst - pointer to external structure
pfNewSymbol - set to !0 if new symbol, otherwise 0
pmod - module to process
fIncReloc - if !0, count relocations
iArcMem - if !0, specifies number of archive file being processed
wMachine - machine type of object file.
Return Value:
None.
--*/
{
IMAGE_SECTION_HEADER *rgImgSecHdr;
PIMAGE_SYMBOL rgsymAll = NULL;
DWORD cbST;
NAME_LIST nlDirectives;
DWORD icon;
// Read in image section headers
ReadImageSecHdrInfoPMOD(pmod, &rgImgSecHdr);
if (fM68K && (Tool != Librarian)) {
// Allocate table that keeps track of references to sym tab
InitSTRefTab(pmod->csymbols);
}
rgsymAll = ReadSymbolTable(FoSymbolTablePMOD(pmod),
pmod->csymbols,
FALSE);
// Read and store object string table.
StringTable = ReadStringTable(SzFilePMOD(pmod),
FoSymbolTablePMOD(pmod) +
(pmod->csymbols * sizeof(IMAGE_SYMBOL)),
&cbST);
totalStringTableSize += cbST;
rgpExternObj = (PEXTERNAL *) PvAllocZ(pmod->csymbols * sizeof(PEXTERNAL));
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
mpisymbToc = (BYTE *) PvAllocZ(pmod->csymbols);
mpisymdwRestoreToc = (DWORD *) PvAlloc(pmod->csymbols * sizeof(DWORD));
}
if (fPowerMac && !(pmod->flags & IMAGE_FILE_MPPC_DLL)) {
// Process symbols in module before sections
// This is done to set TocBitVector and to process
// weak externs before the sections are processed
// Got to redo this some day - ShankarV
ProcessSymbolsInModule(
pimage,
pmod,
pfNewSymbol,
rgsymAll,
iArcMem, TRUE);
}
// process all sections in module
nlDirectives.First = nlDirectives.Last = 0;
nlDirectives.Count = 0;
for (icon = 0; icon < pmod->ccon; icon++) {
ProcessSectionInModule(pimage,
pmod,
(SHORT) (icon + 1),
&rgImgSecHdr[icon],
rgsymAll,
wMachine,
&nlDirectives);
}
if (fIncrDbFile) {
// Make sure directives haven't changed,
// REVIEW: we could ret rt away.
FVerifyDirectivesPMOD(pimage, pmod, &nlDirectives);
}
// Process all symbols in module
ProcessSymbolsInModule(pimage,
pmod,
pfNewSymbol,
rgsymAll,
iArcMem,
FALSE);
if (pimage->Switch.Link.fTCE) {
MakeEdgePextFromISym(pmod);
}
if (fM68K && (Tool != Librarian)) {
CleanupUnknownObjriRaw(pimage->pst,rgsymAll,StringTable,pmod);
CleanupSTRefTab();
}
// done processing sections and symbols, free tables
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
FreePv(mpisymdwRestoreToc);
FreePv(mpisymbToc);
}
FreePv(rgImgSecHdr);
FreeStringTable(StringTable);
FreeSymbolTable(rgsymAll);
FreePv(rgpExternObj);
StringTable = NULL;
if (rgComdatIsyms) {
FreePv(rgComdatIsyms);
rgComdatIsyms = NULL;
}
if (fIncrDbFile) {
FreeArgumentList(&nlDirectives);
}
}
COMDAT_ISYMS *
BuildIsecToIsymMapping (
PCON pcon,
PIMAGE_SYMBOL psymAll
)
{
PMOD pmod = PmodPCON(pcon);
COMDAT_ISYMS *rgcomdatisyms = (COMDAT_ISYMS *) PvAlloc(pmod->ccon * sizeof(COMDAT_ISYMS));
// initialize
DWORD i;
for (i = 0; i < pmod->ccon; i++) {
rgcomdatisyms[i].isymSec = (DWORD) -1;
rgcomdatisyms[i].isymComdat = (DWORD) -1;
}
// Walk the symbol table and place the first two symbols' isym
// associated with a section into the map
PIMAGE_SYMBOL psym = psymAll;
DWORD isym;
for (isym = 0; isym < pmod->csymbols; isym++, psym++) {
SHORT isec = psym->SectionNumber;
if (isec <= 0) {
// Skip the uninteresting symbols
isym += psym->NumberOfAuxSymbols;
psym += psym->NumberOfAuxSymbols;
continue;
}
assert((DWORD) isec <= pmod->ccon);
if (rgcomdatisyms[isec-1].isymSec == -1) {
rgcomdatisyms[isec-1].isymSec = isym;
} else if (rgcomdatisyms[isec-1].isymComdat == -1) {
rgcomdatisyms[isec-1].isymComdat = isym;
}
// Skip over the auxiliary symbols
isym += psym->NumberOfAuxSymbols;
psym += psym->NumberOfAuxSymbols;
}
return rgcomdatisyms;
}
void
RemoveAssociativeComdats (
PCON pcon
)
// marks any comdats that are 'associated' with PCON as IMAGE_SCN_LNK_REMOVE.
// note: all associated pcons come from the same obj
{
ENM_SRC enm_src;
InitEnmSrc(&enm_src, PmodPCON(pcon));
while (FNextEnmSrc(&enm_src)) {
if ((enm_src.pcon->selComdat == IMAGE_COMDAT_SELECT_ASSOCIATIVE) &&
(enm_src.pcon->pconAssoc == pcon)) {
enm_src.pcon->flags |= IMAGE_SCN_LNK_REMOVE;
}
}
EndEnmSrc(&enm_src);
}
BOOL
FIncludeComdat (
PIMAGE pimage,
PCON pcon,
PIMAGE_SYMBOL psymAll,
SHORT isecComdat,
const char **pszComdatName
)
/*++
Routine Description:
Decide whether to include a comdat in an image.
Arguments:
Return Value:
!0 if we are to include the comdat section, 0 otherwise.
--*/
{
static PMOD pmodCur = NULL;
PIMAGE_AUX_SYMBOL pasym;
PIMAGE_SYMBOL psym;
PEXTERNAL pext;
BOOL fNewSymbol = FALSE;
DWORD chksumComdat;
const char *szName;
BYTE selComdat;
PST pst;
assert(pimage);
assert(pimage->pst);
assert(pcon);
assert(psymAll);
pst = pimage->pst;
// build the isec to isym mapping
if (pmodCur != PmodPCON(pcon)) {
pmodCur = PmodPCON(pcon);
rgComdatIsyms = BuildIsecToIsymMapping(pcon, psymAll);
}
// setup section symbol
if (rgComdatIsyms[isecComdat-1].isymSec == -1) {
FatalPcon(pcon, BADCOFF_COMDATNOSYM, isecComdat);
}
psym = psymAll + rgComdatIsyms[isecComdat-1].isymSec;
if (psym->StorageClass != IMAGE_SYM_CLASS_STATIC) {
FatalPcon(pcon, BADCOFF_COMDATNOSYM, isecComdat);
}
if (psym->NumberOfAuxSymbols == 0) {
FatalPcon(pcon, NOAUXSYMFORCOMDAT, isecComdat);
}
pasym = (PIMAGE_AUX_SYMBOL) psym + 1;
selComdat = pasym->Section.Selection;
chksumComdat = pasym->Section.CheckSum;
if (selComdat == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
// REVIEW -- this algorithm (& assert) assumes that an
// associative comdat always follows the section it is
// associated with ... I don't know if that's really
// true.
assert(pasym->Section.Number < isecComdat);
// Include this comdat if the other one got included
// (i.e. has non-zero size).
pcon->selComdat = IMAGE_COMDAT_SELECT_ASSOCIATIVE;
pcon->pconAssoc = RgconPMOD(pmodCur) + pasym->Section.Number - 1;
if (pcon->pconAssoc->flags & IMAGE_SCN_LNK_REMOVE) {
return(FALSE);
}
return(TRUE);
}
// Setup COMDAT symbol
if (rgComdatIsyms[isecComdat-1].isymComdat == -1) {
FatalPcon(pcon, BADCOFF_COMDATNOSYM, isecComdat);
}
psym = psymAll + rgComdatIsyms[isecComdat-1].isymComdat;
// Second symbol has to be STATIC or EXTERNAL
if ((psym->StorageClass != IMAGE_SYM_CLASS_STATIC) &&
(psym->StorageClass != IMAGE_SYM_CLASS_EXTERNAL) &&
(psym->StorageClass != IMAGE_SYM_CLASS_FAR_EXTERNAL)) {
FatalPcon(pcon, BADCOFF_COMDATNOSYM, isecComdat);
}
if (!psym->N.Name.Short) {
szName = &StringTable[psym->N.Name.Long];
} else {
szName = SzNameSymPst(*psym, pst);
}
*pszComdatName = szName;
if (psym->StorageClass == IMAGE_SYM_CLASS_STATIC) {
return(TRUE);
}
if (IsLongName(*psym)) {
pext = LookupExternName(pst, LONGNAME, (char *) szName,
&fNewSymbol);
} else {
pext = LookupExternName(pst, SHORTNAME, (char *) psym->n_name,
&fNewSymbol);
}
if (fPowerMac && READ_BIT(pext, sy_NEWSYMBOL)) {
fNewSymbol = TRUE;
RESET_BIT(pext, sy_NEWSYMBOL);
}
if (fIncrDbFile) {
// A COMDAT that vanished, reappears - mark it as new.
if (pext->Flags & EXTERN_IGNORE) {
fNewSymbol = TRUE;
pext->Offset = 0;
pext->ppextPrevUndefined = NULL;
pext->pextNextUndefined = NULL;
pext->Flags = EXTERN_DEFINED;
SetDefinedExt(pext, FALSE, pimage->pst);
if (fPowerMac) {
RESET_BIT(pext, sy_TOCENTRYFIXEDUP);
RESET_BIT(pext, sy_DESCRRELWRITTEN);
}
}
// previously existing function/data. Need to look
// pext flags since a ref to comdat may occur before defn.
if (!fNewSymbol &&
((pext->Flags & EXTERN_NEWDATA) == 0) &&
((pext->Flags & EXTERN_NEWFUNC) == 0)) {
if (pext->Flags & EXTERN_DEFINED) {
// Already defined
if (selComdat == pext->pcon->selComdat) {
// Attribs match
if ((selComdat == IMAGE_COMDAT_SELECT_SAME_SIZE ||
selComdat == IMAGE_COMDAT_SELECT_EXACT_MATCH) &&
chksumComdat != pext->pcon->chksumComdat) {
errInc = errComdat;
}
return(FALSE);
}
// Attribs don't match
if (selComdat != IMAGE_COMDAT_SELECT_LARGEST &&
pext->pcon->selComdat != IMAGE_COMDAT_SELECT_LARGEST) {
// Pick largest may not match
errInc = errComdat;
return(FALSE);
}
} else {
// Currently undefined
if (pext->Flags & EXTERN_COMDAT) {
// Previously a comdat
if (selComdat == pext->pcon->selComdat) {
if ((selComdat == IMAGE_COMDAT_SELECT_SAME_SIZE ||
selComdat == IMAGE_COMDAT_SELECT_EXACT_MATCH) &&
chksumComdat != pext->pcon->chksumComdat) {
errInc = errComdat;
return(FALSE);
}
pcon->chksumComdat = chksumComdat;
pcon->selComdat = selComdat;
return(TRUE);
}
if (selComdat != IMAGE_COMDAT_SELECT_LARGEST &&
pext->pcon->selComdat != IMAGE_COMDAT_SELECT_LARGEST) {
// Pick largest may not match
errInc = errComdat;
return(FALSE);
}
}
}
}
// if a new function, mark it now since it will not
// appear as a new func when we process symbols.
if (fNewSymbol && ISFCN(psym->Type) && !FIsLibPCON(pcon)) {
pext->Flags |= EXTERN_NEWFUNC;
}
}
if ((pext->Flags & EXTERN_COMDAT) != 0) {
char szComFileName[_MAX_PATH * 2];
char szComFileNameExt[_MAX_PATH * 2];
if ((pext->Flags & EXTERN_DEFINED) == 0) {
// We may have an invalid object module. An example
// is when an object module defines two COMDATs with
// the same name because of the compiler's -H option
// being used to truncate away the uniqueness.
FatalPcon(pcon, BADCOFF_DUPCOMDAT, szName);
}
assert(pext->pcon != NULL);
assert(pext->pcon->flags & IMAGE_SCN_LNK_COMDAT);
if (selComdat != pext->pcon->selComdat) {
// types may not match in the case of IMAGE_COMDAT_SELECT_LARGEST
if (selComdat != IMAGE_COMDAT_SELECT_LARGEST &&
pext->pcon->selComdat != IMAGE_COMDAT_SELECT_LARGEST) {
SzComNamePMOD(pmodCur, szComFileName);
SzComNamePMOD(PmodPCON(pext->pcon), szComFileNameExt);
MultiplyDefinedSym(&pimage->Switch, szComFileName, szName, szComFileNameExt);
return(FALSE);
}
}
switch (pext->pcon->selComdat) {
case IMAGE_COMDAT_SELECT_NODUPLICATES :
SzComNamePMOD(pmodCur, szComFileName);
SzComNamePMOD(PmodPCON(pext->pcon), szComFileNameExt);
MultiplyDefinedSym(&pimage->Switch, szComFileName, szName, szComFileNameExt);
break;
case IMAGE_COMDAT_SELECT_ANY :
if (selComdat == IMAGE_COMDAT_SELECT_LARGEST) {
// select this comdat instead of the previously selected one
// UNDONE: tce is affected by this.
// special ilink handling
if (fINCR) {
if (fIncrDbFile) { // on ilink give up
errInc = errComdat;
return(FALSE);
} else { // on full build remove it from defn list but keep all the refs
RemoveExtFromDefList(PmodPCON(pext->pcon), pext);
}
}
pext->pcon->flags |= IMAGE_SCN_LNK_REMOVE;
RemoveAssociativeComdats(pext->pcon);
SetDefinedExt(pext, FALSE, pst);
goto SelectComdat;
}
break;
case IMAGE_COMDAT_SELECT_SAME_SIZE :
case IMAGE_COMDAT_SELECT_EXACT_MATCH :
if (chksumComdat != pext->pcon->chksumComdat) {
SzComNamePMOD(pmodCur, szComFileName);
SzComNamePMOD(PmodPCON(pext->pcon), szComFileNameExt);
MultiplyDefinedSym(&pimage->Switch, szComFileName, szName, szComFileNameExt);
}
break;
case IMAGE_COMDAT_SELECT_ASSOCIATIVE :
break;
case IMAGE_COMDAT_SELECT_LARGEST :
if ((pcon->cbRawData - pcon->cbPad) >
(pext->pcon->cbRawData - pext->pcon->cbPad)) {
// select this comdat instead of the previously selected one
// UNDONE: tce is affected by this
// special ilink handling
if (fINCR) {
if (fIncrDbFile) { // on ilink give up
errInc = errComdat;
return(FALSE);
} else { // on full build remove it from defn list but keep all the refs
RemoveExtFromDefList(PmodPCON(pext->pcon), pext);
}
}
pext->pcon->flags |= IMAGE_SCN_LNK_REMOVE;
RemoveAssociativeComdats(pext->pcon);
SetDefinedExt(pext, FALSE, pst);
goto SelectComdat;
}
break;
default:
FatalPcon(pcon, INVALIDCOMDATSEL, isecComdat);
}
return(FALSE);
} else if (pext->Flags & EXTERN_COMMON) {
// In FORTRAN it is possible to get a COMMON in one obj
// and a COMDAT in another for the same data. In this case,
// the COMDAT should be selected.
assert(pext->Flags & EXTERN_DEFINED);
// init sym is defined in a cmdline obj => previously seen sym
if (fINCR) {
ProcessInitSymReplacingCommonSym(pext,
SzNamePext(pext, pimage->pst),
pmodCur);
}
pext->Flags &= ~EXTERN_COMMON;
SetDefinedExt(pext, FALSE, pst);
} else if ((pext->Flags & EXTERN_DEFINED) != 0) {
// The symbol is already defined as neither a COMDAT nor
// COMMON. Don't select this COMDAT. A multiply defined
// warning will be issued by ProcessSymbolsInModule.
return(FALSE);
}
SelectComdat:
pcon->chksumComdat = chksumComdat;
pcon->selComdat = selComdat;
pext->Flags |= EXTERN_COMDAT;
// remove the new data flag on ilink
if (fINCR && (pext->Flags & EXTERN_NEWDATA)) {
pext->Flags &= ~(EXTERN_NEWDATA);
}
return(TRUE);
}
#if 0
BOOL
FIncludeComdat (
PIMAGE pimage,
PCON pcon,
PIMAGE_SYMBOL psymAll,
SHORT isecComdat,
const char **pszComdatName
)
/*++
Routine Description:
Decide whether to include a comdat in an image.
Arguments:
Return Value:
!0 if we are to include the comdat section, 0 otherwise.
--*/
{
static PMOD pmodCur = NULL;
static PIMAGE_SYMBOL psymNext;
static DWORD csym;
PIMAGE_AUX_SYMBOL pasym;
PIMAGE_SYMBOL psym;
PEXTERNAL pext;
BOOL fNewSymbol = FALSE;
BOOL fSecSymSeen = FALSE;
DWORD isymLast = 0;
DWORD chksumComdat;
const char *szName;
BYTE selComdat;
PST pst;
assert(pimage);
assert(pimage->pst);
assert(pcon);
assert(psymAll);
pst = pimage->pst;
// compiler guarantees that the comdat section symbols appear in
// order and the symbols defined in these sections come after
// the section symbols. make one pass over the symbol table (not quite)
// for each module to process comdat symbols. Caveat: all symbols of
// an obj must be in memory which is true now. If this should change
// uncomment the FileSeek() call below and make changes as outlined
// in the comments below.
if (pmodCur != PmodPCON(pcon)) {
pmodCur = PmodPCON(pcon);
csym = 0;
psymNext = psymAll;
}
while (csym < pmodCur->csymbols) {
psym = psymNext++;
++csym;
if (psym->SectionNumber != isecComdat) {
// Skip any auxiliary symbol table entries.
psymNext += psym->NumberOfAuxSymbols;
csym += psym->NumberOfAuxSymbols;
continue;
}
if (!fSecSymSeen) {
assert(IMAGE_SYM_CLASS_STATIC == psym->StorageClass);
fSecSymSeen = TRUE;
if (psym->NumberOfAuxSymbols) {
pasym = (PIMAGE_AUX_SYMBOL) psymNext;
selComdat = pasym->Section.Selection;
chksumComdat = pasym->Section.CheckSum;
psymNext += psym->NumberOfAuxSymbols;
csym += psym->NumberOfAuxSymbols;
isymLast = csym;
if (selComdat == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
// REVIEW -- this algorithm (& assert) assumes that an
// associative comdat always follows the section it is
// associated with ... I don't know if that's really
// true.
assert(pasym->Section.Number < isecComdat);
// Include this comdat if the other one got included
// (i.e. has non-zero size).
pcon->selComdat = IMAGE_COMDAT_SELECT_ASSOCIATIVE;
pcon->pconAssoc =
RgconPMOD(pmodCur) + pasym->Section.Number - 1;
if (pcon->pconAssoc->flags & IMAGE_SCN_LNK_REMOVE) {
return(FALSE);
}
return(TRUE);
}
continue;
}
FatalPcon(pcon, NOAUXSYMFORCOMDAT, isecComdat);
}
// need to reset symbol index to where we left off.
psymNext = psymAll+isymLast;
csym = isymLast;
// second symbol has to be STATIC or EXTERNAL
assert(IMAGE_SYM_CLASS_STATIC == psym->StorageClass ||
IMAGE_SYM_CLASS_EXTERNAL == psym->StorageClass ||
IMAGE_SYM_CLASS_FAR_EXTERNAL == psym->StorageClass);
if (!psym->N.Name.Short) {
szName = &StringTable[psym->N.Name.Long];
} else {
szName = SzNameSymPst(*psym, pst);
}
*pszComdatName = szName;
if (psym->StorageClass == IMAGE_SYM_CLASS_STATIC) {
return(TRUE);
}
if (IsLongName(*psym)) {
pext = LookupExternName(pst, LONGNAME, (char *) szName,
&fNewSymbol);
} else {
pext = LookupExternName(pst, SHORTNAME, (char *) psym->n_name,
&fNewSymbol);
}
if (fPowerMac && READ_BIT(pext, sy_NEWSYMBOL)) {
fNewSymbol = TRUE;
RESET_BIT(pext, sy_NEWSYMBOL);
}
// ilink handling of COMDATs
if (fIncrDbFile) {
// A COMDAT that vanished, reappears - mark it as new.
if (pext->Flags & EXTERN_IGNORE) {
fNewSymbol = TRUE;
pext->Offset = 0;
pext->ppextPrevUndefined = NULL;
pext->pextNextUndefined = NULL;
pext->Flags = EXTERN_DEFINED;
SetDefinedExt(pext, FALSE, pimage->pst);
if (fPowerMac) {
RESET_BIT(pext, sy_TOCENTRYFIXEDUP);
RESET_BIT(pext, sy_DESCRRELWRITTEN);
}
}
// previously existing function/data. Need to look
// pext flags since a ref to comdat may occur before defn.
if (!fNewSymbol &&
((pext->Flags & EXTERN_NEWDATA) == 0) &&
((pext->Flags & EXTERN_NEWFUNC) == 0) ) {
if (pext->Flags & EXTERN_DEFINED) {
// Already defined
if (selComdat == pext->pcon->selComdat) {
// Attribs match
if ((selComdat == IMAGE_COMDAT_SELECT_SAME_SIZE ||
selComdat == IMAGE_COMDAT_SELECT_EXACT_MATCH) &&
chksumComdat != pext->pcon->chksumComdat) {
errInc = errComdat;
}
return(FALSE);
}
// Attribs don't match
errInc = errComdat;
return(FALSE);
} else if (pext->Flags & EXTERN_COMDAT) {
// Previously a comdat
if (selComdat == pext->pcon->selComdat) {
if ((selComdat == IMAGE_COMDAT_SELECT_SAME_SIZE ||
selComdat == IMAGE_COMDAT_SELECT_EXACT_MATCH) &&
chksumComdat != pext->pcon->chksumComdat) {
errInc = errComdat;
return(FALSE);
}
pcon->chksumComdat = chksumComdat;
pcon->selComdat = selComdat;
return(TRUE);
}
errInc = errComdat;
return(FALSE);
}
}
// if a new function, mark it now since it will not
// appear as a new func when we process symbols.
if (fNewSymbol && ISFCN(psym->Type) && !FIsLibPCON(pcon)) {
pext->Flags |= EXTERN_NEWFUNC;
}
}
if ((pext->Flags & EXTERN_COMDAT) != 0) {
char szComFileName[_MAX_PATH * 2];
char szComFileNameExt[_MAX_PATH * 2];
if ((pext->Flags & EXTERN_DEFINED) == 0) {
// We may have an invalid object module. An example
// is when an object module defines two COMDATs with
// the same name because of the compiler's -H option
// being used to truncate away the uniqueness.
FatalPcon(pcon, BADCOFF_DUPCOMDAT, szName);
}
assert(pext->pcon != NULL);
assert(pext->pcon->flags & IMAGE_SCN_LNK_COMDAT);
if (selComdat != pext->pcon->selComdat) {
// types may not match in the case of IMAGE_COMDAT_SELECT_LARGEST
if (selComdat != IMAGE_COMDAT_SELECT_LARGEST &&
pext->pcon->selComdat != IMAGE_COMDAT_SELECT_LARGEST) {
SzComNamePMOD(pmodCur, szComFileName);
SzComNamePMOD(PmodPCON(pext->pcon), szComFileNameExt);
MultiplyDefinedSym(&pimage->Switch, szComFileName, szName, szComFileNameExt);
return(FALSE);
}
}
switch (pext->pcon->selComdat) {
case IMAGE_COMDAT_SELECT_NODUPLICATES :
SzComNamePMOD(pmodCur, szComFileName);
SzComNamePMOD(PmodPCON(pext->pcon), szComFileNameExt);
MultiplyDefinedSym(&pimage->Switch, szComFileName, szName, szComFileNameExt);
break;
case IMAGE_COMDAT_SELECT_ANY :
if (selComdat == IMAGE_COMDAT_SELECT_LARGEST) {
// select this comdat instead of the previously selected one
// UNDONE: tce is affected by this.
pext->pcon->flags |= IMAGE_SCN_LNK_REMOVE;
RemoveAssociativeComdats(pext->pcon);
SetDefinedExt(pext, FALSE, pst);
goto SelectComdat;
}
break;
case IMAGE_COMDAT_SELECT_SAME_SIZE :
case IMAGE_COMDAT_SELECT_EXACT_MATCH :
if (chksumComdat != pext->pcon->chksumComdat) {
SzComNamePMOD(pmodCur, szComFileName);
SzComNamePMOD(PmodPCON(pext->pcon), szComFileNameExt);
MultiplyDefinedSym(&pimage->Switch, szComFileName, szName, szComFileNameExt);
}
break;
case IMAGE_COMDAT_SELECT_ASSOCIATIVE :
break;
case IMAGE_COMDAT_SELECT_LARGEST :
if ((pcon->cbRawData - pcon->cbPad) >
(pext->pcon->cbRawData - pext->pcon->cbPad)) {
// select this comdat instead of the previously selected one
// UNDONE: tce is affected by this
pext->pcon->flags |= IMAGE_SCN_LNK_REMOVE;
RemoveAssociativeComdats(pext->pcon);
SetDefinedExt(pext, FALSE, pst);
goto SelectComdat;
}
break;
default:
FatalPcon(pcon, INVALIDCOMDATSEL, isecComdat);
}
return(FALSE);
} else if (pext->Flags & EXTERN_COMMON) {
// In FORTRAN it is possible to get a COMMON in one obj
// and a COMDAT in another for the same data. In this case,
// the COMDAT should be selected.
assert(pext->Flags & EXTERN_DEFINED);
pext->Flags &= ~EXTERN_COMMON;
SetDefinedExt(pext, FALSE, pst);
} else if ((pext->Flags & EXTERN_DEFINED) != 0) {
// The symbol is already defined as neither a COMDAT nor
// COMMON. Don't select this COMDAT. A multiply defined
// warning will be issued by ProcessSymbolsInModule.
return(FALSE);
}
SelectComdat:
pcon->chksumComdat = chksumComdat;
pcon->selComdat = selComdat;
pext->Flags |= EXTERN_COMDAT;
// remove the new data flag on ilink
if (fINCR && (pext->Flags & EXTERN_NEWDATA)) {
pext->Flags &= ~(EXTERN_NEWDATA);
}
return(TRUE);
}
FatalPcon(pcon, BADCOFF_COMDATNOSYM, isecComdat);
return(FALSE);
}
#endif // 0
DWORD
AppendLongName (
PST pst,
const char *Name
)
/*++
Routine Description:
Appends the name to string table.
NOTE: This function currently used by ilink but we should
be able to use it for non-ilink, non-coff builds.
Arguments:
pst - external symbol table.
Name - Pointer to symbol name.
Return Value:
A pointer to the symbol name in the long string table.
--*/
{
DWORD Offset;
PBLK pblk = &pst->blkStringTable;
if (pblk->pb == NULL) {
GrowBlk(pblk, 16L*_1K);
// Reserve space for String Table Length
pblk->cb += sizeof(DWORD);
}
Offset = pblk->cb;
// append long name
IbAppendBlk(pblk, Name, strlen(Name)+1);
// return offset
return(Offset);
}
DWORD
LookupLongName (
PST pst,
const char *Name
)
/*++
Routine Description:
Looks up a symbol name in the long string table. If not found, adds
the symbol name to the long string table.
Arguments:
pst - external symbol table.
Name - Pointer to symbol name.
Return Value:
A pointer to the symbol name in the long string table.
--*/
{
INT i;
PLONG_STRING_LIST ptrString;
PLONG_STRING_LIST *ptrLastString;
PBLK pblk;
// we should never be here on an ilink
assert(!fIncrDbFile);
ptrString = pst->plslFirstLongName;
pblk = &pst->blkStringTable;
// Adds "Name" to String Table if not found.
while (ptrString) {
if (!(i = strcmp(Name, (char *)(&pblk->pb[ptrString->Offset])))) {
return(ptrString->Offset);
}
if (i < 0) {
ptrLastString = &ptrString->Left;
ptrString = ptrString->Left;
} else {
ptrLastString = &ptrString->Right;
ptrString = ptrString->Right;
}
}
ptrString = (PLONG_STRING_LIST) ALLOC_PERM(sizeof(LONG_STRING_LIST));
if (pst->plslFirstLongName == NULL) {
pst->plslFirstLongName = ptrString;
} else {
*ptrLastString = ptrString;
}
if (pblk->pb == NULL) {
GrowBlk(pblk, 16L*_1K);
// Reserve space for String Table Length
pblk->cb += sizeof(DWORD);
}
ptrString->Offset = pblk->cb;
IbAppendBlk(pblk, Name, strlen(Name)+1);
ptrString->Left = ptrString->Right = NULL;
return(ptrString->Offset);
}
INT __cdecl
Compare (
void const *String1,
void const *String2
)
/*++
Routine Description:
Compares two strings.
Arguments:
String1 - A pointer to a string.
String2 - A pointer to a string.
Return Value:
Same as strcmp().
--*/
{
return (strcmp(*(char **) String1, *(char **) String2));
}
void
ReadImageSecHdrInfoPMOD (
PMOD pmod,
IMAGE_SECTION_HEADER **prgImgSecHdr
)
/*++
Routine Description:
Reads in the section headers and saves info.
Arguments:
pmod - ptr to a mod
prgImgSecHdr - if not NULL on return will have ptr to array of section headers
Return Value:
None.
--*/
{
IMAGE_SECTION_HEADER *rgImgSecHdr;
DWORD cbImgSecHdrs;
DWORD icon;
DWORD Seek = sizeof(IMAGE_FILE_HEADER) + pmod->cbOptHdr;
FileSeek(FileReadHandle, FoMemberPMOD(pmod) + Seek, SEEK_SET);
cbImgSecHdrs = pmod->ccon * sizeof(IMAGE_SECTION_HEADER);
rgImgSecHdr = (IMAGE_SECTION_HEADER *) PvAlloc(cbImgSecHdrs);
FileRead(FileReadHandle, rgImgSecHdr, cbImgSecHdrs);
if (pmod->rgci == NULL) {
pmod->rgci = (CONINFO *) PvAlloc(pmod->ccon * sizeof(CONINFO));
}
assert(pmod->rgci);
for (icon = 0; icon < pmod->ccon; icon++) {
pmod->rgci[icon].cReloc = rgImgSecHdr[icon].NumberOfRelocations;
pmod->rgci[icon].cLinenum = rgImgSecHdr[icon].NumberOfLinenumbers;
pmod->rgci[icon].foRelocSrc = rgImgSecHdr[icon].PointerToRelocations;
pmod->rgci[icon].foLinenumSrc = rgImgSecHdr[icon].PointerToLinenumbers;
pmod->rgci[icon].foRawDataSrc = rgImgSecHdr[icon].PointerToRawData;
pmod->rgci[icon].rvaSrc = rgImgSecHdr[icon].VirtualAddress;
}
if (prgImgSecHdr) {
*prgImgSecHdr = rgImgSecHdr;
} else {
FreePv(rgImgSecHdr);
}
}
char *
ReadStringTable (
const char *szFile,
LONG fo,
DWORD *pcb
)
/*++
Routine Description:
Reads the long string table from FileReadHandle.
Arguments:
szFile - file to read string table from
fo - offset to read symbol table from
*pcb - size of the string table read
Return Value:
A pointer to the long string table in memory.
--*/
{
char *pST;
DWORD cbFile;
assert(!fStringTableInUse);
fStringTableInUse = TRUE;
if (fo == 0) {
return NULL; // no stringtable
}
fMappedStrings = FALSE;
pST = (char *) PbMappedRegion(FileReadHandle, fo, sizeof(DWORD));
if (pST != NULL) {
*pcb = *(DWORD UNALIGNED *) pST;
if (*pcb == 0) {
return(NULL);
}
if (*pcb == sizeof(DWORD)) {
*pcb = 0;
return(NULL);
}
pST = (char *) PbMappedRegion(FileReadHandle, fo, *pcb);
if (pST != NULL) {
if (pST[*pcb - 1] == '\0') {
// Only use mapped string table if properly terminated
fMappedStrings = TRUE;
return(pST);
}
}
}
cbFile = FileLength(FileReadHandle);
if (fo + sizeof(DWORD) > cbFile ||
(FileSeek(FileReadHandle, fo, SEEK_SET),
FileRead(FileReadHandle, pcb, sizeof(DWORD)),
fo + *pcb > cbFile)) {
// Invalid stringtable pointer.
Warning(szFile, BADCOFF_STRINGTABLE);
*pcb = 0;
return NULL;
}
if (*pcb == 0) {
return(NULL);
}
if (*pcb == sizeof(DWORD)) {
*pcb = 0;
return(NULL);
}
// Allocate string table plus an extra NULL byte to lessen our
// chances of running off the end of the string table if an object
// is corrupt.
GrowBlk(&blkStringTable, *pcb + 1);
pST = (char *) blkStringTable.pb;
FileSeek(FileReadHandle, fo, SEEK_SET);
FileRead(FileReadHandle, pST, *pcb);
if (*(pST + *pcb - 1)) {
Warning(szFile, NOSTRINGTABLEEND);
}
return(pST);
}
void
FreeStringTable(
char *pchStringTable
)
{
assert(fStringTableInUse);
fStringTableInUse = FALSE;
assert(fMappedStrings || pchStringTable == NULL || pchStringTable == (char *) blkStringTable.pb);
}
void
WriteStringTable (
INT FileHandle,
PST pst
)
/*++
Routine Description:
Writes the long string table to FileWriteHandle.
Arguments:
pst - symbol table
Return Value:
None.
--*/
{
DWORD li;
PBLK pblk = &pst->blkStringTable;
InternalError.Phase = "WriteStringTable";
if (pblk->pb) {
li = pblk->cb;
*(DWORD *) &pblk->pb[0] = li;
FileWrite(FileHandle, pblk->pb, li);
} else {
// No long string names, write a zero.
li = 0L;
FileWrite(FileHandle, &li, sizeof(DWORD));
}
}
PIMAGE_RELOCATION
ReadRgrelPCON(
PCON pcon,
DWORD *pcreloc
)
{
DWORD creloc;
DWORD cbRelocs;
PIMAGE_RELOCATION rgrel;
assert(!fRelocsInUse);
fRelocsInUse = TRUE;
creloc = CRelocSrcPCON(pcon);
if (pcon->flags & IMAGE_SCN_LNK_NRELOC_OVFL) {
if (creloc == 0xFFFF) {
IMAGE_RELOCATION relFirst;
PIMAGE_RELOCATION prelFirst;
// When creloc == 0xFFFF, the reloc count is stored in the first relocation
prelFirst = (PIMAGE_RELOCATION) PbMappedRegion(FileReadHandle,
FoRelocSrcPCON(pcon),
sizeof(IMAGE_RELOCATION));
if (prelFirst == NULL) {
FileSeek(FileReadHandle, FoRelocSrcPCON(pcon), SEEK_SET);
FileRead(FileReadHandle, (void *) &relFirst, sizeof(IMAGE_RELOCATION));
prelFirst = &relFirst;
}
creloc = prelFirst->VirtualAddress;
#ifndef TESTOVFL
if (creloc < 0xFFFF) {
FatalPcon(pcon, BADCOFF_RELOCCOUNT, creloc);
}
#endif
} else {
FatalPcon(pcon, BADCOFF_RELOCCOUNT, creloc);
}
}
*pcreloc = creloc;
cbRelocs = creloc * sizeof(IMAGE_RELOCATION);
rgrel = (PIMAGE_RELOCATION) PbMappedRegion(FileReadHandle,
FoRelocSrcPCON(pcon),
cbRelocs);
fMappedRelocs = (rgrel != NULL);
if (fMappedRelocs) {
return(rgrel);
}
GrowBlk(&blkRelocs, cbRelocs);
rgrel = (PIMAGE_RELOCATION) blkRelocs.pb;
FileSeek(FileReadHandle, FoRelocSrcPCON(pcon), SEEK_SET);
FileRead(FileReadHandle, (void *) rgrel, cbRelocs);
return(rgrel);
}
void
FreeRgrel(
PIMAGE_RELOCATION rgrel
)
{
assert(fRelocsInUse);
fRelocsInUse = FALSE;
assert(fMappedRelocs || rgrel == NULL || rgrel == (PIMAGE_RELOCATION) blkRelocs.pb);
}
PIMAGE_SYMBOL
ReadSymbolTable (
DWORD fo,
DWORD NumberOfSymbols,
BOOL fAllowWrite
)
/*++
Routine Description:
Reads the symbol table from FileReadHandle.
Arguments:
fo - A file pointer to the symbol table on disk.
NumberOfSymbols - Number of symbol table entries.
Return Value:
A pointer to the symbol table in memory.
If zero, then indicates entire symbol table won't fit in memory.
--*/
{
DWORD cb;
PIMAGE_SYMBOL rgsym;
assert(!fSymbolTableInUse);
fSymbolTableInUse = TRUE;
cb = NumberOfSymbols * sizeof(IMAGE_SYMBOL);
// Don't use mapping because ProcessSymbolsInModule writes to symbol
if (!fAllowWrite) {
rgsym = (PIMAGE_SYMBOL) PbMappedRegion(FileReadHandle,
fo,
cb);
} else {
rgsym = NULL;
}
fMappedSyms = (rgsym != NULL);
if (fMappedSyms) {
return(rgsym);
}
GrowBlk(&blkSymbolTable, cb);
rgsym = (PIMAGE_SYMBOL) blkSymbolTable.pb;
FileSeek(FileReadHandle, fo, SEEK_SET);
FileRead(FileReadHandle, (void *) rgsym, cb);
return(rgsym);
}
void
FreeSymbolTable(
PIMAGE_SYMBOL rgsym
)
{
assert(fSymbolTableInUse);
fSymbolTableInUse = FALSE;
assert(fMappedSyms || rgsym == NULL || rgsym == (PIMAGE_SYMBOL) blkSymbolTable.pb);
}
PIMAGE_SYMBOL
FetchNextSymbol (
PIMAGE_SYMBOL *PtrSymbolTable
)
/*++
Routine Description:
Returns a pointer to the next symbol table entry.
Arguments:
PtrSymbolTable - A pointer to the last symbol table entry.
If zero, then indicates the next symbol table entry
must be read from disk, else its already in memory.
Return Value:
A pointer to the next symbol table entry in memory.
--*/
{
static IMAGE_SYMBOL symbol;
if (*PtrSymbolTable) {
return((*PtrSymbolTable)++);
}
ReadSymbolTableEntry(FileReadHandle, &symbol);
return(&symbol);
}
void
ReadFileHeader (
INT Handle,
PIMAGE_FILE_HEADER FileHeader
)
/*++
Routine Description:
Reads a file header.
Arguments:
Handle - File handle to read from.
FileHeader - Pointer to location to write file header to.
Return Value:
None.
--*/
{
FileRead(Handle, FileHeader, sizeof(IMAGE_FILE_HEADER));
}
void
WriteFileHeader (
INT Handle,
PIMAGE_FILE_HEADER FileHeader
)
/*++
Routine Description:
Writes a file header.
Arguments:
Handle - File handle to write to.
FileHeader - Pointer to location to read file header from.
Return Value:
None.
--*/
{
// Force flags for little endian target
FileHeader->Characteristics |= IMAGE_FILE_32BIT_MACHINE;
FileWrite(Handle, FileHeader, sizeof(IMAGE_FILE_HEADER));
}
void
ReadOptionalHeader (
INT Handle,
PIMAGE_OPTIONAL_HEADER OptionalHeader,
WORD Size
)
/*++
Routine Description:
Reads an optional header.
Arguments:
Handle - File handle to read from.
OptionalHeader - Pointer to location to write optional header to.
Size - Length in bytes of optional header.
Return Value:
None.
--*/
{
if (Size) {
Size = (WORD) __min(Size, sizeof(IMAGE_OPTIONAL_HEADER));
FileRead(Handle, OptionalHeader, Size);
}
}
void
WriteOptionalHeader (
INT Handle,
PIMAGE_OPTIONAL_HEADER OptionalHeader,
WORD Size
)
/*++
Routine Description:
Writes an optional header.
Arguments:
Handle - File handle to read from.
OptionalHeader - Pointer to location to read optional header from.
Size - Length in bytes of optional header.
Return Value:
None.
--*/
{
if (Size) {
FileWrite(Handle, OptionalHeader, Size);
}
}
void
ReadSymbolTableEntry (
INT Handle,
PIMAGE_SYMBOL SymbolEntry
)
/*++
Routine Description:
Reads a symbol table entry.
Arguments:
Handle - File handle to read from.
SymbolEntry - Pointer to location to write symbol entry to.
Return Value:
None.
--*/
{
FileRead(Handle, (void *) SymbolEntry, sizeof(IMAGE_SYMBOL));
}
// WriteSectionHeader: writes a COFF section header to object or image file.
//
void
WriteSectionHeader (
INT Handle,
PIMAGE_SECTION_HEADER SectionHeader
)
{
FileWrite(Handle, SectionHeader, sizeof(IMAGE_SECTION_HEADER));
}
void
WriteSymbolTableEntry (
INT Handle,
PIMAGE_SYMBOL SymbolEntry
)
/*++
Routine Description:
Writes a symbol entry.
Arguments:
Handle - File handle to write to.
SymbolEntry - Pointer to location to read symbol entry from.
Return Value:
None.
--*/
{
BOOL fPCODE = FALSE;
if ((fM68K || fPowerMac) && FPcodeSym(*SymbolEntry)) {
fPCODE = TRUE;
SymbolEntry->Type &= ~IMAGE_SYM_TYPE_PCODE;
}
FileWrite(Handle, (void *) SymbolEntry, sizeof(IMAGE_SYMBOL));
if ((fM68K || fPowerMac) && fPCODE) {
SymbolEntry->Type |= IMAGE_SYM_TYPE_PCODE;
}
}
void
WriteAuxSymbolTableEntry (
INT Handle,
PIMAGE_AUX_SYMBOL AuxSymbolEntry
)
/*++
Routine Description:
Writes an auxiliary symbol entry.
Arguments:
Handle - File handle to write to.
AuxSymbolEntry - Pointer to location to read auxiliary symbol entry from.
Return Value:
None.
--*/
{
FileWrite(Handle, (void *) AuxSymbolEntry, sizeof(IMAGE_AUX_SYMBOL));
}
void
ReadRelocations (
INT Handle,
PIMAGE_RELOCATION RelocTable,
DWORD NumRelocs
)
/*++
Routine Description:
Reads relocations.
Arguments:
Handle - File handle to read from.
RelocTable - Pointer to location to write relocations to.
NumRelocs - Number of relocations to read.
Return Value:
None.
--*/
{
FileRead(Handle, (void *) RelocTable, NumRelocs*sizeof(IMAGE_RELOCATION));
}
void
WriteRelocations (
INT Handle,
PIMAGE_RELOCATION RelocTable,
DWORD NumRelocs
)
/*++
Routine Description:
Write relocations.
Arguments:
Handle - File handle to write to.
RelocTable - Pointer to location to read relocations from.
NumRelocs - Number of relocations to write.
Return Value:
None.
--*/
{
FileWrite(Handle, (PVOID)RelocTable, NumRelocs*sizeof(IMAGE_RELOCATION));
}
INT __cdecl
FpoDataCompare (
void const *Fpo1,
void const *Fpo2
)
/*++
Routine Description:
Compares two fpo data structures
Arguments:
Fpo1 - A pointer to a Fpo Data Structure.
Fpo2 - A pointer to a Fpo Data Structure.
Return Value:
Same as strcmp().
--*/
{
return (((PFPO_DATA) Fpo1)->ulOffStart -
((PFPO_DATA) Fpo2)->ulOffStart);
}
char *
SzModifyFilename(
const char *szIn,
const char *szNewExt
)
// Mallocs a version of the old filename with the new extension.
{
char szDrive[_MAX_DRIVE];
char szDir[_MAX_DIR];
char szFname[_MAX_FNAME];
char szExt[_MAX_EXT];
char szOut[_MAX_PATH];
_splitpath(szIn, szDrive, szDir, szFname, szExt);
_makepath(szOut, szDrive, szDir, szFname, szNewExt);
return SzDup(szOut);
}
void
SaveFixupForMapFile(
DWORD rva
)
{
if (plrvaFixupsForMapFile == NULL ||
crvaFixupsForMapFile >= crvaInLrva) {
LRVA *plrvaNew = (LRVA *) PvAlloc(sizeof(LRVA));
plrvaNew->plrvaNext = plrvaFixupsForMapFile;
plrvaFixupsForMapFile = plrvaNew;
crvaFixupsForMapFile = 0;
}
plrvaFixupsForMapFile->rgrva[crvaFixupsForMapFile++] = rva;
}
void
PrintBanner(VOID)
{
const char *szThing;
switch (Tool) {
case Editor: szThing = "COFF Binary File Editor"; break;
#if defined(_M_IX86) || defined(_M_MRX000)
case Linker: szThing = "32-Bit Incremental Linker"; break;
#else
case Linker: szThing = "32-Bit Executable Linker"; break;
#endif
case Librarian: szThing = "32-Bit Library Manager"; break;
case Dumper: szThing = "COFF Binary File Dumper"; break;
default: szThing = ToolGenericName; break;
}
printf("Microsoft (R) %s Version " VERSION_STR
"\n"
"Copyright (C) Microsoft Corp 1992-1996. All rights reserved.\n"
"\n",
szThing);
if (blkResponseFileEcho.pb != NULL) {
if (blkResponseFileEcho.pb[blkResponseFileEcho.cb - 1] != '\n') {
IbAppendBlk(&blkResponseFileEcho, "\n", 1);
}
IbAppendBlk(&blkResponseFileEcho, "", 1); // null-terminate
printf("%s", blkResponseFileEcho.pb);
FreeBlk(&blkResponseFileEcho);
}
fflush(stdout);
fNeedBanner = FALSE;
}
const char *
SzObjSectionName(
const char *szsName,
const char *rgchObjStringTable
)
// Returns a section name as read from an object, properly mapping names
// beginning with "/" to longnames.
//
// Uses a static buffer for the returned zero-terminated name (i.e. don't
// use it twice at the same time ...)
{
static char szSectionNameBuf[IMAGE_SIZEOF_SHORT_NAME + 1];
unsigned long ichName;
strncpy(szSectionNameBuf, szsName, IMAGE_SIZEOF_SHORT_NAME);
if (szSectionNameBuf[0] != '/') {
return szSectionNameBuf;
}
if (sscanf(&szSectionNameBuf[1], "%7lu", &ichName) == 1) {
return &rgchObjStringTable[ichName];
}
return szSectionNameBuf;
}
DWORD
RvaAlign(
DWORD rvaIn,
DWORD flags
)
// Aligns an RVA according to the alignment specified in the given flags.
//
{
DWORD mskAlign;
if (flags & IMAGE_SCN_TYPE_NO_PAD) {
return rvaIn; // no align
}
switch (flags & 0x00700000) {
default: assert(FALSE); // this can't happen
case IMAGE_SCN_ALIGN_1BYTES:
return rvaIn;
case IMAGE_SCN_ALIGN_2BYTES: mskAlign = 1; break;
case IMAGE_SCN_ALIGN_4BYTES: mskAlign = 3; break;
case IMAGE_SCN_ALIGN_8BYTES: mskAlign = 7; break;
case IMAGE_SCN_ALIGN_16BYTES: mskAlign = 15; break;
case IMAGE_SCN_ALIGN_32BYTES: mskAlign = 31; break;
case IMAGE_SCN_ALIGN_64BYTES: mskAlign = 63; break;
// If no explicit alignment is specified (because this is an old object or a
// section that was created by the linker), default a to machine-dependent value
case 0:
if (fM68K) {
mskAlign = 3;
break;
} else {
mskAlign = 15;
break;
}
}
if ((rvaIn & mskAlign) == 0) {
return rvaIn;
}
return (rvaIn & ~mskAlign) + mskAlign + 1;
}
void
AddToLext(
LEXT **pplext,
PEXTERNAL pext
)
{
LEXT *plextNew = (LEXT *) PvAlloc(sizeof(LEXT));
plextNew->pext = pext;
plextNew->plextNext = *pplext;
*pplext = plextNew;
}
LEXT *
PlextFind (
LEXT *plextFirst,
PEXTERNAL pext
)
{
LEXT *plext = plextFirst;
while (plext) {
if (plext->pext == pext) {
return plext;
}
plext = plext->plextNext;
}
return NULL;
}
BOOL
FValidFileHdr (
const char *szFilename,
PIMAGE_FILE_HEADER pImgFileHdr
)
/*++
Routine Description:
Validates an object or image.
Arguments:
Argument - argument.
Return Value:
0 invalid file header
!0 valid file header
--*/
{
// Check to see if it has a valid machine type
switch (pImgFileHdr->Machine) {
case IMAGE_FILE_MACHINE_UNKNOWN :
case IMAGE_FILE_MACHINE_I386 :
case IMAGE_FILE_MACHINE_R3000 :
case IMAGE_FILE_MACHINE_R4000 :
case IMAGE_FILE_MACHINE_R10000 :
case IMAGE_FILE_MACHINE_ALPHA :
case IMAGE_FILE_MACHINE_POWERPC :
case 0x0290 : // UNDONE : IMAGE_FILE_MACHINE_PARISC
case IMAGE_FILE_MACHINE_M68K :
case IMAGE_FILE_MACHINE_MPPC_601 :
break;
default:
Warning(szFilename, NOTCOFF);
return(FALSE);
}
return(TRUE);
}
// CheckDupFilename: checks for an output file having the same name as an
// input file.
void
CheckDupFilename(
const char *szOutFilename,
PARGUMENT_LIST parg
)
{
char szFullOutPath[_MAX_PATH];
if (_fullpath(szFullOutPath, szOutFilename, _MAX_PATH - 1) == NULL) {
Fatal(NULL, CANTOPENFILE, szOutFilename);
}
while (parg != NULL) {
char szPargPath[_MAX_PATH];
if (_fullpath(szPargPath, parg->OriginalName, _MAX_PATH - 1) == NULL) {
Fatal(NULL, CANTOPENFILE, parg->OriginalName);
}
if (_tcsicmp(szFullOutPath, szPargPath) == 0) {
OutFilename = NULL; // don't clobber output file
Fatal(NULL, DUP_OUT_FILE, szFullOutPath);
}
parg = parg->Next;
}
}
typedef PIMAGE_NT_HEADERS (WINAPI *PFNCSMF)(PVOID, DWORD, DWORD *, DWORD *);
typedef PIMAGE_NT_HEADERS (WINAPI *PFNMFACS)(LPSTR, DWORD *, DWORD *);
void
ChecksumImage(
PIMAGE pimage
)
{
HINSTANCE hImagehlp;
DWORD cbImageFile;
BYTE *pbMap;
DWORD dwSumHeader;
DWORD dwChecksum;
hImagehlp = LoadLibrary("IMAGEHLP.DLL");
if (hImagehlp == NULL) {
Warning(NULL, DLLLOADWARN, "IMAGEHLP.DLL");
return;
}
cbImageFile = FileLength(FileWriteHandle);
pbMap = PbMappedRegion(FileWriteHandle, 0, cbImageFile);
if (pbMap == NULL) {
PFNMFACS pfnMapAndCheckSum;
pfnMapAndCheckSum = (PFNMFACS) GetProcAddress(hImagehlp, "MapFileAndCheckSumA");
if (pfnMapAndCheckSum == NULL) {
Warning(NULL, FCNNOTFOUNDWARN, "MapFileAndCheckSumA", "IMAGEHLP.DLL");
return;
}
FileClose(FileWriteHandle, TRUE);
if ((*pfnMapAndCheckSum)(OutFilename, &dwSumHeader, &dwChecksum)) {
Warning(NULL, UNABLETOCHECKSUM);
}
FileWriteHandle = FileOpen(OutFilename, O_RDWR | O_BINARY, S_IREAD | S_IWRITE);
pimage->ImgOptHdr.CheckSum = dwChecksum;
pimage->WriteHeader(pimage, FileWriteHandle);
} else {
PFNCSMF pfnCheckSumMappedFile;
PIMAGE_NT_HEADERS pHdr;
pfnCheckSumMappedFile = (PFNCSMF) GetProcAddress(hImagehlp, "CheckSumMappedFile");
if (pfnCheckSumMappedFile == NULL) {
Warning(NULL, FCNNOTFOUNDWARN, "CheckSumMappedFile", "IMAGEHLP.DLL");
return;
}
pHdr = (*pfnCheckSumMappedFile)(pbMap, cbImageFile, &dwSumHeader, &dwChecksum);
if (pHdr == NULL) {
Warning(NULL, UNABLETOCHECKSUM);
return;
}
pHdr->OptionalHeader.CheckSum = dwChecksum;
}
FreeLibrary(hImagehlp);
}
//================================================================
// PsymAlternateStaticPcodeSym -
// given a pointer to a static pcode symbol foo,
// this function returns a pointer to __nep_foo. __nep_foo will
// preced foo by either
// one symbol (the file was *NOT* compiled /Gy), or
// three symbols (the file was compiled /Gy.
// In the second case, the two symbols in between the native and
// pcode symbol are the section sym and its aux sym.
// So the algorithm is to look back two symbols and check if that
// symbol has one aux symbol. If so, the file was compiled /Gy
// and __nep_foo is three symbols back. Otherwise, __nep_foo is
// one symbol back.
//================================================================
PIMAGE_SYMBOL
PsymAlternateStaticPcodeSym(
PIMAGE pimage,
PCON pcon,
BOOL fPass1,
PIMAGE_SYMBOL psym,
BOOL fPcodeRef
)
{
const char *szPrefix = fPcodeRef ? szPCODEFHPREFIX : szPCODENATIVEPREFIX;
size_t cchPrefix = strlen(szPrefix);
PIMAGE_SYMBOL pStaticPcodeSym;
WORD isym;
// make sure this is in fact a pcode symbol
assert(FPcodeSym(*psym));
// Search backward for a symbol with the appropriate name and prefix. Try
// a maximum of two symbols; ignore section symbols. The compiler is
// required to generate Pcode entry points this way.
pStaticPcodeSym = psym - 1;
for (isym = 0; isym < 2; isym++) {
if ((pStaticPcodeSym-1)->NumberOfAuxSymbols == 1 &&
(pStaticPcodeSym-1)->StorageClass == IMAGE_SYM_CLASS_STATIC)
{
pStaticPcodeSym -= 2;
}
if (pStaticPcodeSym->StorageClass != IMAGE_SYM_CLASS_STATIC ||
pStaticPcodeSym->NumberOfAuxSymbols != 0)
{
FatalPcon(pcon, MACBADPCODEEP);
}
const char *szSym;
if (fPass1) {
szSym = SzNameSymPb(*pStaticPcodeSym, StringTable);
} else {
szSym = SzNameFixupSym(pimage, pStaticPcodeSym);
}
if (strncmp(szSym, szPrefix, cchPrefix) == 0) {
// Found it
return(pStaticPcodeSym);
}
pStaticPcodeSym--;
}
// Didn't find the Pcode variant ... this isn't supposed to happen.
FatalPcon(pcon, MACBADPCODEEP);
return(NULL);
}
// keep a list of weak externs
void
AddWeakExtToList (
IN PEXTERNAL pext,
IN PEXTERNAL pextWeakDefault
)
{
WEAK_EXTERN_LIST *pwel = pwelHead;
while (pwel) {
if (pwel->pext == pext) {
pwel->pextWeakDefault = pextWeakDefault;
return;
}
pwel = pwel->pwelNext;
}
pwel = (WEAK_EXTERN_LIST *)PvAlloc(sizeof(WEAK_EXTERN_LIST));
pwel->pext = pext;
pwel->pextWeakDefault = pextWeakDefault;
// attach it to list
pwel->pwelNext = pwelHead;
pwelHead = pwel;
}
// return the extern associated with the weak extern
PEXTERNAL
PextWeakDefaultFind (
IN PEXTERNAL pext
)
{
WEAK_EXTERN_LIST *pwel = pwelHead;
while (pwel) {
if (pwel->pext == pext) {
return pwel->pextWeakDefault;
}
pwel = pwel->pwelNext;
}
return NULL;
}
void
FreeWeakExtList (
IN VOID
)
{
WEAK_EXTERN_LIST *pwelNext;
while (pwelHead) {
pwelNext = pwelHead->pwelNext;
FreePv(pwelHead);
pwelHead = pwelNext;
}
pwelHead = NULL;
}