mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6155 lines
162 KiB
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;
|
|
}
|