windows-nt/Source/XPSP1/NT/sdktools/link16/newtrn.c
2020-09-26 16:20:57 +08:00

2521 lines
72 KiB
C

/* SCCSID = @(#)newtrn.c 4.10 86/10/08 */
/*
* Copyright Microsoft Corporation, 1983-1987
*
* This Module contains Proprietary Information of Microsoft
* Corporation and should be treated as Confidential.
*/
/****************************************************************
* *
* NEWTRN.C *
* *
* Main function of the linker. *
* *
****************************************************************/
#include <minlit.h> /* Types, constants, macros */
#if USE_REAL AND (NOT defined( _WIN32 ))
#define i386
#endif
#include <bndtrn.h> /* Types and constants */
#include <bndrel.h> /* More types and constants */
#include <lnkio.h> /* Linker I/O definitions */
#include <lnkmsg.h> /* Error messages */
#include <extern.h> /* External declarations */
#include <nmsg.h> /* Near message strings */
#include <newexe.h>
#include <sys\types.h>
#if NOT CLIBSTD
#include <fcntl.h>
#endif
#include <direct.h>
#if EXE386
#include <exe386.h>
#endif
#if OSEGEXE AND CPU286
#define INCL_DOSSESMGR
#define INCL_DOSERRORS
#include <os2.h>
#if defined(M_I86LM)
#undef NEAR
#define NEAR
#endif
#endif
#include <process.h>
#include <malloc.h>
#include <undname.h>
#if WIN_NT
#include <except.h>
#endif
#if (WIN_3 OR USE_REAL)
#if defined( _WIN32 )
#undef NEAR
#undef FAR
#undef PASCAL
#endif
#include <windows.h>
#endif
#define _32k 0x8000
LOCAL FTYPE RunFileOpen; /* Executable-file-open flag */
LOCAL int ifhLast; /* Last input file */
#if LNKPROF
extern FTYPE fP1stop; /* Stop after Pass 1 */
#endif
#if NEWIO
#include <errno.h> /* System level error codes */
#endif
/*
* LOCAL FUNCTION PROTOTYPES
*/
LOCAL void NEAR PrintStats(void);
LOCAL void PrintAnUndef(APROPNAMEPTR prop,
RBTYPE rhte,
RBTYPE rprop,
WORD fNewHte);
LOCAL void NEAR InitFP(void);
LOCAL void NEAR InitFpSym(BYTE *sb, BYTE flags);
LOCAL void NEAR InterPass(void);
LOCAL void NEAR InitAfterCmd(void);
#if EXE386
LOCAL void NEAR ChkSize386(void);
#endif
LOCAL void NEAR CleanUp(void);
LOCAL void NEAR OutRunFile(BYTE *sbRun);
LOCAL void NEAR SpawnOther(BYTE *sbRun, BYTE *szMyself);
#if CVPACK_MONDO
extern int cvpack_main(int, char **);
#endif // CVPACK_MONDO
#ifdef PENTER_PROFILE
void saveEntries();
#endif
#if TIMINGS
#include <sys\types.h>
#include <sys\timeb.h>
struct _timeb time_start;
struct _timeb time_end;
int fShowTiming;
#endif // TIMINGS
#if DEBUG_HEAP_ALLOCS
#define D_SIZE 5 // Number of test bytes on each side of the allocated buffer
#define FILL_CHAR 1 // Character to fill the test areas
#define P_SIZE 5000 // Size of an array of 'malloc'ated pointers
struct Entry {
BYTE FAR * ptr;
int size;
};
struct Entry Pointers[P_SIZE];
int indexMac = 0;
// Check a block from the Pointers table
int Ckb ( int index )
{
BYTE * pBuf;
int size,i;
int ret = 1;
if(index > P_SIZE)
{
fprintf(stdout, "INDEX TOO LARGE %d ", index);
return 0;
}
if(!Pointers[index].ptr) // a freed entry
return 1;
pBuf = Pointers[index].ptr-D_SIZE;
size = Pointers[index].size;
for( i=0; i<D_SIZE; i++ )
{
if(pBuf[i] != FILL_CHAR)
{
fprintf(stdout, "\r\nFront block memory error; idx %d at %d, %x != %x ",
index, i, pBuf[i], FILL_CHAR);
ret = 0;
}
}
pBuf += D_SIZE + size;
for( i=0; i<D_SIZE; i++ )
{
if(pBuf[i] != FILL_CHAR)
{
fprintf(stdout, "\r\nMemory tail error; idx %d at %d, %x != %x",
index, i, pBuf[i], FILL_CHAR);
ret = 0;
}
}
fflush(stdout);
return ret;
}
// Ckeck all the memory blocks allocated so far
int CheckAll(void)
{
int i;
for(i=0; i<indexMac; i++)
{
if(!Ckb(i))
return 0;
}
return 1;
}
#pragma intrinsic(memset)
BYTE FAR *GETMEM(unsigned size, BYTE* pFile, int Line)
{
BYTE FAR *p;
BYTE FAR *pBuf;
fprintf(stdout,"\r\nGETMEM : size %d bytes, idx %d, file %s, line %d ",
size, indexMac, pFile, Line);
if(!CheckAll()) // check all so far allocated blocks first
exit(2);
pBuf = (BYTE FAR *) malloc(size + 2*D_SIZE);
if(pBuf)
{
p = pBuf + D_SIZE;
memset(pBuf, FILL_CHAR, size + 2*D_SIZE);
}
else
Fatal(ER_memovf);
memset(p, 0, size);
Pointers[indexMac].ptr = p;
Pointers[indexMac++].size = size;
fprintf(stdout, " returns %x ", p);
fflush(stdout);
return(p);
}
#pragma function(memset)
void FreeMem( void * p )
{
int i;
unsigned size;
BYTE FAR * pBuf = (BYTE*)p-D_SIZE;
fprintf(stdout, "\r\nFreeMem : %x ", p);
for( i=0; i<= indexMac; i++)
{
if(Pointers[i].ptr == p)
{
size = Pointers[i].size;
fprintf(stdout, "size %d, idx %d ", size, i);
break;
}
}
if (i> indexMac)
{
fprintf(stdout, "Pointer UNKNOWN ");
return;
}
if (!Ckb(i))
exit(1);
fprintf(stdout, " freeing %x ", (BYTE*)p-D_SIZE);
fflush(stdout);
free((BYTE*)p-D_SIZE);
fprintf(stdout, ". ");
fflush(stdout);
Pointers[i].ptr = NULL;
}
void *REALLOC_ (void * memblock, size_t nsize, char* pFile, int Line)
{
int i;
unsigned size;
BYTE * ret;
BYTE FAR * pBuf = (BYTE FAR* )memblock-D_SIZE;
fprintf(stdout, "\r\nREALLOC %x, new size %d, file %s, line %d ",
memblock, nsize, pFile, Line);
if(!CheckAll())
exit(2);
if(!memblock)
exit(2);
for( i=0; i<= indexMac; i++)
{
if(Pointers[i].ptr == memblock)
{
size = Pointers[i].size;
fprintf(stdout, "old size %d, idx %d ", size, i);
if(Ckb(i))
fprintf(stdout, " Chk OK ");
break;
}
}
if (i> indexMac)
{
fprintf(stdout, "Pointer UNKNOWN ");
memblock = realloc( memblock, nsize );
if (!memblock)
Fatal(ER_memovf);
return (void*)memblock;
}
else
{
fflush(stdout);
fprintf(stdout, "\r\nreallocing %x ", pBuf);
fflush(stdout);
pBuf = malloc(nsize + 2*D_SIZE);
if (!pBuf) Fatal(ER_memovf);
memset(pBuf, FILL_CHAR, nsize+2*D_SIZE);
memcpy(pBuf+D_SIZE, memblock, size);
free((BYTE*)memblock-D_SIZE);
fprintf(stdout, " new addr %x ", pBuf);
fflush(stdout);
Pointers[i].size = nsize;
Pointers[i].ptr = pBuf+D_SIZE;
if(Ckb(i))
fprintf(stdout, " Chk2 OK ");
else
exit(2);
return pBuf+D_SIZE;
}
}
#else // IF !DEBUG_HEAP_ALLOCS
/*** GetMem - memory allocator
*
* Purpose:
* Allocate memory block and zero-out it. Report problems.
*
* Input:
* - size - memory block size in bytes.
*
* Output:
* If sucessfull function returns pointer to the allocated memory,
* otherwise function doesnt return.
*
* Exceptions:
* No more memory - fatal error - abort
*
* Notes:
* None.
*
*************************************************************************/
#pragma intrinsic(memset)
BYTE FAR *GetMem(unsigned size)
{
BYTE FAR *p;
p = (BYTE FAR *) FMALLOC(size);
if (p == NULL)
Fatal(ER_memovf);
FMEMSET(p, 0, size);
return(p);
}
#pragma function(memset)
#endif // !DEBUG_HEAP_ALLOCS
/*** DeclareStdIds - declare standard identifiers
*
* Purpose:
* Introduce to linker's symbol table standard identifiers
*
* Input:
* None.
*
* Output:
* No explicit value is returned. Symbol table is initialized.
*
* Exceptions:
* None.
*
* Notes:
* None.
*
*************************************************************************/
void DeclareStdIds(void)
{
APROPGROUPPTR papropGroup;
// Definition of DGROUP
papropGroup = (APROPGROUPPTR ) PropSymLookup((BYTE *) "\006DGROUP", ATTRGRP, TRUE);
papropGroup->ag_ggr = ggrMac;
// In case we won't see a DGROUP definition
mpggrrhte[ggrMac] = vrhte;
ggrDGroup = ggrMac++;
// Definition of class "CODE"
PropSymLookup((BYTE *) "\004CODE", ATTRNIL, TRUE);
/* Create hash table entry */
vrhteCODEClass = vrhte; /* Save virtual hash table address */
// Definition of special classes
PropSymLookup((BYTE *) "\007BEGDATA", ATTRNIL, TRUE);
rhteBegdata = vrhte;
PropSymLookup((BYTE *) "\003BSS", ATTRNIL, TRUE);
rhteBss = vrhte;
PropSymLookup((BYTE *) "\005STACK", ATTRNIL, TRUE);
rhteStack = vrhte;
}
#if FDEBUG
/*
* Print statistics to list file or console.
*/
LOCAL void NEAR PrintStats()
{
if (fLstFileOpen) /* Send to list file if any */
bsErr = bsLst;
// Print statistics
FmtPrint(GetMsg(STAT_segs), gsnMac - 1);
FmtPrint(GetMsg(STAT_groups), ggrMac - 1);
FmtPrint(GetMsg(STAT_bytes),
#if NEWSYM
(long) cbSymtab);
#else
(long) rbMacSyms << SYMSCALE);
#endif
#if OVERLAYS
if (fOverlays)
FmtPrint(GetMsg(STAT_ovls), iovMac);
#endif
bsErr = stderr; /* Reset */
}
#endif /* FDEBUG */
/****************************************************************
* *
* CleanUp: *
* *
* This function cleans up after the rest of the linker. *
* *
****************************************************************/
LOCAL void NEAR CleanUp(void)
{
SBTYPE buf;
if (bsRunfile != NULL) /* If run file open, close it */
CloseFile (bsRunfile);
if(vgsnLineNosPrev && fLstFileOpen) NEWLINE(bsLst); /* Write newline */
#if CMDMSDOS AND NOT WIN_3
if (
#if QCLINK
!fZ1 &&
#endif
cErrors) /* If there were non-fatal errors */
FmtPrint(strcpy(buf, GetMsg((MSGTYPE)(cErrors > 1 ? P_errors : P_1error))),
cErrors);
#endif
}
#if NEWIO
/* #pragma loop_opt(on) */
/*
* FreeHandle : Free a file handle by closing an open file
*
* In pass 1, close the currently open file. In pass 2, close
* an open library handle.
* Mark the appropriate record fields 0 to indicate unopened.
*/
void FreeHandle ()
{
APROPFILEPTR apropFile; /* Pointer to file */
RBTYPE vindx; /* Virtual temp. pointer */
int FileHandle;
int CurrentFileHandle;
FTYPE fLibFile;
int count;
CurrentFileHandle = fileno(bsInput);
/* Loop throught all open files and close one, that is different from */
/* currently open file */
vindx = rprop1stOpenFile;
count = 0;
do
{
apropFile = (APROPFILEPTR) FetchSym(vindx,TRUE);
/* Fetch file property cell from VM */
fLibFile = (FTYPE) (apropFile->af_ifh != FHNIL);
/* Check if this is library file */
if (fLibFile) /* Get file handle */
FileHandle = mpifhfh[apropFile->af_ifh];
else
FileHandle = apropFile->af_fh;
if (FileHandle &&
FileHandle != CurrentFileHandle &&
FileHandle != vmfd)
{ /* File can be closed */
_close(FileHandle);
count++;
if (fLibFile) /* Mark data structures */
mpifhfh[apropFile->af_ifh] = 0;
else
apropFile->af_fh = 0;
if (count == 2)
{
rprop1stOpenFile = (apropFile->af_FNxt == RHTENIL) ?
r1stFile : apropFile->af_FNxt;
/* Set new first open file pointer */
/* If end of file list goto list begin */
/* Becouse of bug in bind API emulation */
/* we have to free to handles at any time */
break; /* Job done */
}
}
vindx = (apropFile->af_FNxt == RHTENIL) ? r1stFile : apropFile->af_FNxt;
} while (vindx != rprop1stOpenFile);
}
/* #pragma loop_opt(off) */
/*
* SmartOpen : open a file, closing another file if necessary
*
* Open the given file for binary reading, plus sharing mode
* "deny write" if library file. If no more handles, free a
* handle and try again. Update mpifhfh[].
*
* PARAMETERS:
* sbInput Null-terminated string, name of file
* ifh File index (FHNIL if not a library)
*
* RETURNS
* File handle of opened file or -1.
*
* SIDE EFFECTS
* Sets mpifhfh[ifh] to file handle if successful.
*/
int NEAR SmartOpen (char *sbInput, int ifh)
{
int fh; /* File handle */
FTYPE fLib; /* True if library */
int secondtry = 0; /* True if on second try */
// Determine whether library file or not.
fLib = (FTYPE) (ifh != FHNIL);
secondtry = 0;
// Do at most twice
for(;;)
{
if (fLib)
fh = _sopen(sbInput, O_BINARY|O_RDONLY, SH_DENYWR);
else
fh = _open(sbInput, O_BINARY|O_RDONLY);
// If open succeeds or we've tried twice exit the loop.
if (fh != -1 || secondtry)
break;
// Prepare for second try: free a file handle
FreeHandle();
secondtry = 1;
}
// If library file and open succeeded, update mpifhfh[].
if (fLib && fh != -1)
mpifhfh[ifh] = (char) fh;
return(fh);
}
#endif /* NEWIO */
/*** SearchPathLink - self-expalnatory
*
* Purpose:
* Search given path for given file and open file if found.
*
* Input:
* lpszPath - path to search
* pszFile - file to search for
* ifh - file handle index for libraries
* fStripPath - TRUE if original path specification
* can be ignored
*
* Output:
* Returns file handle if file was found.
*
* Exceptions:
* None.
*
* Notes:
* None.
*
*************************************************************************/
#pragma check_stack(on)
int NEAR SearchPathLink(char FAR *lpszPath, char *pszFile,
int ifh, WORD fStripPath)
{
char oldDrive[_MAX_DRIVE];
char oldDir[_MAX_DIR];
char oldName[_MAX_FNAME];
char oldExt[_MAX_EXT];
char newDir[_MAX_DIR];
char fullPath[_MAX_PATH];
int fh;
char FAR *lpch;
char *pch;
/* Decompose pszFile into four components */
_splitpath(pszFile, oldDrive, oldDir, oldName, oldExt);
// Don't search path if the input file has absolute or
// relative path and you are not allowed to ignore it
if (!fStripPath && (oldDrive[0] != '\0' || oldDir[0] != '\0'))
return(-1);
/* Loop through environment value */
lpch = lpszPath;
pch = newDir;
do
{
if (*lpch == ';' || *lpch == '\0')
{ /* If end of path specification */
if (pch > newDir)
{ /* If specification not empty */
if (!fPathChr(pch[-1]) && pch[-1] != ':')
*pch++ = CHPATH; /* Add path char if none */
*pch = '\0';
_makepath(fullPath, NULL, newDir, oldName, oldExt);
fh = SmartOpen(fullPath, ifh);
if (fh > 0)
return(fh); /* File found - return file handle */
pch = newDir; /* Reset pointer */
}
}
else
*pch++ = *lpch; /* Else copy character to path */
}
while(*lpch++ != '\0' && pch < &newDir[_MAX_DIR - 1]);
/* Loop until end of string */
return(-1);
}
#pragma check_stack(off)
/****************************************************************
* *
* DrivePass: *
* *
* This function applies either the pass 1 or the pass 2 *
* object module processor to all the objects being linked *
* together. *
* *
****************************************************************/
void NEAR DrivePass(void (NEAR *pProcessPass)(void))
{
GRTYPE grggr[GRMAX]; /* f(local grpnum) = global grpnum */
SNTYPE sngsn[SNMAX]; /* f(local segnum) = global segnum */
AHTEPTR ahte; /* Pointer to hash table entry */
APROPFILEPTR apropFile; /* Pointer to file entry */
int ifh; /* File handle index */
RBTYPE rbFileNext; /* Ptr to prop list of next file */
long lfa; /* File offset */
WORD i;
BYTE *psbName;
#if NEWSYM
BYTE *sbInput;
#else
SBTYPE sbInput; /* Input file name */
#endif
#if OSMSDOS
BYTE b; /* A byte */
#endif
#if NEWIO
int fh; /* File handle */
#endif
fDrivePass = (FTYPE) TRUE; /* Executing DrivePass */
mpgrggr = grggr; /* Initialize pointer */
mpsngsn = sngsn; /* Initialize pointer */
rbFileNext = rprop1stFile; /* Next file to look at is first */
while(rbFileNext) /* Loop to process objects */
{
vrpropFile = rbFileNext; /* Make next file the current file */
apropFile = (APROPFILEPTR ) FetchSym(vrpropFile,FALSE);
/* Fetch table entry from VM */
#if ILINK
if (fIncremental)
imodFile = apropFile->af_imod;
#endif
rbFileNext = apropFile->af_FNxt;/* Get pointer to next file */
ifh = apropFile->af_ifh; /* Get the file handle index */
fLibraryFile = (FTYPE) (ifh != FHNIL);
/* Set library flag */
#if NEWIO
if(fLibraryFile)
fh = mpifhfh[ifh];
else
fh = (int) apropFile->af_fh;
#endif
if(!vfPass1)
vfNewOMF = (FTYPE) ((apropFile->af_flags & FNEWOMF) != 0);
lfa = apropFile->af_lfa; /* Get file offset */
/* "Get hte (name) of file" */
while(apropFile->af_attr != ATTRNIL)
{ /* While haven't found nil attr */
vrhteFile = apropFile->af_next;
/* Try next entry in list */
apropFile = (APROPFILEPTR ) FetchSym(vrhteFile,FALSE);
/* Fetch it from VM */
}
DEBUGVALUE(vrhteFile); /* Debug info */
ahte = (AHTEPTR ) apropFile; /* Save pointer to hash tab entry */
#if CMDMSDOS
/* Library file with offset 0 means process all the modules
* the library. This is done on pass 1; in pass 2 they are
* inserted into the file list.
*/
if(fLibraryFile && lfa == 0 && vfPass1)
{
psbName = GetFarSb(ahte->cch);
#if WIN_3
StatMsgWin("%s\r\n", psbName+1);
#endif
#if C8_IDE
if(fC8IDE)
{
sprintf(msgBuf, "@I4%s\r\n", psbName+1);
_write(fileno(stderr), msgBuf, strlen(msgBuf));
}
#endif
GetLibAll(psbName);
continue;
}
#endif
/* If new object file, or pass2 and new library, there's a
* new file to open.
*/
if(!fLibraryFile || (!fLibPass && ifhLast != ifh))
{
#if NOT NEWIO
if(!fLibPass && ifhLast != FHNIL) fclose(bsInput);
/* Close previous lib. on pass two */
#endif
for(;;) /* Loop to get input file and */
{ /* allow user to change diskette */
#if NEWSYM
sbInput = GetFarSb(ahte->cch);
#else
memcpy(sbInput,1 + GetFarSb(ahte->cch),B2W(ahte->cch[0]));
/* Copy name to buffer */
sbInput[B2W(ahte->cch[0])] = '\0';
/* Null-terminate file name */
#endif
#if WIN_3
StatMsgWin("%s\r\n", sbInput+1);
#endif
#if C8_IDE
if(fC8IDE)
{
sprintf(msgBuf, "@I4%s\r\n", sbInput+1);
_write(fileno(stderr), msgBuf, strlen(msgBuf));
}
#endif
#if NEWIO
if(!fh)
fh = SmartOpen(&sbInput[1],ifh);
if(fh > 0)
break;
#if OSMSDOS
else if (lpszLIB != NULL)
{ /* If variable set */
fh = SearchPathLink(lpszLIB, &sbInput[1], ifh, FALSE);
if(fh > 0)
break; /* File found, breake WHILE loop */
}
#endif
#else
if((bsInput = fopen(sbInput,RDBIN)) != NULL)
/* If no error opening input file */
break; /* Exit loop */
#endif /* NEWIO */
#if OSMSDOS
if (ahte->cch[2] == ':') b = (char) (ahte->cch[1] - 'A');
/* If disk specified, grab it */
else b = DskCur; /* Else use current drive */
#endif
fDrivePass = FALSE;
#if OSMSDOS
/* "If we are changing the listfile device or
* the VM.TMP device or if the device is not
* changeable, then exit."
*/
if((fLstFileOpen && b == chListFile) ||
(!fScrClosed && b == DskCur) || !FCHGDSK(b) ||
fNoprompt)
#endif
Fatal(ER_opnobj,&sbInput[1]);
#if OSMSDOS
if(!(*pfPrompt)(NULL,ER_fileopn,(int) (INT_PTR)(sbInput+1),P_ChangeDiskette,
b + 'A'))
Fatal(0);
#endif
#if NEWIO
fh = 0;
#endif
fDrivePass = (FTYPE) TRUE;
#if OSXENIX
break; /* Make sure we exit the loop */
#endif
}
if(fh > 0)
{
fflush(bsInput);
bsInput->_file = (char) fh;
bsInput->_flag &= ~_IOEOF;
}
}
/* If previous module was in same library, do relative seek
* else do absolute seek.
* Can't do it with Xenix libraries unless __.SYMDEF is loaded
* in memory.
*/
#if LIBMSDOS
if(fLibraryFile && ifh == ifhLast)
{
if (lfa-lfaLast > 0)
fseek(bsInput,lfa - lfaLast,1);
else
fseek(bsInput,lfa,0);
}
else
#endif
if(fLibraryFile || !vfPass1)
fseek(bsInput,lfa,0); /* Seek to desired offset */
lfaLast = lfa; /* Update current file position */
(*pProcessPass)(); /* Call ProcP1 or ProcP2 */
ifhLast = ifh; /* Save this file handle */
if(!fLibraryFile) /* If not a library */
{
#if NEWIO
apropFile = (APROPFILEPTR) FetchSym(vrpropFile,TRUE);
if(vfPass1)
apropFile->af_fh = fileno(bsInput);
else
{
_close(fileno(bsInput));
apropFile->af_fh = 0;
}
#else
fclose(bsInput); /* Close input file */
#endif
}
#if NEWIO
rbFilePrev = vrpropFile;
#endif
}
#if NEWIO
if(!vfPass1) /* Free up file stream on pass two */
#else
if(ifh != FHNIL && !vfPass1) // Close libraries on pass two
#endif
{
for (i = 0; i < ifhLibMac; i++)
{
if (mpifhfh[i])
{
_close(mpifhfh[i]);
mpifhfh[i] = 0;
}
}
}
fDrivePass = FALSE; /* No longer executing DrivePass */
}
/****************************************************************
* *
* PrintAnUndef: *
* *
* This function will print the name of an undefined symbol *
* and the name(s) of the module(s) in which it is referenced. *
* This routine is passed as an argument to EnSyms(). *
* *
****************************************************************/
LOCAL void PrintAnUndef(prop,rhte,rprop,fNewHte)
APROPNAMEPTR prop; /* Pointer to undef prop cell */
RBTYPE rprop; /* Virt addr of prop cell */
RBTYPE rhte; /* Virt addr of hash tab ent */
WORD fNewHte; /* True if name has been written */
{
APROPUNDEFPTR propUndef;
AHTEPTR hte; /* Pointer to hash table entry */
WORD x;
MSGTYPE errKind;
PLTYPE FAR * entry;
char *puname;
char *substitute;
SBTYPE testName;
SBTYPE undecorUndef;
SBTYPE undecorSubst;
propUndef = (APROPUNDEFPTR) prop;
if (((propUndef->au_flags & WEAKEXT) && !(propUndef->au_flags & UNDECIDED)) ||
!propUndef->u.au_rFil)
return; // Don't print "weak" externs or
// undefined exports
hte = (AHTEPTR ) FetchSym(rhte,FALSE);
/* Fetch symbol from hash table */
puname = GetFarSb(hte->cch);
substitute = NULL;
if (propUndef->au_flags & SUBSTITUTE)
{
substitute = puname;
puname = GetPropName(FetchSym(propUndef->au_Default, FALSE));
}
++cErrors; /* Increment error count */
hte = (AHTEPTR ) FetchSym(rhte,FALSE);
/* Fetch symbol from hash table */
errKind = ER_UnresExtern;
#if WIN_3
fSeverity = SEV_ERROR;
#endif
// Check here for calling convention mismatch
if (puname[1] == '@' || puname[1] == '_')
{
strcpy(testName, puname);
if (testName[1] == '@')
testName[1] = '_';
else
testName[1] = '@';
// Check for fast-call/C-call mismatch
if (PropSymLookup(testName, ATTRPNM, FALSE) != PROPNIL)
errKind = ER_callmis;
else
{
// Check for Pascal/fast-call or C-call mismatch
for (x = 1; x < testName[0]; x++)
testName[x] = (BYTE) toupper(testName[x + 1]);
testName[0]--;
if (PropSymLookup(testName, ATTRPNM, FALSE) != PROPNIL)
errKind = ER_callmis;
}
}
// Undecorate names if necessary
if (puname[1] == '?')
{
UndecorateSb(puname, undecorUndef, sizeof(undecorUndef));
puname = undecorUndef;
}
if (substitute && substitute[1] == '?')
{
UndecorateSb(substitute, undecorSubst, sizeof(undecorSubst));
substitute = undecorSubst;
}
// Walk the list of file references to this symbol
entry = propUndef->u.au_rFil;
vrpropFile = 0;
do
{
if (vrpropFile != entry->pl_rprop)
vrpropFile = entry->pl_rprop;/* Set the file pointer */
else
{
entry = entry->pl_next; /* Advance the list pointer */
continue;
}
if(fLstFileOpen && bsLst != stdout)
{ /* If listing but not to console */
#if QCLINK
if (fZ1)
{
fZ1 = FALSE; // Restore normal linker print function
OutFileCur(bsLst); // Output file name
fZ1 = (FTYPE) TRUE; // Restore QC call-back
}
else
#endif
{
#if WIN_3
APROPFILEPTR apropFile; /* Pointer to file property cell */
AHTEPTR ahte; /* Pointer symbol name */
SBTYPE sb; /* String buffer */
int n; /* String length counter */
apropFile = (APROPFILEPTR ) FetchSym(vrpropFile,FALSE);
ahte = GetHte(vrpropFile);
for(n = B2W(ahte->cch[0]), sb[n+1] = 0; n >= 0; sb[n] = ahte->cch[n], --n);
fprintf(bsLst, sb+1);
#else
OutFileCur(bsLst); /* Output file name */
#endif
}
}
OutFileCur(stderr); /* Output file name */
if(fLstFileOpen && bsLst != stdout)
{ /* If listing but not to console */
#if MSGMOD
fprintf(bsLst, " : %s %c%04d: ",
__NMSG_TEXT(N_error), 'L', ER_UnresExtern);
fprintf(bsLst, GetMsg(errKind), &puname[1]);
if (substitute)
fprintf(bsLst, GetMsg(ER_UnresExtra), &substitute[1]);
#else
fprintf(bsLst, " : error: ");
fprintf(bsLst, GetMsg(errKind), &puname[1]);
#endif
}
#if MSGMOD
FmtPrint(" : %s %c%04d: ", __NMSG_TEXT(N_error), 'L', errKind);
FmtPrint(GetMsg(errKind), &puname[1]);
if (substitute)
FmtPrint(GetMsg(ER_UnresExtra), &substitute[1]);
#else
FmtPrint(" : error: ");
FmtPrint(GetMsg(errKind), &puname[1]);
#endif
entry = entry->pl_next; /* Advance the list pointer */
} while(entry != NULL);
}
#if OSEGEXE AND NOT QCLINK
LOCAL void NEAR InitFpSym(sb, flags)
BYTE * sb;
BYTE flags;
{
APROPNAMEPTR aprop;
/* If symbol exists as EXTDEF, convert to PUBDEF */
aprop = (APROPNAMEPTR ) PropSymLookup(sb,ATTRUND,FALSE);
if(aprop != PROPNIL)
{
aprop->an_attr = ATTRPNM;
aprop->an_gsn = 0;
aprop->an_ra = 0;
aprop->an_ggr = 0;
aprop->an_flags = 0;
}
/* Otherwise, if it exists as a PUBDEF, get it else quit */
else
{
aprop = (APROPNAMEPTR) PropSymLookup(sb,ATTRPNM,FALSE);
if(aprop == PROPNIL)
return;
}
aprop->an_flags |= flags;
MARKVP();
}
/*
* InitFP
*
* Initialize table for processing floating-point fixups for new-format
* executables.
*/
LOCAL void NEAR InitFP ()
{
InitFpSym((BYTE *) "\006FIARQQ", 1 << FFPSHIFT);
InitFpSym((BYTE *) "\006FISRQQ", 2 << FFPSHIFT);
InitFpSym((BYTE *) "\006FICRQQ", 3 << FFPSHIFT);
InitFpSym((BYTE *) "\006FIERQQ", 4 << FFPSHIFT);
InitFpSym((BYTE *) "\006FIDRQQ", 5 << FFPSHIFT);
InitFpSym((BYTE *) "\006FIWRQQ", 6 << FFPSHIFT);
InitFpSym((BYTE *) "\006FJARQQ", FFP2ND);
InitFpSym((BYTE *) "\006FJSRQQ", FFP2ND);
InitFpSym((BYTE *) "\006FJCRQQ", FFP2ND);
}
#endif /* OSEGEXE AND NOT QCLINK */
#if (OSEGEXE AND CPU286)
/* until the 16 bit bsedos.h supports these definitions: */
#define FAPPTYP_NOTSPEC 0x0000
#define FAPPTYP_NOTWINDOWCOMPAT 0x0001
#define FAPPTYP_WINDOWCOMPAT 0x0002
#define FAPPTYP_WINDOWAPI 0x0003
#define FAPPTYP_BOUND 0x0008
#define FAPPTYP_DLL 0x0010
#define FAPPTYP_DOS 0x0020
#define FAPPTYP_PHYSDRV 0x0040 /* physical device driver */
#define FAPPTYP_VIRTDRV 0x0080 /* virtual device driver */
#define FAPPTYP_PROTDLL 0x0100 /* 'protected memory' dll */
/* I added these definitions: */
#define _FAPPTYP_32BIT 0x4000
#define _FAPPTYP_EXETYPE FAPPTYP_WINDOWAPI
/*-----------------------------------------------------------*/
/* from cruiser DCR 1117: */
/*
* PM Program PM (0x0)
* DOS DOSFS (0x1)
* OS/2 or FAPI Window Compatible OS2W (0x2)
* OS/2 or FAPI Non-Window Compatible OS2FS (0x3)
*/
#define _AT_PMAPI 0x00 /* Uses PM API */
#define _AT_DOS 0x01 /* DOS APP */
#define _AT_PMW 0x02 /* Window compatible */
#define _AT_NOPMW 0x03 /* Not Window compatible */
#define _AT_EXETYPE 0x03 /* EXE type mask */
/*** InitEA - initialize buffer describing extended attribute
*
* Purpose:
* Initialize EA buffer by coping its name and setting up the FEALIST.
*
* Input:
* pEABuf - pointer to EA buffer
* cbBuf - size of EA buffer
* pszEAName - extended attribute name
* peaop - pointer to EA operand
* cbEAVal - size of extended attribute value
* bEAFlags - extended attribute flags
*
* Output:
* Pointer to the place where the EA value should be copied into EA buffer
*
* Exceptions:
* None.
*
* Notes:
* None.
*
*************************************************************************/
LOCAL BYTE * NEAR InitEA(BYTE *pEABuf, WORD cbBuf, char *pszEAName,
EAOP *peaop, WORD cbEAVal, WORD bEAFlags)
{
WORD cbFEAList;
FEALIST *pfeaList;
WORD cbEAName;
BYTE *pszT;
cbEAName = strlen(pszEAName);
cbFEAList = sizeof(FEALIST) + 1 + cbEAName + cbEAVal + 2*sizeof(USHORT);
if (cbFEAList > cbBuf)
return(NULL);
pfeaList = (FEALIST *) pEABuf;
/* First initialize the EAOP structure */
peaop->fpGEAList = NULL; /* Not used for sets */
peaop->fpFEAList = (PFEALIST)pfeaList;
/* Now initialize the FEAList */
pfeaList->cbList = cbFEAList;
pfeaList->list[0].fEA = (BYTE) bEAFlags;
pfeaList->list[0].cbName = (unsigned char) cbEAName;
pfeaList->list[0].cbValue = cbEAVal + 2*sizeof(USHORT);
pszT = (char *) pfeaList + sizeof(FEALIST);
strcpy(pszT, pszEAName);
pszT += cbEAName + 1;
return(pszT);
}
#pragma check_stack(on)
/*** SetFileEABinary - set file extended attribute binary value
*
* Purpose:
* Set file extended attributes for OS/2 1.2 and higher.
*
* Input:
* fh - file handle
* pszEAName - extended attribute name
* EAVal - extended attribute value
* bEAFlags - extended attribute flags
*
* Output:
* No explicit value is returned. If succesfull file extended attributes
* are set, otherwise not.
*
* Exceptions:
* None.
*
* Notes:
* This function allocates quite a bit on stack, so don't remove
* stack checking pragma.
*
*************************************************************************/
LOCAL void NEAR SetFileEABinary(int fh, char *pszEAName,
BYTE *pEAVal, USHORT cbEAVal,
WORD bEAFlags)
{
BYTE bEABuf[512]; /* Should be enought for linker purposes */
EAOP eaop;
BYTE *pszT;
WORD retCode;
if (pszEAName == NULL || cbEAVal > sizeof(bEABuf))
return;
pszT = InitEA(bEABuf, sizeof(bEABuf), pszEAName, &eaop, cbEAVal, bEAFlags);
if (pszT == NULL)
return;
*((USHORT *)pszT) = EAT_BINARY;
pszT += sizeof(USHORT);
*((USHORT *)pszT) = cbEAVal;
pszT += sizeof(USHORT);
memmove(pszT, pEAVal, cbEAVal);
/* Now call the set file info to set the EA */
retCode = DosSetFileInfo(fh, 0x2, (void FAR *)&eaop, sizeof(EAOP));
#if FALSE
switch (retCode)
{
case 0:
fprintf(stdout, "EA -> Binary set - %s; %d bytes\r\n", pszEAName, cbEAVal);
break;
case ERROR_BUFFER_OVERFLOW:
fprintf(stdout, "Buffer overflow\r\n");
break;
case ERROR_DIRECT_ACCESS_HANDLE:
fprintf(stdout, "Direct access handle\r\n");
break;
case ERROR_EA_LIST_INCONSISTENT:
fprintf(stdout, "EA list inconsistent\r\n");
break;
case ERROR_INVALID_EA_NAME:
fprintf(stdout, "Invalid EA name\r\n");
break;
case ERROR_INVALID_HANDLE:
fprintf(stdout, "Invalid handle\r\n");
break;
case ERROR_INVALID_LEVEL:
fprintf(stdout, "Invalid level\r\n");
break;
default:
fprintf(stdout, "Unknow %d\r\n", retCode);
break;
}
#endif
return;
}
/*** SetFileEAString - set file extended attribute string
*
* Purpose:
* Set file extended attributes for OS/2 1.2 and higher.
*
* Input:
* fh - file handle
* pszEAName - extended attribute name
* pszEAVal - extended attribute string
* bEAFlags - extended attribute flags
*
* Output:
* No explicit value is returned. If succesfull file extended attributes
* are set, otherwise not.
*
* Exceptions:
* None.
*
* Notes:
* This function allocates quite a bit on stack, so don't remove
* stack checking pragma.
*
*************************************************************************/
LOCAL void NEAR SetFileEAString(int fh, char *pszEAName,
char *pszEAVal, WORD bEAFlags)
{
BYTE bEABuf[512]; /* Should be enought for linker purposes */
EAOP eaop;
WORD cbEAVal;
char *pszT;
WORD retCode;
if (pszEAName == NULL)
return;
if (pszEAVal != NULL)
cbEAVal = strlen(pszEAVal);
else
cbEAVal = 0;
pszT = InitEA(bEABuf, sizeof(bEABuf), pszEAName, &eaop, cbEAVal, bEAFlags);
if (pszT == NULL)
return;
if (pszEAVal != NULL)
{
*((USHORT *)pszT) = EAT_ASCII;
pszT += sizeof(USHORT);
*((USHORT *)pszT) = cbEAVal;
pszT += sizeof(USHORT);
memmove(pszT ,pszEAVal , cbEAVal);
}
/* Now call the set path call to set the EA */
retCode = DosSetFileInfo(fh, 0x2, (void FAR *)&eaop, sizeof(EAOP));
#if FALSE
switch (retCode)
{
case 0:
fprintf(stdout, "EA -> String set - %s = '%s'\r\n", pszEAName, pszEAVal);
break;
case ERROR_BUFFER_OVERFLOW:
fprintf(stdout, "Buffer overflow\r\n");
break;
case ERROR_DIRECT_ACCESS_HANDLE:
fprintf(stdout, "Direct access handle\r\n");
break;
case ERROR_EA_LIST_INCONSISTENT:
fprintf(stdout, "EA list inconsistent\r\n");
break;
case ERROR_INVALID_EA_NAME:
fprintf(stdout, "Invalid EA name\r\n");
break;
case ERROR_INVALID_HANDLE:
fprintf(stdout, "Invalid handle\r\n");
break;
case ERROR_INVALID_LEVEL:
fprintf(stdout, "Invalid level\r\n");
break;
default:
fprintf(stdout, "Unknow %d\r\n", retCode);
break;
}
#endif
return;
}
#pragma check_stack(off)
#endif
#pragma check_stack(on)
/*
* OutRunFile:
*
* Top-level routine to outputting executable file. Prepares some,
* then calls routine to do the work according exe format.
*/
LOCAL void NEAR OutRunFile(sbRun)
BYTE *sbRun; /* Executable file name */
{
AHTEPTR hte; /* Hash table entry address */
#if (OSEGEXE AND CPU286) OR EXE386
#pragma pack(1)
struct {
WORD ibm; /* IBM part */
WORD ms; /* Microsoft part */
} EAAppType; /* Happy EA's !?! */
#pragma pack()
#endif
#if defined(M_I386) || defined( _WIN32 )
BYTE *pIOBuf;
#endif
CheckSegmentsMemory();
#if CMDMSDOS
#if ODOS3EXE
if(fQlib)
ValidateRunFileName(sbDotQlb, TRUE, TRUE);
/* Force extension to .QLB */
else if (fBinary)
ValidateRunFileName(sbDotCom, TRUE, TRUE);
/* Force extension to .COM */
else
#endif
#if OSMSDOS
/* If runfile is a dynlink library and no runfile extension
* has been given, force the extension to ".DLL". Issue a
* warning that the name is being changed.
*/
if ((vFlags & NENOTP) && (TargetOs == NE_OS2))
ValidateRunFileName(sbDotDll, TRUE, TRUE);
else
#endif /* OSMSDOS */
ValidateRunFileName(sbDotExe, TRUE, TRUE);
/* If extension missing add .EXE */
#endif
hte = (AHTEPTR ) FetchSym(rhteRunfile,FALSE);
/* Get run file name */
#if OSMSDOS
#if NOT WIN_NT
if(hte->cch[2] != ':') /* If no drive spec */
{
sbRun[1] = chRunFile; /* Use saved drive letter */
sbRun[2] = ':'; /* Put in colon */
sbRun[0] = '\002'; /* Set length */
}
else
#endif
sbRun[0] = '\0'; /* Length is zero */
memcpy(&sbRun[B2W(sbRun[0]) + 1],&GetFarSb(hte->cch)[1],B2W(hte->cch[0]));
/* Get name from hash table */
sbRun[0] += hte->cch[0]; /* Fix length */
#else
memcpy(sbRun,GetFarSb(hte->cch),B2W(hte->cch[0]) + 1);
/* Get name from hash table */
#endif
sbRun[B2W(sbRun[0]) + 1] = '\0';
#if C8_IDE
if(fC8IDE)
{
sprintf(msgBuf, "@I4%s\r\n", sbRun+1);
_write(fileno(stderr), msgBuf, strlen(msgBuf));
}
#endif
if ((bsRunfile = fopen(&sbRun[1],WRBIN)) == NULL)
Fatal(ER_runopn, &sbRun[1], strerror(errno));
#if CPU286 AND OSMSDOS
/* Relative seeking to character devices is prohibited in
* protect mode (and under API emulation). Since we call fseek
* later on, if the output file is a character device then just
* skip the output stage.
*/
if(isatty(fileno(bsRunfile)))
return;
#endif
#if OSMSDOS
#if defined(M_I386) || defined( _WIN32 )
pIOBuf = GetMem(_32k); // Allocate 32k I/O buffer
setvbuf(bsRunfile,pIOBuf,_IOFBF,_32k);
#else
setvbuf(bsRunfile,bigbuf,_IOFBF,sizeof(bigbuf));
#endif
#endif
psbRun = sbRun; /* Set global pointer */
#if OIAPX286
OutXenExe();
#endif
#if OSEGEXE
#if EXE386
OutExe386();
#else
if(fNewExe)
OutSegExe();
#if ODOS3EXE
else
#endif
#endif
#endif
#if ODOS3EXE
OutDos3Exe();
#endif
#if (OSEGEXE AND CPU286)
if ((_osmode == OS2_MODE && (_osmajor == 1 && _osminor >= 20 || _osmajor >= 2)) ||
(_osmode == DOS_MODE && _osmajor >= 10))
{
/* Set Extended Attributes for .EXE file */
SetFileEAString(fileno(bsRunfile), ".TYPE", "Executable", 0);
EAAppType.ibm = 0;
EAAppType.ms = FAPPTYP_NOTSPEC;
if (fNewExe)
{
#if NOT EXE386
if (vFlags & NENOTP)
EAAppType.ms = FAPPTYP_DLL;
if ((vFlags & NEWINAPI) == NEWINAPI)
{
EAAppType.ibm = _AT_PMAPI;
EAAppType.ms |= FAPPTYP_WINDOWAPI;
}
else if (vFlags & NEWINCOMPAT)
{
EAAppType.ibm = _AT_PMW;
EAAppType.ms |= FAPPTYP_WINDOWCOMPAT;
}
else if (vFlags & NENOTWINCOMPAT)
{
EAAppType.ibm = _AT_NOPMW;
EAAppType.ms |= FAPPTYP_NOTWINDOWCOMPAT;
}
#endif
}
else
{
EAAppType.ibm = _AT_DOS;
EAAppType.ms = FAPPTYP_DOS;
}
SetFileEABinary(fileno(bsRunfile), ".APPTYPE",
(BYTE *) &EAAppType, sizeof(EAAppType), 0);
}
#endif
CloseFile(bsRunfile); /* Close run file */
#if defined(M_I386) || defined( _WIN32 )
FreeMem(pIOBuf);
#endif
#if OSXENIX
if(!fUndefinedExterns) chmod(&sbRun[1],0775 & ~umask(077));
/* Set protection executable */
#endif
}
#pragma check_stack(off)
#if NOT WIN_3
/*** SpawnOther - spawn any other processes
*
* Purpose:
* Spawn the other processes (i.e. cvpack) necessary to complete the
* construction of the executible.
*
* Input:
* sbRun - pointer to the name of the executible
*
* Output:
* None.
*
* Exceptions:
* None.
*
* Notes:
* None.
*
*************************************************************************/
LOCAL void NEAR SpawnOther(sbRun, szMyself)
BYTE *sbRun; /* Executable file name */
BYTE *szMyself; /* A full LINK path */
{
char FAR *env[2]; /* Enviroment for MPC */
SBTYPE progName; /* Program to invoke after linker */
SBTYPE progOptions; /* Program options */
char path_buffer[_MAX_PATH]; /* Stuff for splitpath() */
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
intptr_t status;
if ((
#if PCODE
fMPC ||
#endif
(fSymdeb && fCVpack)
#if O68K
|| iMacType != MAC_NONE
#endif
) && !cErrors && !fUndefinedExterns)
{
#if FAR_SEG_TABLES
FreeSymTab();
#if NOT WIN_NT AND NOT DOSX32
_fheapmin();
#endif
#endif
#if NOT WIN_NT
if(lpszPath != NULL)
{
FSTRCPY((char FAR *) bufg, lpszPath - 5);
env[0] = (char FAR *) bufg;
env[1] = NULL;
_putenv((char FAR *) bufg);
}
#endif
#if O68K
if (fMPC || (fSymdeb && fCVpack)) {
#endif /* O68K */
progOptions[0] = '\0';
#if PCODE
if (fSymdeb && fCVpack && fMPC)
{
strcpy(progName, "cvpack");
strcpy(progOptions, "/pcode");
}
else
strcpy(progName, fMPC ? "mpc" : "cvpack16");
#else
strcpy(progName, "cvpack");
#endif
#ifndef C8_IDE
if (fNoBanner)
#endif
strcat(progOptions, "/nologo");
// Now determine which instance of child is to be loaded
// First - check the LINK directory
_splitpath(szMyself, drive, dir, fname, ext);
strcpy(fname, progName);
_makepath(path_buffer, drive, dir, fname, ext);
if (_access(path_buffer, 0) != 0) // file not in the LINK dir
{
// Second - check the current dir
drive[0] = '\0';
_getcwd(dir, _MAX_DIR);
_makepath(path_buffer, drive, dir, fname, ext);
if (_access(path_buffer, 0) != 0) // file not in the current dir
{
strcpy(path_buffer, progName);// spawn on the PATH
}
}
#if NOT (WIN_NT OR EXE386)
// If /TINY is active, we are building a .COM file,
// and the cv info is in a .DBG file
if (fBinary)
{
_splitpath(sbRun+1, drive, dir, fname, ext);
strcpy(ext, ".DBG");
_makepath(sbRun+1, drive, dir, fname, ext);
}
#endif
#if WIN_NT OR DOSX32
if ((status = _spawnlp(P_WAIT, path_buffer, path_buffer, progOptions, &sbRun[1], NULL)) == -1)
OutWarn(ER_badspawn, path_buffer, &sbRun[1], strerror(errno));
else if (status != 0)
cErrors++;
#else
if (spawnlpe(
#if DOSEXTENDER
(!_fDosExt) ?
#else
(_osmode == DOS_MODE && _osmajor < 10) ?
#endif
P_OVERLAY : P_WAIT, path_buffer, path_buffer, progOptions, &sbRun[1], NULL, env) == -1)
OutWarn(ER_badspawn, path_buffer, &sbRun[1], strerror(errno));
#endif
#if O68K
}
if (iMacType != MAC_NONE) {
progOptions[0] = '\0';
strcpy(progName, "link_68k");
/* Now determine which instance of child is to be loaded */
/* First - check the LINK directory */
_splitpath (szMyself, drive, dir, fname, ext);
strcpy (fname, progName);
_makepath (path_buffer, drive, dir, fname, ext);
if (_access (path_buffer, 0) != 0) // file not in the LINK dir
{
// Second - check the current dir
drive[0] = '\0';
#if (_MSC_VER >= 700)
_getcwd (0, dir, _MAX_DIR);
#else
_getcwd (dir, _MAX_DIR);
#endif
_makepath (path_buffer, drive, dir, fname, ext);
if (_access (path_buffer, 0) != 0) // file not in the current dir
{
strcpy (path_buffer, progName); // spawn on the PATH
}
}
if (iMacType == MAC_SWAP)
strcat(progOptions, "/s ");
if (fSymdeb)
strcat(progOptions, "/c ");
if ((status = spawnlp(P_WAIT, path_buffer, path_buffer,
progOptions, &sbRun[1], NULL)) == -1)
OutWarn(ER_badspawn, path_buffer, &sbRun[1], strerror(errno));
else if (status != 0)
cErrors++;
}
#endif /* O68K */
}
}
#endif
/****************************************************************
* *
* InterPass: *
* *
* Take care of miscellaneous items which must be done between *
* pass 1 and 2. *
* *
****************************************************************/
LOCAL void NEAR InterPass (void)
{
#if OEXE
if(!fPackSet) packLim = fNewExe ?
#if EXE386
CBMAXSEG32 :
#elif O68K
(iMacType != MAC_NONE ? LXIVK / 2 :
LXIVK - 36) :
#else
LXIVK - 36 :
#endif
0L;
#endif
#if NOT EXE386
// Set TargetOS - see LINK540 bug #11 for description
if (fNewExe && TargetOs != NE_OS2)
{
// Import/export seen in the OBJ files or .DEF file specified
#if CPU286
if(rhteDeffile == RHTENIL) // OS2 host and no .def file - OS2 target
TargetOs = NE_OS2;
else
TargetOs = NE_WINDOWS;
#else
TargetOs = NE_WINDOWS;
#endif
}
#endif
#if ODOS3EXE
// /DOSSEG (from switch or comment rec) forces off /DS, /NOG
if (fSegOrder)
vfDSAlloc = fNoGrpAssoc = FALSE;
#endif
#if ILINK
fQCIncremental = (FTYPE) (!fNewExe && fIncremental);
/* QC incremental link */
if (fQCIncremental)
{
TargetOs = 0xff; /* Mark .EXE as not compatibile with OS/2 .EXE */
fNewExe = (FTYPE) TRUE; /* Force to build segemented-executable */
}
#endif
#if ODOS3EXE AND OSEGEXE AND NOT EXE386
if (fNewExe)
{
// Check for invalid options for segmented-executable and ignore them
if ((vFlags & NENOTP) && cbStack)
{
cbStack = 0; // For DLLs ignore STACKSIZE
OutWarn(ER_ignostksize);
}
if (
#if ILINK
!fQCIncremental &&
#endif
cparMaxAlloc != 0xffff)
{
OutWarn(ER_swbadnew, "/HIGH or /CPARMAXALLOC");
cparMaxAlloc = 0xffff;
}
if (vfDSAlloc)
{
OutWarn(ER_swbadnew, "/DSALLOCATE");
vfDSAlloc = FALSE;
}
if (fNoGrpAssoc)
{
OutWarn(ER_swbadnew, "/NOGROUPASSOCIATION");
fNoGrpAssoc = FALSE;
}
if (fBinary)
{
OutWarn(ER_swbadnew, "/TINY");
fBinary = FALSE;
}
#if OVERLAYS
if (fOverlays)
{
OutWarn(ER_swbadnew, "Overlays");
fOverlays = FALSE;
}
#endif
}
else
{
if(fileAlign != DFSAALIGN)
OutWarn(ER_swbadold,"/ALIGNMENT");
#ifdef LEGO
if (fKeepFixups)
OutWarn(ER_swbadold, "/KEEPFIXUPS");
#endif /* LEGO */
if(fPackData)
OutWarn(ER_swbadold,"/PACKDATA");
#if OVERLAYS
if(fOldOverlay)
fDynamic= (FTYPE) FALSE;
else
fDynamic = fOverlays;
#endif
}
#if NOT QCLINK
// Check if fixup optimizations are possible
fOptimizeFixups = (FTYPE) ((TargetOs == NE_OS2 || TargetOs == NE_WINDOWS)
#if ILINK
&& !fIncremental
#endif
#if O68K
&& iMacType == MAC_NONE
#endif
);
#endif
pfProcFixup = fNewExe ? FixNew : FixOld;
#ifdef LEGO
if (fKeepFixups && fNewExe && (vFlags & NEPROT)
#if ILINK
&& !fIncremental
#endif
#if O68K
&& (iMacType == MAC_NONE)
#endif
)
pfProcFixup = FixNewKeep;
#endif /* LEGO */
#endif
/* Since mpsegraFirst was used for something else, clear it. */
FMEMSET(mpsegraFirst,0, gsnMax * sizeof(RATYPE));
}
#if EXE386
/*
* ChkSize386 : check 386 program size
*
* Made necessary by the way segment mapping is done to VM. See
* msa386().
*/
LOCAL void NEAR ChkSize386(void)
{
register long *p; /* Pointer to mpsegcb */
register long *pEnd; /* Pointer to end of mpsegcb */
register unsigned long cb; /* Byte count */
/*
* Check that total size of segments fits within virtual memory
* area alloted for segments. Note that we DO NOT CHECK FOR
* ARITHMETIC OVERFLOW. To be strictly correct we should but
* it will be very rare and the error should be evident elsewhere.
*/
if (fNewExe)
{
p = &mpsacb[1];
pEnd = &mpsacb[segLast];
}
#if ODOS3EXE
else
{
p = &mpsegcb[1];
pEnd = &mpsegcb[segLast];
}
#endif
for(cb = 0; p <= pEnd; ++p)
cb += (*p + (PAGLEN - 1)) & ~(PAGLEN - 1);
/* If size exceeds VM limit, quit with a fatal error. */
if(cb > (((unsigned long)VPLIB1ST<<LG2PAG)-AREAFSG))
Fatal(ER_pgmtoobig,(((unsigned long)VPLIB1ST<<LG2PAG)-AREAFSG));
}
#endif
LOCAL void NEAR InitAfterCmd (void)
{
#if ILINK
if (fIncremental && fBinary)
{
fIncremental = FALSE;
OutWarn(ER_tinyincr);
}
if (fIncremental && !fPackSet)
{
packLim = 0;
fPackSet = (FTYPE) TRUE;
}
#endif
fFarCallTransSave = fFarCallTrans;
InitTabs(); /* Initialize dynamic tables */
#if QBLIB
if(fQlib) InitQbLib(); /* Initialize QB-Library items */
#endif
#if CMDMSDOS
LibEnv(); /* Process LIB= environment variable */
#endif
if(fLstFileOpen && cbStack)
fprintf(bsLst,"Stack Allocation = %u bytes\r\n",
(cbStack + 1) & ~1); /* Print stack size */
}
/****************************************************************
* *
* main: *
* *
* The main function. *
* *
****************************************************************/
#if NOT WIN_3
void __cdecl main (argc,argv)
int argc; /* Argument count */
char **argv; /* Argument list */
#else
int PASCAL WinMain( HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
#endif
{
#if OVERLAYS OR ODOS3EXE
APROPNAMEPTR apropName; /* Public symbol pointer */
#endif
SBTYPE sbRun; /* Executable file name */
#if NOT WIN_3
#if !defined( _WIN32 ) AND ( WIN_NT AND !defined(DOSX32) OR USE_REAL )
int exceptCode;
_try
{
#endif
/* DLH bsErr can't be statically initialized with the CRT in a DLL */
bsErr = stderr;
#if CVPACK_MONDO
/* check for special cvpack only invocation */
if (argc > 1 && strcmp(argv[1], "/CvpackOnly") == 0)
{
/* we're not linking at all -- just invoke the built in cvpack */
argv[1] = "cvpack";
argv++;
argc--;
exit(cvpack_main(argc, argv));
}
#endif // CVPACK_MONDO
#if TIMINGS
ftime(&time_start);
#endif // TIMINGS
#if OSEGEXE
/* HACK ALERT !!! - special check for undocumented /Z1 option */
if (argc > 1)
{
if ((argv[1][0] == CHSWITCH) &&
((argv[1][1] == 'Z') || (argv[1][1] == 'z')))
{
BYTE option[30];
option[0] = (BYTE) strlen(argv[1]);
strcpy(&option[1], argv[1]);
PeelFlags(option); /* Process /Z1 */
}
}
#endif
#else // WIN_3 TRUE
ProcessWinArgs( lpCmdLine );
#endif // WIN_3
InitializeWorld(); /* Initialize the linker */
#if NOT WIN_3
#if CMDMSDOS
if (argc <= 1 && !fNoBanner)
#endif
DisplayBanner(); /* Display signon banner */
ParseCmdLine(argc,argv); /* Parse the command line */
InitAfterCmd(); /* Initialize post-cmd stuff */
#else // WIN_3 is TRUE
ParseLinkCmdStr();
InitAfterCmd(); /* Initialize post-cmd stuff */
#endif // WIN_3
#if USE_REAL
if(IsDosxnt() && IsWin31() && !fSwNoUseReal)
fUseReal = (FTYPE)MakeConvMemPageable();
if(fUseReal)
_onexit( (_onexit_t) RealMemExit );
#endif
#if OSEGEXE
#if FDEBUG AND NOT QCLINK AND NOT WIN_3
if(fDebug) FmtPrint(GetMsg(P_parsedeffile)); // **** PARSE DEFINITIONS FILE ****\r\n
#endif
#if WIN_3
StatHdrWin(GetMsg(P_lwParseDef));
#endif
#if C8_IDE
if(fC8IDE)
{
sprintf(msgBuf, "@I0\r\n");
_write(fileno(stderr), msgBuf, strlen(msgBuf));
sprintf(msgBuf, "@I1Microsoft (R) Linker Version 5.40\r\n");
_write(fileno(stderr), msgBuf, strlen(msgBuf));
sprintf(msgBuf, "@I2Copyright (C) Microsoft Corp 1992\r\n");
_write(fileno(stderr), msgBuf, strlen(msgBuf));
sprintf(msgBuf, "@I3%s\r\n", GetMsg(P_lwParseDef));
_write(fileno(stderr), msgBuf, strlen(msgBuf));
}
#endif
#if NOT QCLINK
#if NOT EXE386
if (!fBinary)
#endif
ParseDeffile(); /* Parse the definitions file */
#endif
#endif
#if ODOS3EXE
// If overlays have been specified, but switches /OLDOV /DYN were
// not present on the command line, set /DYN to ON
// (dynamic overlays are the default)
if(fOverlays && !fOldOverlay && !fDynamic)
{
fDynamic = TRUE;
fFarCallTrans = (FTYPE) TRUE;
fPackSet = (FTYPE) TRUE;
packLim = LXIVK - 36; /* Default limit is 64K - 36 */
ovlThunkMax = 256;
}
#endif
fFarCallTransSave = fFarCallTrans;
if(fDynamic && fExePack)
{
fExePack = FALSE;
OutWarn(ER_dynexep);
}
#if WIN_3
StatHdrWin(GetMsg(P_lwPassOne));
#endif
#if C8_IDE
if(fC8IDE)
{
sprintf(msgBuf,"@I3%s\r\n", GetMsg(P_lwPassOne));
_write(fileno(stderr), msgBuf, strlen(msgBuf));
}
#endif
#if FDEBUG
if(fDebug) FmtPrint(GetMsg(P_passone)); // **** PASS ONE ****\r\n
#endif
#if OSMSDOS AND AUTOVM
CleanupNearHeap();
#endif
snkey = 0; /* Initialize for pass 1 */
modkey = 0; /* Initialize for pass 1 */
ObjDebTotal = 1;
ifhLast = FHNIL; /* No files looked at yet */
#if NEWIO
/* Allocate a file stream for bsInput with a dummy file handle */
bsInput = fdopen(0,RDBIN);
#endif /*NEWIO*/
#if OSMSDOS
setvbuf(bsInput,bigbuf,_IOFBF,sizeof(bigbuf));
#endif
rprop1stOpenFile = rprop1stFile; /* Remember first open file */
r1stFile = rprop1stFile; /* which is also first input file */
vfPass1 = (FTYPE) TRUE; /* Now pass 1 */
DrivePass(ProcP1); /* Make pass 1 */
#if OVERLAYS
// If overlays, make $$OVLINIT or $$MOVEINIT an undefined symbol
if (fOverlays)
{
if (!fOldOverlay)
{
if (PropSymLookup("\012$$MOVEINIT",ATTRPNM,FALSE) == PROPNIL)
PropSymLookup("\012$$MOVEINIT", ATTRUND, TRUE);
}
else
{
if (PropSymLookup("\011$$OVLINIT",ATTRPNM,FALSE) == PROPNIL)
PropSymLookup("\011$$OVLINIT", ATTRUND, TRUE);
}
}
#endif
#if WIN_3
StatHdrWin(GetMsg(P_lwLibraryS));
#endif
#if C8_IDE
if(fC8IDE)
{
sprintf(msgBuf,"@I3%s\r\n", GetMsg(P_lwLibraryS));
_write(fileno(stderr), msgBuf, strlen(msgBuf));
}
#endif
#if FDEBUG
if(fDebug) FmtPrint(GetMsg(P_libsearch));
#endif
#if OSMSDOS AND AUTOVM
CleanupNearHeap();
#endif
#if OEXE
if (fSegOrder)
SetDosseg();
#endif
LibrarySearch(); /* Search libraries */
vfPass1 = FALSE; /* No longer pass 1 */
#if LNKPROF
if(fP1stop) { FlsStdio(); exit(0); }
#endif
InterPass(); /* Do various between-pass tasks */
#if OSMSDOS AND AUTOVM
CleanupNearHeap();
#endif
#if WIN_3
StatHdrWin(GetMsg(P_lwAssign));
#endif
#if C8_IDE
if(fC8IDE)
{
sprintf(msgBuf,"@I3%s\r\n", GetMsg(P_lwAssign));
_write(fileno(stderr), msgBuf, strlen(msgBuf));
}
#endif
#if FDEBUG
if(fDebug) FmtPrint(GetMsg(P_assignadd)); /* **** ASSIGN ADDRESSES ****\r\n*/
#endif
AllocComDat();
AssignAddresses(); /* Assign addresses to segments */
#if SYMDEB
if (fSymdeb)
DoComdatDebugging();
#endif
if (fFullMap)
UpdateComdatContrib(
#if ILINK
FALSE,
#endif
TRUE);
#if EXE386
InitVmBase(); /* Set VM object areas base addresses */
FillInImportTable();
#endif
if(fLstFileOpen) /* If list file open */
{
#if WIN_3
StatHdrWin(GetMsg(P_lwMapfile));
#endif
#if C8_IDE
if(fC8IDE)
{
sprintf(msgBuf,"@I3%s\r\n", GetMsg(P_lwMapfile));
_write(fileno(stderr), msgBuf, strlen(msgBuf));
}
#endif
#if FDEBUG
if(fDebug) FmtPrint(GetMsg(P_printmap));/* **** PRINT MAP ****\r\n */
#endif
PrintMap(); /* Print load map */
#if QBLIB
if(fQlib) PrintQbStart();
#endif
}
#if OSEGEXE AND NOT QCLINK
if (fNewExe
#if NOT EXE386 AND ILINK
&& !fQCIncremental
#endif
)
InitEntTab(); /* Initialize the Entry Table */
#endif
#if EXE386
if(f386) ChkSize386(); /* Check program size for 386 */
#endif
#if OSEGEXE AND NOT QCLINK
if (fNewExe
#if NOT EXE386 AND ILINK
&& !fQCIncremental
#endif
)
InitFP(); /* Initialize floating-point items */
#endif
#if OSMSDOS AND AUTOVM
CleanupNearHeap();
#endif
snkey = 0; /* Initialize for pass 2 */
modkey = 0; /* Initialize for pass 2 */
ifhLast = FHNIL; /* No files examined on pass 2 yet */
#if WIN_3
StatHdrWin(GetMsg(P_lwPassTwo));
#endif
#if C8_IDE
if(fC8IDE)
{
sprintf(msgBuf,"@I3%s\r\n", GetMsg(P_lwPassTwo));
_write(fileno(stderr), msgBuf, strlen(msgBuf));
}
#endif
#if FDEBUG
if(fDebug) FmtPrint(GetMsg(P_passtwo)); /* **** PASS TWO ****\r\n*/
#endif
DrivePass(ProcP2); /* Make pass 2 */
#if OSEGEXE
if (vpropAppLoader != PROPNIL)
{
APROPUNDEFPTR apropUndef;
apropUndef = (APROPUNDEFPTR) FetchSym(vpropAppLoader, TRUE);
fUndefinedExterns = fUndefinedExterns || (FTYPE) (apropUndef->au_attr == ATTRUND);
apropUndef->u.au_rFil = AddVmProp(apropUndef->u.au_rFil, rprop1stFile);
}
#endif
#if ODOS3EXE
if (fDOSExtended)
{
apropName = (APROPNAMEPTR ) PropSymLookup("\017__DOSEXT16_MODE", ATTRPNM, FALSE);
// Look up public symbol
if (apropName != PROPNIL)
{
if (dosExtMode != 0)
MoveToVm(sizeof(WORD), (BYTE *) &dosExtMode, mpgsnseg[apropName->an_gsn], apropName->an_ra);
// Store value
}
}
#endif
#if OVERLAYS
if (fOverlays)
{
// If there are overlays check if we have an overlay manager
apropName = (APROPNAMEPTR ) PropSymLookup(fDynamic ? "\012$$MOVEINIT" :
"\011$$OVLINIT",
ATTRPNM, FALSE);
if (apropName != PROPNIL)
{ // If starting point defined
raStart = apropName->an_ra;// Get offset of entry point
segStart = mpgsnseg[apropName->an_gsn];
// Get base number of entry point
}
else
OutError(ER_ovlmnger);
}
#endif
if(fUndefinedExterns) /* If we have unresolved references */
{
if(fLstFileOpen && bsLst != stdout)
{ /* If we have a list file */
NEWLINE(bsLst);
#if CMDXENIX
fprintf(bsLst,"%s: ",lnknam);
/* Linker name */
#endif
}
#if QCLINK
if (!fZ1)
#endif
NEWLINE(stderr);
EnSyms(PrintAnUndef,ATTRUND); /* Print undefined symbols */
if(fLstFileOpen && bsLst != stdout)
NEWLINE(bsLst);
#if QCLINK
if (!fZ1)
#endif
NEWLINE(stderr);
}
#if ILINK
if (fIncremental)
{
OutputIlk(); /* Output .ilk / .sym files */
}
#endif /*ILINK*/
#if FDEBUG
if(fDebug)
{
if( !fDelexe || fDelexe && cErrors==0 )
{
FmtPrint(GetMsg(P_writing1)); /* **** WRITING */
if (fNewExe)
{
if (TargetOs == NE_OS2)
FmtPrint("OS/2");
else if (TargetOs == NE_WINDOWS)
FmtPrint("WINDOWS");
}
else
{
FmtPrint("DOS");
#if OVERLAYS
if (fOverlays)
FmtPrint(GetMsg(P_writing2)); /* - overlaid*/
#endif
}
FmtPrint(GetMsg(P_writing3)); /* EXECUTABLE ****\r\n*/
#if OVERLAYS
if (fOverlays && fDynamic)
FmtPrint(GetMsg(P_overlaycalls), ovlThunkMax, ovlThunkMac);/***** NUMBER OF INTEROVERLAY CALLS: requested %d; generated %d ****\r\n*/
#endif
PrintStats();
#if PROFSYM
ProfSym(); /* Profile symbol table */
#endif
}
else // some errors occured
{
FmtPrint(GetMsg(P_noexe));
}
}
#endif /* FDEBUG */
if( !fDelexe || fDelexe && cErrors==0 )
{
#if WIN_3
StatHdrWin(GetMsg(P_lwExecutable));
#endif
#if C8_IDE
if(fC8IDE)
{
sprintf(msgBuf,"@I3%s\r\n", GetMsg(P_lwExecutable));
_write(fileno(stderr), msgBuf, strlen(msgBuf));
}
#endif
#if OSMSDOS
if (chRunFile >= 'a' && chRunFile <= 'z')
chRunFile += (BYTE) ('A' - 'a');
/* Make drive letter upper case */
if(fPauseRun && FCHGDSK(chRunFile - 'A'))
{
if(fLstFileOpen && chListFile == (BYTE) (chRunFile - 'A'))
{ /* If map on EXE drive */
fclose(bsLst); /* Close the list file */
fLstFileOpen = FALSE; /* Set flag accordingly */
}
(*pfPrompt)(NULL,P_genexe,(int) NULL,P_ChangeDiskette,chRunFile);
}
else
fPauseRun = FALSE;
#endif
if(fLstFileOpen && bsLst != stdout)
{
fclose(bsLst);
fLstFileOpen = FALSE;
}
fclose(bsInput); /* Close input file */
#if NOT EXE386
if (fExePack && fNewExe && (TargetOs == NE_WINDOWS))
{
OutWarn(ER_exepack);
fExePack = FALSE;
}
#endif
OutRunFile(sbRun); /* Output executable file */
CleanUp(); /* Mop up after itself */
#ifdef PENTER_PROFILE
saveEntries();
#endif
#if OWNSTDIO
FlsStdio();
#endif
#if TIMINGS
if (fShowTiming) // check if we started the timer...
{
char buf[80];
int hundr;
time_t td;
ftime(&time_end);
td = time_end.time - time_start.time;
hundr = (time_end.millitm - time_start.millitm)/10;
td = td*100 + hundr;
sprintf(buf, "Linker phase: %d.%02ds\r\n", td/100, td%100);
_write(fileno(stdout), buf, strlen(buf));
time_start = time_end;
}
#endif // TIMINGS
#if NOT WIN_3
#ifndef CVPACK_MONDO
SpawnOther(sbRun, argv[0]);
#else
if (fSymdeb && fCVpack && !cErrors && !fUndefinedExterns)
{
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
int argcT = 0;
char *argvT[5];
argvT[argcT++] = "cvpack";
argvT[argcT++] = "/nologo";
if (fMPC)
argvT[argcT++] = "/pcode";
sbRun[sbRun[0]+1] = '\0'; // NUL terminate
// If /TINY is active, we are building a .COM file,
// and the cv info is in a .DBG file
if (fBinary)
{
_splitpath(sbRun+1, drive, dir, fname, NULL);
_makepath(sbRun+1, drive, dir, fname, ".DBG");
}
argvT[argcT++] = sbRun+1;
argvT[argcT] = NULL;
fflush(stderr);
fflush(stdout);
_setmode(1,_O_TEXT);
_setmode(2,_O_TEXT);
#if FAR_SEG_TABLES
FreeSymTab();
#if NOT WIN_NT AND NOT DOSX32
_fheapmin();
#endif
#endif
cvpack_main(argcT, argvT);
}
else if (fMPC)
SpawnOther(sbRun, argv[0]); // we'll be running MPC
#endif
#if TIMINGS
if (fShowTiming) // check if we started the timer...
{
char buf[80];
int hundr;
time_t td;
ftime(&time_end);
td = time_end.time - time_start.time;
hundr = (time_end.millitm - time_start.millitm)/10;
td = td*100 + hundr;
sprintf(buf, "Cvpack phase: %d.%02ds\r\n", td/100, td%100);
_write(fileno(stdout), buf, strlen(buf));
time_start = time_end;
}
#endif // TIMINGS
#endif
}
fflush(stdout);
fflush(stderr);
#if USE_REAL
RealMemExit();
#endif
EXIT((cErrors || fUndefinedExterns)? 2: 0);
#if !defined( _WIN32 ) AND ( WIN_NT AND !defined(DOSX32) OR USE_REAL )
}
_except (1)
{
#if USE_REAL
RealMemExit();
#endif
exceptCode = _exception_code();
if (exceptCode == EXCEPTION_ACCESS_VIOLATION)
{
fprintf(stdout, "\r\nLINK : fatal error L5000 : internal failure - access violation ");
fflush(stdout);
}
else if (exceptCode == EXCEPTION_DATATYPE_MISALIGNMENT)
{
fprintf(stdout, "\r\nLINK : fatal error L5001 : internal failure - datatype misalignment ");
fflush(stdout);
}
else
CtrlC();
}
#endif
}