Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

717 lines
20 KiB

/* %W% %E% */
/*
* Copyright Microsoft Corporation, 1983-1987
*
* This Module contains Proprietary Information of Microsoft
* Corporation and should be treated as Confidential.
*/
/****************************************************************
* *
* LINKER INITIALIZATION *
* *
****************************************************************/
#include <minlit.h> /* Types and constants */
#include <bndtrn.h> /* More of the same */
#include <bndrel.h> /* More of the same */
#include <lnkio.h> /* Linker I/O definitions */
#include <newexe.h> /* DOS & 286 .EXE format definitions */
#if EXE386
#include <exe386.h> /* 386 .EXE format definitions */
#endif
#include <signal.h> /* Signal definitions */
#if QCLINK
#include <stdlib.h>
#endif
#include <lnkmsg.h> /* Error messages */
#if OSMSDOS AND NOT (WIN_NT OR DOSEXTENDER OR DOSX32) AND NOT WIN_3
#define INCL_BASE
#define INCL_DOSMISC
#include <os2.h> /* OS/2 system calls */
#if defined(M_I86LM)
#undef NEAR
#define NEAR
#endif
#endif
#include <extern.h> /* External declarations */
#include <impexp.h>
#include <direct.h>
#if defined(DOSX32) OR defined(WIN_NT)
extern char FAR * _stdcall GetCommandLineA(void);
#endif
/*
* FUNCTION PROTOTYPES
*/
LOCAL void NEAR InitLeadByte(void);
LOCAL void NEAR SetupEnv(void);
LOCAL int NEAR IsPrefix(BYTE *pszPrefix, BYTE *pszString);
#if TCE
extern SYMBOLUSELIST aEntryPoints; // List of program entry points
#endif
#if ECS
/*
* InitLeadByte
*
* Initialize lead byte table structures.
* Returns no meaningful value.
*/
LOCAL void NEAR InitLeadByte ()
{
struct lbrange
{
unsigned char low; /* minimum */
unsigned char high; /* maximum */
};
static struct lbrange lbtab[5] = { { 0, 0 } };
struct lbrange *ptab;
WORD i; /* index */
COUNTRYCODE cc; /* country code */
cc.country = cc.codepage = 0;
if (DosGetDBCSEv(sizeof(lbtab), &cc, (char FAR *)lbtab))
return;
// For each range, set corresponding entries in fLeadByte
for (ptab = lbtab; ptab->low || ptab->high; ptab++)
if (ptab->low >= 0x80)
for (i = ptab->low; i <= ptab->high; i++)
fLeadByte[i-0x80] = (FTYPE) TRUE;
// Mark inclusive range true
}
#endif /* ECS */
#if NOT (WIN_NT OR DOSX32)
/*** _setenvp - stub for C run-time
*
* Purpose:
* Call stub instead of real function, we don't want C run-time to
* setup enviroment.
*
* Input:
* None;
*
* Output:
* None;
*
* Exceptions:
* None.
*
* Notes:
* None.
*
*************************************************************************/
void cdecl _setenvp(void)
{
return;
}
/*** IsPrefix - self-explanatory
*
* Purpose:
* Check if one string is a prefix of another.
*
* Input:
* pszPrefix - pointer to prefix string
* pszString - the string
*
* Output:
* The function returns TRUE if the first string is a prefix of the
* second; otherwise it returns FALSE.
*
* Exceptions:
* None.
*
* Notes:
* None.
*
*************************************************************************/
LOCAL int NEAR IsPrefix(BYTE *pszPrefix, BYTE *pszString)
{
while(*pszPrefix) // While not at end of prefix
{
if (*pszPrefix != *pszString) return(FALSE);
// Return zero if mismatch
++pszPrefix; // Increment pointer
++pszString; // Increment pointer
}
return(TRUE); // We have a prefix
}
#endif
/*** SetupEnv - set up pointer to linker evironment variables
*
* Purpose:
* Every byte in the DGROUP is to valuable to waste it to hold
* information available elswere in the memory linker is not using
* C run-time GETENV function, which accesses copy of the entire
* environemt in the DGROUP placed there by the startup code.
* Insted this function scans enviroment and set up pointers to
* appropriate strings. Because initially enviroment is in the FAR
* memory no space in DGROUP is used.
*
* Input:
* No explicit parameters are passed.
*
* Output:
* Four global pointer set to appropriate enviroment strings
*
* lpszLink - the LINK
* lpszPath - the PATH
* lpszTMP - the TMP
* lpszLIB - the LIB
* lpszQH - the QH for QuickHelp
*
* Exceptions:
* None.
*
* Notes:
* None.
*
*************************************************************************/
LOCAL void NEAR SetupEnv(void)
{
#if WIN_NT OR DOSX32
#if C8_IDE
char * pIDE = getenv("_MSC_IDE_FLAGS");
if(pIDE)
{
if(strstr(pIDE, "FEEDBACK"))
{
fC8IDE = TRUE;
#if DEBUG_IDE
fprintf(stdout, "\r\nIDE ACTIVE - FEEDBACK is ON");
#endif
}
if(strstr(pIDE, "BATCH"))
{
// NOTE: The link response file will still be echoed in this case!
// NOTE: this is different than if you specify /BATCH on the
// NOTE: command line -- also, the banner is still displayed
// NOTE: this is intentional as the IDE wants to BATCH to cause
// NOTE: the linker not to prompt, but it does want the banner
// NOTE: and response file echoed unless /NOLOGO is also specified
// NOTE: see CAVIAR 2378 [rm]
fNoprompt = (FTYPE) TRUE;
fPauseRun = FALSE; /* Disable /PAUSE */
#if DEBUG_IDE
fprintf(stdout, "\r\nIDE ACTIVE - BATCH is ON");
#endif
}
if(strstr(pIDE, "NOLOGO"))
{
fNoBanner = (FTYPE) TRUE;
#if DEBUG_IDE
fprintf(stdout, "\r\nIDE ACTIVE - LOGO is OFF");
#endif
}
}
#if DEBUG_IDE
else
fprintf(stdout, "\r\nIDE NOT ACTIVE");
fflush(stdout);
#endif
#endif // C8_IDE
lpszPath = getenv("PATH");
lpszLink = getenv("LINK");
lpszTMP = getenv("TMP");
lpszLIB = getenv("LIB");
lpszQH = getenv("QH");
lpszHELPFILES = getenv("HELPFILES");
lpszCmdLine = GetCommandLineA();
while (*lpszCmdLine != ' ')
lpszCmdLine++;
#else
WORD selEnv;
WORD cmdOffset;
register WORD offMac;
char FAR *lpszEnv;
char FAR *lpch;
SBTYPE buf;
register WORD ich;
WORD fEOS;
#if QCLINK OR CPU8086 OR DOSEXTENDER
// Get the segment address of the environment block
// and set the command line offset to infinity. We
// stop scanning environment block at NULL string.
lpszEnv = (char FAR *)
(((long) _psp << 16)
+ 0x2c);
selEnv = *((WORD FAR *) lpszEnv);
lpszCmdLine = (char FAR *)(((long) _psp << 16) + 0x80);
lpszCmdLine[lpszCmdLine[0] + 1] = '\0';
lpszCmdLine++;
cmdOffset = 0xffff;
#else
if (DosGetEnv((unsigned FAR *) &selEnv, (unsigned FAR *) &cmdOffset))
return;
#endif
lpszEnv = (char FAR *)((long) selEnv << 16);
#if NOT (QCLINK OR CPU8086 OR DOSEXTENDER)
lpszCmdLine = lpszEnv + cmdOffset;
// Skip LINK
lpszCmdLine += _fstrlen(lpszCmdLine) + 1;
#endif
// Skip leading spaces in command line
while (*lpszCmdLine == ' ')
lpszCmdLine++;
lpch = lpszEnv;
for (offMac = 0; offMac < cmdOffset && *lpszEnv; )
{
// Copy the enviroment variable string into near buffer
ich = 0;
while (*lpch && ich < sizeof(buf) - 1)
buf[ich++] = *lpch++;
if (*lpch == '\0')
{
// Skip over terminating zero
lpch++;
fEOS = TRUE;
}
else
fEOS = FALSE;
buf[ich] = '\0';
// Check what it is and setup appropriate pointer
if (lpszPath == NULL && IsPrefix((BYTE *) "PATH=", buf))
lpszPath = lpszEnv + 5;
else if (lpszLink == NULL && IsPrefix((BYTE *) "LINK=", buf))
lpszLink = lpszEnv + 5;
else if (lpszTMP == NULL && IsPrefix((BYTE *) "TMP=", buf))
lpszTMP = lpszEnv + 4;
else if (lpszLIB == NULL && IsPrefix((BYTE *) "LIB=", buf))
lpszLIB = lpszEnv + 4;
else if (lpszQH == NULL && IsPrefix((BYTE *) "QH=", buf))
lpszQH = lpszEnv + 3;
else if (lpszHELPFILES == NULL && IsPrefix((BYTE *) "HELPFILES=", buf))
lpszHELPFILES = lpszEnv + 10;
// If everything setup don't bother to look father
if (lpszPath && lpszLink && lpszTMP && lpszLIB && lpszQH && lpszHELPFILES)
break;
// Update enviroment pointer and offset in enviroment segment
offMac += ich;
if (!fEOS)
{
// Oops ! - enviroment variable longer then buffer
// skip to its end
while (*lpch && offMac < cmdOffset)
{
lpch++;
offMac++;
}
// Skip over terminating zero
lpch++;
offMac++;
}
lpszEnv = lpch;
}
#endif
}
#if FALSE
/*** Dos3SetMaxFH - set max file handle count for DOS
*
* Purpose:
* Sets the maximum number of files that may be opened
* simultaneously using handles by the linker.
*
* Input:
* cFH - number of desired handles
*
* Output:
* No explicit value is returned.
*
* Exceptions:
* None.
*
* Notes:
* This function uses the int 21h function 67h which available on
* DOS 3.3 and higher. The function fails if the requested number of
* handles is greater then 20 and there is not sufficient free memory
* in the system to allocate a new block to hold the enlarged table.
*
* If the number of handles requested is larger the available
* entries in the system's global table for file handles (controlled
* by the FILES entry in CONFIG.SYS), no error is returned.
* However, a subsequent attempt to open a file or create a new
* file will fail if all entries in the system's global file table
* are in use, even if the requesting process has not used up all
* of its own handles
*
* We don't check for error, because we can't do much about it.
* Linker will try to run with what is available.
*
*************************************************************************/
LOCAL void NEAR Dos3SetMaxFH(WORD cFH)
{
if ((_osmajor >= 3) && (_osminor >= 30))
{
_asm
{
mov ax, 0x6700
mov bx, cFH
int 0x21
}
}
}
#endif
/****************************************************************
* *
* InitializeWorld: *
* *
* This function takes no arguments and returns no meaningful *
* value. It sets up virtual memory, the symbol table *
* Handlers, and it initializes segment structures. *
* *
****************************************************************/
void InitializeWorld(void)
{
#if OSMSDOS
BYTE buf[512]; /* Temporary buffer */
char FAR *lpch; /* Temporary pointer */
int i; /* Temporary index */
#endif
#if NOT (FIXEDSTACK OR CPU386)
InitStack(); /* Initialize stack */
#endif
#if OSMSDOS
DskCur = (BYTE) (_getdrive() - 1); /* Get current (default) disk drive */
#if FALSE
if(!isatty(fileno(stderr))) /* No prompts if output not console */
fNoprompt = TRUE;
#endif
#if CRLF
/* Default mode of stdout, stdin, stderr is text, change to binary. */
_setmode(fileno(stdout),O_BINARY);
if(stderr != stdout)
_setmode(fileno(stderr),O_BINARY);
_setmode(fileno(stdin),O_BINARY);
#endif
#endif
InitSym(); /* Initialize symbol table handler */
DeclareStdIds();
// Install CTRL-C handler
#if OSMSDOS AND NOT WIN_NT
signal(SIGINT, (void (__cdecl *)(int)) UserKill);
#endif /* OSMSDOS */
#if OSXENIX
if(signal(SIGINT,UserKill) == SIG_IGN) signal(SIGINT,SIG_IGN);
/* Trap user interrupts */
if(signal(SIGHUP,UserKill) == SIG_IGN) signal(SIGHUP,SIG_IGN);
/* Trap hangup signal */
if(signal(SIGTERM,UserKill) == SIG_IGN) signal(SIGTERM,SIG_IGN);
/* Trap software termination */
#endif
#if SYMDEB
InitDbRhte();
#endif
#if ECS
InitLeadByte(); /* Initialize lead byte table */
#endif
#if OSMSDOS
// Initialize LINK environment.
// Do it yourself to save the memory.
SetupEnv();
/* Process switches from LINK environment variable */
if (lpszLink != NULL)
{
lpch = lpszLink;
/* Skip leading whitespace. */
while(*lpch == ' ' || *lpch == '\t')
lpch++;
if(*lpch++ == CHSWITCH)
{
// If string begins with switchr
// Copy string to buf, removing whitespace
for (i = 1; *lpch && i < sizeof(buf); lpch++)
if (*lpch != ' ' && *lpch != '\t')
buf[i++] = *lpch;
buf[0] = (BYTE) (i - 1); /* Set the length of buf */
if(buf[0]) /* If any switches, process them */
BreakLine(buf,ProcFlag,CHSWITCH);
}
}
#endif
#if CPU286
if (_osmode == OS2_MODE)
{
DosSetMaxFH(128); /* This is the same as _NFILE in crt0dat.asm */
DosError(EXCEPTION_DISABLE);
}
#if FALSE
else
Dos3SetMaxFH(40);
#endif
#endif
#if FALSE AND CPU8086
Dos3SetMaxFH(40);
#endif
// Initialize import/export tables
InitByteArray(&ResidentName);
InitByteArray(&NonResidentName);
InitByteArray(&ImportedName);
ImportedName.byteMac++; // Ensure non-zero offsets to imported names
InitWordArray(&ModuleRefTable);
InitByteArray(&EntryTable);
#if TCE
aEntryPoints.cMaxEntries = 64;
aEntryPoints.pEntries = (RBTYPE*)GetMem(aEntryPoints.cMaxEntries * sizeof(RBTYPE*));
#endif
}
#if (OSXENIX OR OSMSDOS OR OSPCDOS) AND NOT WIN_NT
/****************************************************************
* *
* UserKill: *
* *
* Clean up if linker killed by user. *
* *
****************************************************************/
void cdecl UserKill()
{
signal(SIGINT, SIG_IGN); /* Disallow ctrl-c during handler */
CtrlC();
}
#endif
/*
* InitTabs:
*
* Initialize tables required in Pass 1.
*/
void InitTabs(void)
{
#if NOT FAR_SEG_TABLES
char *tabs; /* Pointer to table space */
unsigned cbtabs;
#endif
/* Initialize the following tables:
*
* NAME TYPE
* ---- ----
* mpsegraFirst RATYPE
* mpgsnfCod FTYPE
* mpgsndra RATYPE
* mpgsnrprop RBTYPE
* mplnamerhte RBTYPE
*/
#if FAR_SEG_TABLES
mplnamerhte = (RBTYPE FAR *) GetMem(lnameMax * sizeof(RBTYPE));
mpsegraFirst = (RATYPE FAR *) GetMem(gsnMax * sizeof(RATYPE));
mpgsnfCod = (FTYPE FAR *) mpsegraFirst; /* Use same space twice */
mpgsndra = (RATYPE FAR *) GetMem(gsnMax * sizeof(RATYPE));
mpgsnrprop = (RBTYPE FAR *) GetMem(gsnMax * sizeof(RBTYPE));
#else
mplnamerhte = (RBTYPE *) malloc(lnameMax * sizeof(RBTYPE));
if (mplnamerhte == NULL)
Fatal(ER_seglim);
memset(mplnamerhte, 0, lnameMax * sizeof(RATYPE));
cbtabs = gsnMax * (sizeof(RATYPE) + sizeof(RATYPE) + sizeof(RBTYPE));
if((tabs = malloc(cbtabs)) == NULL)
Fatal(ER_seglim);
memset(tabs,0,cbtabs); /* Clear everything */
mpsegraFirst = (RATYPE *) tabs; /* Initialize base */
mpgsnfCod = (FTYPE *) mpsegraFirst; /* Use same space twice */
mpgsndra = (RATYPE *) &mpsegraFirst[gsnMax];
mpgsnrprop = (RBTYPE *) &mpgsndra[gsnMax];
#endif
}
/*
* InitP2Tabs:
*
* Initialize tables not needed until Pass 2.
*/
void InitP2Tabs (void)
{
char FAR *tabs; /* Pointer to table space */
unsigned cbtabs; /* Size of table space */
unsigned TabSize;
TabSize = gsnMac + iovMac + 1;
/* Tables required regardless of exe format generated:
* mpsegsa SATYPE
* mpgsnseg SEGTYPE
*/
#if FAR_SEG_TABLES
cbtabs = 0;
mpsegsa = (SATYPE FAR *) GetMem(TabSize * sizeof(SATYPE));
mpgsnseg = (SEGTYPE FAR *) GetMem(TabSize * sizeof(SEGTYPE));
mpseggsn = (SNTYPE FAR *) GetMem(TabSize * sizeof(SNTYPE));
#else
cbtabs = TabSize * (sizeof(RATYPE) + sizeof(SATYPE));
#endif
/* Tables required according to exe format generated:
*
* DOS 3:
* mpsegcb[TabSize] long
* mpsegFlags[TabSize] FTYPE
* mpsegalign[TabSize] ALIGNTYPE
* mpsegiov[TabSize] IOVTYPE
* mpiovRlc[iovMac] RUNRLC
* Seg. exe:
* mpsacb[SAMAX] long
* mpsadraDP[SAMAX] long; for O68K
* mpsacbinit[SAMAX] long
* mpsaRlc[SAMAX] HASHRLC FAR *
* mpsaflags[SAMAX] WORD; DWORD for EXE386
* htsaraep[HEPLEN] EPTYPE FAR *
* X.out:
* mpsegcb[TabSize] long
* mpsegFlags[TabSize] FTYPE
* mpstsa[TabSize] SATYPE
*/
#if EXE386
if(fNewExe)
cbtabs += (SAMAX*(sizeof(long)+sizeof(long)+sizeof(DWORD)+
sizeof(DWORD))) + (HEPLEN * sizeof(WORD));
else
#else
if(fNewExe)
#if O68K
cbtabs += (SAMAX*(sizeof(long)+sizeof(long)+sizeof(long)+sizeof(WORD)+
sizeof(WORD))) + (HEPLEN * sizeof(WORD));
#else
cbtabs += (SAMAX*(sizeof(long)+sizeof(long)+sizeof(RLCHASH FAR *) +
sizeof(WORD))) + (HEPLEN * sizeof(EPTYPE FAR *));
#endif
else
#endif
#if OEXE
cbtabs += TabSize * (sizeof(long) + sizeof(FTYPE) + sizeof(ALIGNTYPE));
#else
cbtabs += TabSize * (sizeof(long) + sizeof(FTYPE) + sizeof(SATYPE));
#endif
cbtabs += sizeof(WORD);
tabs = GetMem(cbtabs);
#if NOT FAR_SEG_TABLES
mpgsnseg = (SEGTYPE *)tabs;
mpsegsa = (SATYPE *)&mpgsnseg[TabSize];
tabs = (char *)&mpsegsa[TabSize];
#endif
#if OSEGEXE
if(fNewExe)
{
mpsacb = (DWORD FAR *) tabs;
#if O68K
mpsadraDP = (long *)&mpsacb[SAMAX];
mpsacbinit = (long *)&mpsadraDP[SAMAX];
#else
mpsacbinit = (DWORD FAR *)&mpsacb[SAMAX];
#endif
#if EXE386
mpsacrlc = (DWORD *)&mpsacbinit[SAMAX];
mpsaflags = (DWORD *)&mpsacrlc[SAMAX];
#else
mpsaRlc = (RLCHASH FAR * FAR *) &mpsacbinit[SAMAX];
mpsaflags = (WORD FAR *) &mpsaRlc[SAMAX];
#endif
htsaraep = (EPTYPE FAR * FAR *)&mpsaflags[SAMAX];
}
else
#endif
{
#if ODOS3EXE OR OIAPX286
mpsegcb = (long FAR *) tabs;
mpsegFlags = (FTYPE FAR *)&mpsegcb[TabSize];
#if OEXE
mpsegalign = (ALIGNTYPE FAR *)&mpsegFlags[TabSize];
#if OVERLAYS
cbtabs = iovMac * sizeof(RUNRLC) + TabSize * sizeof(IOVTYPE) +
(sizeof(DWORD) - 1); // leave room to align mpiovRlc
mpsegiov = (IOVTYPE FAR*) GetMem(cbtabs);
// align mpiovRlc on a DWORD, the alignment needed by struct _RUNRLC
mpiovRlc = (RUNRLC FAR*) ( ( (__int64)&mpsegiov[TabSize] +
(sizeof(DWORD) - 1)
) & ~(sizeof(DWORD) - 1)
);
#endif
#endif
#if OIAPX286
mpstsa = (SATYPE *)&mpsegFlags[TabSize];
#endif
#endif /* ODOS3EXE OR OIAPX286 */
}
/* Attempt to allocate space for mpextprop. */
cbtabs = extMax * sizeof(RBTYPE);
mpextprop = (RBTYPE FAR *) GetMem(cbtabs);
}