Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

677 lines
17 KiB

/***********************************************************************
* Microsoft (R) 32-Bit Incremental Linker
*
* Copyright (C) Microsoft Corp 1992-1996. All rights reserved.
*
* File: order.cpp
*
* File Comments:
*
* Comdat ordering engine. This is used for working set tuning via
* -order from the command line.
*
***********************************************************************/
#include "link.h"
static BOOL fOrder = FALSE;
extern char *OrderFilename;
#define MAXLINELEN (2048+256)
#define UNORDERED 0
#define ORDERED 1
VOID
OrderInit(void)
/*++
Routine Description:
Initialize the order manager.
Return Value:
None.
--*/
{
fOrder = TRUE;
}
VOID
OrderClear(void)
/*++
Routine Description:
Clears the fOrder flag so that the -order option will be ignored. This was
added for the mac target. If -order is ever enable for the mac, make sure that
if pcode functions are ordered that their other two corresponding comdats are
ordered with them.
FYI: pcode functions when compiled /Gy produce three comdats in the following order:
1st) __pcd_tbl_foo: the function's call table
2nd) __nep_foo: the function's native entry point
3rd) __foo: the function's pcode entry point
The ordering of the above three comdats MUST be preserved.
--*/
{
fOrder = FALSE;
}
// VerboseOrder: prints to the /VERBOSE stream the names of all code comdats which weren't
// listed in the /ORDER file.
//
VOID
VerboseOrder(PIMAGE pimage)
{
BOOL fPrintedHeader = FALSE;
BOOL fSkipUnderscore;
PEXTERNAL pext;
switch (pimage->ImgFileHdr.Machine) {
case IMAGE_FILE_MACHINE_I386 :
case IMAGE_FILE_MACHINE_M68K :
case IMAGE_FILE_MACHINE_MPPC_601 :
fSkipUnderscore = TRUE;
break;
default :
fSkipUnderscore = FALSE;
break;
}
InitEnumerateExternals(pimage->pst);
while ((pext = PexternalEnumerateNext(pimage->pst)) != NULL) {
const char *szComdat;
if ((pext->Flags & EXTERN_DEFINED) == 0) {
continue;
}
if ((pext->Flags & (EXTERN_COMDAT | EXTERN_COMMON)) == 0) {
continue;
}
assert(pext->pcon != NULL);
if (pext->pcon->rva == ORDERED) {
continue; // this one was ordered
}
if (FetchContent(pext->pcon->flags) != IMAGE_SCN_CNT_CODE) {
// Only report code
continue;
}
if (!fPrintedHeader) {
Message(ORDERHEADER);
fputc('\n', stdout);
fPrintedHeader = TRUE;
}
szComdat = SzNamePext(pext, pimage->pst);
if (fSkipUnderscore && (szComdat[0] == '_')) {
szComdat++;
}
printf(" %s", szComdat);
if (pext->pcon->pmodBack != pmodLinkerDefined) {
char szBuf[_MAX_PATH * 2];
printf("\t\t; %s", SzComNamePMOD(PmodPCON(pext->pcon), szBuf));
}
fputc('\n', stdout);
}
if (fPrintedHeader) {
fputc('\n', stdout);
}
TerminateEnumerateExternals(pimage->pst);
}
VOID
OrderByGrp(PCON **prgpcon, DWORD *picon, DWORD *pccon, char *szName, PIMAGE pimage)
{
PGRP pgrpSrc;
PGRP pgrpDst;
ENM_SEC enmSec;
ENM_DST enmDst;
// Locate the GRP referenced in the order file.
pgrpSrc = NULL;
InitEnmSec(&enmSec, &pimage->secs);
while (FNextEnmSec(&enmSec)) {
pgrpSrc = PgrpFind(enmSec.psec, szName);
if (pgrpSrc != NULL) {
EndEnmSec(&enmSec);
break;
}
}
if (pgrpSrc == NULL) {
Warning(NULL, ORDERNOTCOMDAT, szName, NULL); // terse & appropriate message
return;
}
// Locate the GRP in the same section as pgrpSrc, which has the same name as the section.
pgrpDst = PgrpFind(pgrpSrc->psecBack, pgrpSrc->psecBack->szName);
if ((pgrpDst == NULL) || (pgrpSrc == pgrpDst)) {
Warning(NULL, ORDERNOTCOMDAT, szName, NULL); // terse & appropriate message
return;
}
InitEnmDst(&enmDst, pgrpSrc);
while (FNextEnmDst(&enmDst)) {
// Move a CON from pgrpSrc to pgrpDst. All we have to do is update the back-pointer, since:
// a. we are emptying out pgrpSrc and will NULL out the head of its CON list
// b. this CON will end up in the order array, one way or another (it might be there already)
// c. we are about to rebuild the linked list from scratch, for all CON's in the order array.
assert(pgrpSrc->ccon != 0);
pgrpSrc->ccon--;
pgrpDst->ccon++;
enmDst.pcon->pgrpBack = pgrpDst;
// If the CON has already been ordered into the array, leave it alone ... this allows mention by
// name to override mention by group (or module).
if (enmDst.pcon->rva != ORDERED) {
// Add the CON to the order array.
(*prgpcon)[(*picon)++] = enmDst.pcon;
enmDst.pcon->rva = ORDERED;
pgrpDst->fOrdered = TRUE;
// grow array if needed
if (*picon == *pccon) {
*pccon *= 2;
*prgpcon = (PPCON) PvRealloc(*prgpcon, *pccon * sizeof(PCON));
}
}
}
pgrpSrc->pconNext = pgrpSrc->pconLast = NULL;
pgrpSrc->ccon = 0;
}
DWORD
CconOrderFile(
PST pst,
PPCON *prgpcon,
PIMAGE pimage)
/*++
Routine Description:
Initialize working set tuning.
Arguments:
pst - external symbol table
*prgpcon - table of comdats contributions to order
Return Value:
None.
--*/
{
char *szToken;
FILE *pfile;
DWORD ccon;
DWORD icon;
BOOL fPrependUnderscore;
DWORD li;
assert(fOrder);
ccon = 64;
*prgpcon = (PPCON) PvAlloc(ccon * sizeof(CON));
szToken = (char *) PvAlloc(MAXLINELEN);
if (!(pfile = fopen(OrderFilename, "rt"))) {
Fatal(NULL, CANTOPENFILE, OrderFilename);
}
switch (pimage->ImgFileHdr.Machine) {
case IMAGE_FILE_MACHINE_I386 :
case IMAGE_FILE_MACHINE_M68K :
case IMAGE_FILE_MACHINE_MPPC_601 :
fPrependUnderscore = TRUE;
break;
default :
fPrependUnderscore = FALSE;
break;
}
li = 1;
icon = 0;
while (fgets(szToken+2, MAXLINELEN-1, pfile)) {
char *szName;
BOOL fOrderByModule;
BOOL fOrderByGrp;
BOOL fLFN; // LongFileName
char *pch;
char *pchEnd;
fLFN = FALSE;
szName = szToken+2;
// Skip leading white space.
while ((szName[0] == ' ') || (szName[0] == '\t')) {
szName++;
}
fOrderByModule = (szName[0] == '*');
fOrderByGrp = (szName[0] == '&');
if (fOrderByModule || fOrderByGrp) {
// Skip '*'
szName++;
// Skip leading white space.
// UNDONE: Leading white space is significant for Win32 long names
while ((szName[0] == ' ') || (szName[0] == '\t')) {
szName++;
}
if (*szName == '\"') {
fLFN = TRUE;
szName++;
assert (fOrderByModule);
}
}
// UNDONE: This needs to be DBCS enabled to handle filenames correctly
pchEnd = szName;
for (pch = szName; *pch != '\0'; pch++) {
if (fLFN && (*pch == '\"')) {
// Terminate at double quote if LongFileName
*pch = '\0';
break;
}
if ((*pch == '\n') || (*pch == '\r')) {
// Terminate at end of line
*pch = '\0';
break;
}
if ((*pch == ';') && !fOrderByModule) {
// Terminate at first semicolon
*pch = '\0';
break;
}
if ((*pch != ' ') && (*pch != '\t')) {
// Remember last non-white space character
pchEnd = pch + 1;
}
}
// Trim trailing white space
*pchEnd = '\0';
if (szName[0] != '\0') {
if (fOrderByGrp) {
OrderByGrp(prgpcon, &icon, &ccon, szName, pimage);
} else if (fOrderByModule) {
PMOD pmod;
ENM_SRC enmSrc;
// Order an object module
pmod = PmodFind(pimage->plibCmdLineObjs, szName, 0);
if (pmod == NULL) {
Warning(OrderFilename, MODULENOTFOUND, szName);
continue;
}
for (InitEnmSrc(&enmSrc, pmod); FNextEnmSrc(&enmSrc); ) {
#if 0
if ((enmSrc.pcon->flags & IMAGE_SCN_LNK_COMDAT) == 0) {
// Only order COMDATs
continue;
}
#endif
if (FetchContent(enmSrc.pcon->flags) != IMAGE_SCN_CNT_CODE) {
// Only order code
continue;
}
if (enmSrc.pcon->rva == ORDERED) {
// Previously specified
continue;
}
enmSrc.pcon->pgrpBack->fOrdered = TRUE;
enmSrc.pcon->rva = ORDERED; // Mark as a CON to order
(*prgpcon)[icon] = enmSrc.pcon;
icon++;
if (icon == ccon) {
ccon *= 2;
*prgpcon = (PPCON) PvRealloc(*prgpcon, ccon * sizeof(PCON));
}
}
} else {
PEXTERNAL pext;
// Order a COMDAT
// Do not prepend underscore if name begins with '?' or '@'
if (fPrependUnderscore && (szName[0] != '?') && (szName[0] != '@')) {
*--szName = '_';
}
pext = SearchExternSz(pst, szName);
#ifdef NT_BUILD
if ((pext == NULL) && !fPrependUnderscore) {
// UNDONE: This code should be removed when the NT build
// UNDONE: process is fixed to use architecture specific
// UNDONE: order files. For now, all platforms are linked
// UNDONE: with an X86 specific order file.
if (szName[0] != '?') {
char *pchAt;
if (szName[0] == '@') {
// This is probably a __fastcall function
szName++;
}
pchAt = strchr(szName, '@');
if (pchAt != NULL) {
// This is probably __fastcall or __stdcall
*pchAt = '\0';
}
}
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
*--szName = '.';
*--szName = '.';
}
pext = SearchExternSz(pst, szName);
}
#endif
if ((pext == NULL) || !(pext->Flags & EXTERN_DEFINED)) {
Warning(OrderFilename, COMDATDOESNOTEXIST, szName);
continue;
}
if ((pext->Flags & (EXTERN_COMDAT | EXTERN_COMMON)) == 0) {
// Don't warng for weak externs. The default defn does get
// ordered and the weak extern is pointing to it.
// This code is similar to the one that was added to 4199 linker
// to let Office folks order Pcode symbols for Word 6.1 (6.0.a)
if (fPowerMac && FPcodeSym(pext->ImageSymbol)) {
char *pcodeName;
int i;
pcodeName = (char *) PvAlloc(strlen(szName) + 10);
for (i = 0; i < 3; i++) {
if ( i == 0) {
strcpy(pcodeName, szPCODEPREFIX);
strcat(pcodeName, "_tbl");
} else if (i == 1) {
strcpy(pcodeName, szPCODENATIVEPREFIX);
} else {
strcpy(pcodeName, szPCODEFHPREFIX);
}
strcat(pcodeName, szName);
pext = SearchExternSz(pst, pcodeName);
if (pext) {
pext->pcon->pgrpBack->fOrdered = TRUE;
pext->pcon->rva = ORDERED; // Mark as a CON to order
(*prgpcon)[icon] = pext->pcon;
icon++;
if (icon == ccon) {
ccon *= 2;
*prgpcon = (PPCON) PvRealloc(*prgpcon, ccon * sizeof(PCON));
}
}
}
continue;
}
if ((pext->Flags & (EXTERN_WEAK | EXTERN_LAZY | EXTERN_ALIAS)) == 0) {
Warning(OrderFilename, ORDERNOTCOMDAT, szName);
}
continue;
}
assert(pext->pcon != NULL);
if ((pext->Flags & EXTERN_COMDAT) != 0) {
assert((pext->pcon->flags & IMAGE_SCN_LNK_COMDAT) != 0);
}
pext->pcon->pgrpBack->fOrdered = TRUE;
if (pext->pcon->rva == ORDERED) {
// This con was already ordered. Warn the user that we'll be using the
// last one seen
Warning(OrderFilename, DUPLICATEORDER, szName);
}
pext->pcon->rva = ORDERED; // Mark as a CON to order
(*prgpcon)[icon] = pext->pcon;
icon++;
if (icon == ccon) {
ccon *= 2;
*prgpcon = (PPCON) PvRealloc(*prgpcon, ccon * sizeof(PCON));
}
}
}
}
fclose(pfile);
FreePv(szToken);
return(icon);
}
void
OrderComdats(
PIMAGE pimage)
/*++
Routine Description:
Order comdats in contribution map.
Arguments:
pst - external symbol table
Return Value:
None.
--*/
{
PPCON rgpcon;
DWORD ccon;
ENM_SEC enm_sec;
PCON pcon;
if (Verbose) {
fputc('\n', stdout);
Message(STARTORDER);
}
// count the number of entries in the order file and make the rva field
// !0 in the CON of contributions represented in the order file
ccon = CconOrderFile(pimage->pst, &rgpcon, pimage);
// Unlink the ordered contributions from the list of CONs
InitEnmSec(&enm_sec, &pimage->secs);
while (FNextEnmSec(&enm_sec)) {
PSEC psec;
ENM_GRP enm_grp;
psec = enm_sec.psec;
assert(psec);
InitEnmGrp(&enm_grp, psec);
while (FNextEnmGrp(&enm_grp)) {
PGRP pgrp;
PCON pconLast;
PCON *ppconLast;
pgrp = enm_grp.pgrp;
assert(pgrp);
if (!pgrp->fOrdered) {
// There are no CONs from this group in the order file
continue;
}
pconLast = NULL;
ppconLast = &pgrp->pconNext;
for (pcon = pgrp->pconNext; pcon; pcon = pcon->pconNext) {
if (pcon->rva == 0) {
// This CON is not ordered. Link into new list.
pconLast = pcon;
*ppconLast = pcon;
ppconLast = &pcon->pconNext;
}
}
*ppconLast = NULL;
pgrp->pconLast = pconLast;
}
}
if (Verbose) {
// Output some info to the /VERBOSE stream about
// what functions are still available to be ordered.
VerboseOrder(pimage);
}
// Link ordered CONs to the head of each GRPs CON list in reverse order
while (ccon-- > 0) {
pcon = rgpcon[ccon];
assert(pcon->pgrpBack->fOrdered);
if (pcon->rva == 0) {
// Some CON was referenced twice in the order file, probably
// because multiple externals were defined in the same CON
// (i.e. not a comdat), or possibly because there was a
// name in the order file twice. Might want to print some
// warning here?
continue;
}
pcon->rva = 0; // just to be tidy
pcon->pconNext = pcon->pgrpBack->pconNext;
pcon->pgrpBack->pconNext = pcon;
if (pcon->pgrpBack->pconLast == NULL) {
pcon->pgrpBack->pconLast = pcon;
}
}
FreePv(rgpcon);
if (Verbose) {
Message(ENDORDER);
}
}
VOID
OrderSemantics(
PIMAGE pimage)
/*++
Routine Description:
Apply comdat ordering semantics.
Arguments:
pst - external symbol table
Return Value:
None.
--*/
{
if (fOrder) {
OrderComdats(pimage);
}
}