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

1355 lines
46 KiB
C

/* SCCSID = %W% %E% */
/*
* Copyright Microsoft Corporation, 1983-1987
*
* This Module contains Proprietary Information of Microsoft
* Corporation and should be treated as Confidential.
*/
/****************************************************************
* *
* LIBRARY PROCESSING ROUTINES *
* *
****************************************************************/
#include <minlit.h> /* Types and constants */
#include <bndtrn.h> /* Types and constants */
#include <bndrel.h> /* Types and constants */
#include <lnkio.h> /* Linker I/O definitions */
#include <lnkmsg.h> /* Error messages */
#include <extern.h> /* External declarations */
#include <stdlib.h>
#if OSMSDOS
#include <dos.h> /* DOS interface definitions */
#if CPU286
#define INCL_BASE
#include <os2.h> /* OS/2 interface definitions */
#if defined(M_I86LM)
#undef NEAR
#define NEAR
#endif
#endif
#endif
#define DICHDR 0xF1 /* Dictionary header type (F1H) */
#if OSXENIX
#define ShrOpenRd(f) fopen(f,RDBIN)
#endif
#if NEWIO
#include <errno.h> /* System error codes */
#endif
#define PNSORTMAX 512 /* Maximum # modules can be sorted */
typedef struct _edmt /* Extended Dictionary Module Table */
{
WORD page;
WORD list;
}
edmt;
LOCAL FTYPE fUndefHit; /* found this undef in the library */
LOCAL FTYPE fFileExtracted; /* Took file from library flag */
LOCAL FTYPE fUndefsSeen; /* True if externals seen in library */
LOCAL WORD ipnMac; /* Count of page numbers in sort table */
LOCAL WORD *pnSort; /* Sort table for library page numbers */
/* f(ifh) = pointer to dictionary */
LOCAL WORD mpifhcpnHash[IFHLIBMAX];
/* f(ifh) = # pages in hash table */
LOCAL BYTE mpifhAlign[IFHLIBMAX];
/* f(ifh) = lib alignment factor */
LOCAL RBTYPE vrpNewList; /* List of unprocessed files */
LOCAL FTYPE vfLibOpen; /* Library open flag */
#if M_BYTESWAP OR defined( _WIN32 )
#define getfarword getword /* This assumes no far data */
#else
#define getfarword(x) (((WORD FAR *)(x))[0])
#endif
/*
* INTERFACE WITH ASSEMBLY LANGUAGE FUNCTION
*/
WORD libAlign; /* Library alignment factor */
WORD libcpnHash; /* Length of hash table in pages */
BYTE FAR *mpifhDict[IFHLIBMAX];
/*
* FUNCTION PROTOTYPES
*/
LOCAL unsigned char NEAR OpenLibrary(unsigned char *sbLib);
LOCAL void NEAR FreeDictionary(void);
#if CPU8086 OR CPU286
LOCAL WORD NEAR readfar(int fh, char FAR *buf,int n);
#endif
LOCAL void NEAR GetDictionary(void);
LOCAL WORD NEAR GetLib(void);
LOCAL void ProcessAnUndef(APROPNAMEPTR papropUndef,
RBTYPE rhte,
RBTYPE rprop,
WORD fNewHte);
LOCAL int cdecl FGtNum(const WORD *pn1, const WORD *pn2);
LOCAL void NEAR LookMod(edmt *modtab,unsigned short iMod);
LOCAL void NEAR LookPage(edmt *modtab,unsigned short cMod,unsigned short page);
LOCAL void NEAR ProcExtDic(char *pExtDic);
LOCAL char * NEAR GetExtDic(void);
#if NEW_LIB_SEARCH
/// undef lookaside list
typedef struct tag_UND
{
struct tag_UND * pNext;
APROPNAMEPTR papropUndef;
DWORD dwLibMask;
RBTYPE rhte;
} UND;
#define C_UNDS_POOL 128
typedef struct tag_UNDPOOL
{
struct tag_UNDPOOL *pNext;
UND und[C_UNDS_POOL];
} UNDPOOL;
// pool storage management variables
UNDPOOL *pundpoolCur;
UNDPOOL *pundpoolHead;
int iundPool = C_UNDS_POOL;
UND * pundFree;
UND * pundListHead;
#define FUndefsLeft() (pundListHead != NULL)
void StoreUndef(APROPNAMEPTR, RBTYPE, RBTYPE, WORD);
#else
#define FUndefsLeft() (fUndefsSeen)
#endif
FTYPE fStoreUndefsInLookaside = FALSE;
/////
#if NOASM
LOCAL WORD NEAR rolw(WORD x, WORD n) /* Rotate word left */
{
return(LO16BITS((x << n) | ((x >> (WORDLN - n)) & ~(~0 << n))));
}
LOCAL WORD NEAR rorw(WORD x, WORD n) /* Rotate word right */
{
return(LO16BITS((x << (WORDLN - n)) | ((x >> n) & ~(~0 << (WORDLN - n)))));
}
#endif
#if OSMSDOS
BSTYPE NEAR ShrOpenRd(pname)
char *pname; /* Name of file (null-terminated) */
{
int fh; /* File handle */
#if NEWIO
if(mpifhfh[ifhLibCur])
{
fh = mpifhfh[ifhLibCur];
/* If dictionary not allocated, seek to beginning since we're
* somewhere else now.
*/
if(!mpifhDict[ifhLibCur])
_lseek(fh,0L,0);
}
else
fh = SmartOpen(pname,ifhLibCur);
if(fh > 0)
{
fflush(bsInput);
bsInput->_file = (char) fh;
return(bsInput);
}
else
return(NULL);
#else
if((fh = _sopen(pname,O_RDONLY | O_BINARY,SH_DENYWR)) < 0)
return(NULL);
return(fdopen(fh,RDBIN));
#endif
}
#endif /* OSMSDOS */
#pragma check_stack(on)
/****************************************************************
* *
* OpenLibrary: *
* *
* This function takes as its arguments a pointer to the text *
* of the name of the library to open, a count of the bytes in *
* that name, an index into a global table in which to place *
* the file handle for the opened library. It returns TRUE if *
* it succeeds, FALSE if it fails to open the file; and it *
* dies gracefully if the file is not a valid library. *
* *
****************************************************************/
LOCAL FTYPE NEAR OpenLibrary(sbLib)
BYTE *sbLib; /* Library name */
{
SBTYPE libnam; /* Library name */
WORD reclen; /* Library header record length */
BSTYPE bsLib; /* File stream pointer for library */
memcpy(libnam,&sbLib[1],B2W(sbLib[0]));
/* Copy library name */
libnam[B2W(sbLib[0])] = '\0'; /* Null-terminate name */
/* WARNING: do not assign bsInput to NULL if open fails, it
* screws up NEWIO.
*/
if((bsLib = ShrOpenRd(libnam)) != NULL)
{ /* If open successful */
bsInput = bsLib;
/* If dictionary already allocated, no need to do anything */
if(mpifhDict[ifhLibCur])
return((FTYPE) TRUE);
#if OSMSDOS
/* Reduce buffer size. We can avoid calling setvbuf() because
* everything is set up properly at this point.
*/
#if OWNSTDIO
bsInput->_bsize = 512;
#else
setvbuf(bsInput, bsInput->_base, _IOFBF, 512);
#endif
#endif
if(getc(bsInput) == LIBHDR) /* If we have a library */
{
reclen = (WORD) (3 + WSGets());
/* Get record length */
for(libAlign = 15; libAlign &&
!(reclen & (1 << libAlign)); --libAlign);
/* Calculate alignment factor */
mpifhAlign[ifhLibCur] = (BYTE) libAlign;
if(libAlign >= 4 && reclen == (WORD) (1 << libAlign))
{ /* Check legality of alignment */
libHTAddr = (long) WSGets();
libHTAddr += (long) WSGets() << WORDLN;
/* Get the offset of the hash table */
if (libHTAddr <= 0L)
Fatal(ER_badlib,libnam);
if ((mpifhcpnHash[ifhLibCur] = WSGets()) <= 0)
/* Get size of hash table in pages */
Fatal(ER_badlib,libnam);
#if OSMSDOS
/* Restore big buffer size. Avoid calling setvbuf(). */
#if OWNSTDIO
bsInput->_bsize = LBUFSIZ;
#else
setvbuf(bsInput, bsInput->_base, _IOFBF, LBUFSIZ);
#endif
#endif
return((FTYPE) TRUE); /* Success */
}
}
Fatal(ER_badlib,libnam);
}
return(FALSE); /* Failure */
}
#pragma check_stack(off)
/*
* LookupLibSym: look up a symbol in library dictionary
*
* The minimum page size is 16, so we can return paragraph offsets.
* This is a win because offsets are stored as paragraphs in the
* sorting table anyway. Also, the majority of libraries have page
* size of 16.
*
* Parameters:
* char *psb - pointer to length-prefixed string
* Returns:
* Long paragraph offset to location of module which defines
* the symbol, or 0L if not found.
*/
#if NOASM
LOCAL WORD NEAR LookupLibSym(psb)
BYTE *psb; /* Symbol to look up */
{
WORD i1; /* First hash value */
WORD d1; /* First hash delta */
WORD i2; /* Second hash value */
WORD d2; /* Second hash delta */
WORD pn; /* Page number */
WORD dpn; /* Page number delta */
WORD pslot; /* Page slot */
WORD dpslot; /* Page slot delta */
WORD ipn; /* Initial page number */
BYTE FAR *hpg;
#if NOASM
WORD ch1; /* Character */
WORD ch2; /* Character */
char *pc1; /* Character pointer */
char *pc2; /* Character pointer */
WORD length; /* Symbol length */
#endif
#if LIBDEBUG
OutSb(stderr,psb);
fprintf(stderr," is wanted; dictionary is %d pages\r\n",libcpnHash);
#endif
#if NOASM
length = B2W(psb[0]); /* Get symbol length */
pc1 = (char *) psb; /* Initialize */
pc2 = (char *) &psb[B2W(psb[0])]; /* Initialize */
i1 = 0; /* Initialize */
d1 = 0; /* Initialize */
i2 = 0; /* Initialize */
d2 = 0; /* Initialize */
while(length--) /* Hashing loop */
{
ch1 = (WORD) (B2W(*pc1++) | 040);/* Force to lower case */
ch2 = (WORD) (B2W(*pc2--) | 040);/* Force to lower case */
i1 = (WORD) (rolw(i1,2) ^ ch1); /* Hash */
d1 = (WORD) (rolw(d1,2) ^ ch2); /* Hash */
i2 = (WORD) (rorw(i2,2) ^ ch2); /* Hash */
d2 = (WORD) (rorw(d2,2) ^ ch1); /* Hash */
}
#else
i1 = libhash(psb,&d1,&i2,&d2); /* Hash */
#endif
pn = (WORD) (i1 % libcpnHash); /* Calculate page number index */
if(!(dpn = (WORD) (d1 % libcpnHash))) dpn = 1;
/* Calculate page number delta */
pslot = (WORD) (i2 % CSLOTMAX); /* Calculate page slot index */
if(!(dpslot = (WORD) (d2 % CSLOTMAX))) dpslot = 1;
/* Calculate page slot delta */
#if LIBDEBUG
fprintf(stderr,"page index %d, delta %d, bucket index %d, delta %d\r\n",
pn,dpn,pslot,dpslot);
#endif
ipn = pn; /* Remember initial page number */
for(;;) /* Search loop */
{
#if LIBDEBUG
fprintf(stderr,"Page %d:\r\n",pn);
#endif
// Get pointer to the dictionary page
hpg = mpifhDict[ifhLibCur] + (pn << LG2PAG);
for(i2 = 0; i2 < CSLOTMAX; ++i2)/* Loop to check slots */
{
#if LIBDEBUG
fprintf(stderr,"Bucket %d %sempty, page %sfull\r\n",
pslot,hpg[pslot]? "not ": "",
B2W(hpg[CSLOTMAX]) == 0xFF? "": "not ");
#endif
if(!(i1 = (WORD) (B2W(hpg[pslot]) << 1)))
{ /* If slot is empty */
if(B2W(hpg[CSLOTMAX]) == 0xFF) break;
/* If page is full, break */
return(0); /* Search failed */
}
#if LIBDEBUG
fprintf(stderr," Comparing ");
OutSb(stderr,psb);
fprintf(stderr," to ");
OutSb(stderr,&hpg[i1]);
fprintf(stderr," %signoring case\r\n",fIgnoreCase? "": "not ");
#endif
if(psb[0] == hpg[i1] && SbNewComp(psb,&hpg[i1],fIgnoreCase))
{ /* If symbols match */
#if LIBDEBUG
fprintf(stderr,"Match found in slot %d\r\n",i2 >> 1);
#endif
i1 += (WORD) (B2W(hpg[i1]) + 1); /* Skip over name */
i1 = getfarword(&hpg[i1]);
/* Get page number of module */
return(i1); /* Return page number of module */
}
if((pslot += dpslot) >= CSLOTMAX) pslot -= CSLOTMAX;
/* Try next slot */
}
if((pn += dpn) >= libcpnHash) pn -= libcpnHash;
/* Try next page */
if (ipn == pn) return(0); /* Once around without finding it */
}
}
#endif /*NOASM*/
/*
* FreeDictionary : free space allocated for dictionaries
*/
LOCAL void NEAR FreeDictionary ()
{
WORD i;
for (i = 0; i < ifhLibMac; ++i)
if (mpifhDict[i])
FFREE(mpifhDict[i]);
}
#if CPU8086 OR CPU286
/*
* readfar : read() with a far buffer
*
* Emulate read() except use a far buffer. Call the system
* directly.
*
* Returns:
* 0 if error, else number of bytes read.
*/
LOCAL WORD NEAR readfar (fh, buf, n)
int fh; /* File handle */
char FAR *buf; /* Buffer to store bytes in */
int n; /* # bytes to read */
{
#if OSMSDOS
unsigned bytesread; /* Number of bytes read */
#if CPU8086
if (_dos_read(fh, buf, n, &bytesread))
return(0);
return(bytesread);
#else
if(DosRead(fh,buf,n,(unsigned FAR *) &bytesread))
return(0);
return(bytesread);
#endif
#endif /* OSMSDOS */
#if OSXENIX
char mybuf[PAGLEN];
int cppage;
char *p;
while(n > 0)
{
cppage = n > PAGLEN ? PAGLEN : n;
if(read(fh,mybuf,cppage) != cppage)
return(0);
n -= cppage;
for(p = mybuf; p < mybuf[cppage]; *buf++ = *p++);
}
#endif
}
#endif
LOCAL void NEAR GetDictionary ()
{
unsigned cb;
#if CPU8086 OR CPU286
// If there is more than 128 pages in dictionary return,
// because the dictionary is bigger than 64k
if (libcpnHash >= 128)
return;
#endif
cb = libcpnHash << LG2PAG;
mpifhDict[ifhLibCur] = GetMem(cb);
// Go to the dictionary and read it in a single call
#if defined(M_I386) || defined( _WIN32 )
fseek(bsInput, libHTAddr, 0);
if (fread(mpifhDict[ifhLibCur], 1, cb, bsInput) != (int) cb)
Fatal(ER_badlib,1 + GetPropName(FetchSym(mpifhrhte[ifhLibCur],FALSE)));
#else
_lseek(fileno(bsInput), libHTAddr, 0);
if (readfar(fileno(bsInput), mpifhDict[ifhLibCur], cb) != cb)
Fatal(ER_badlib,1 + GetPropName(FetchSym(mpifhrhte[ifhLibCur],FALSE)));
#endif
}
#pragma check_stack(on)
LOCAL WORD NEAR GetLib(void) /* Open the next library in list */
{
AHTEPTR pahteLib; /* Pointer to library name */
#if OSMSDOS
SBTYPE sbLib; /* Library name */
SBTYPE sbNew; /* New parts to library name */
#endif
if(mpifhrhte[ifhLibCur] == RHTENIL) /* If this library is to be skipped */
{
return(FALSE); /* No library opened */
}
for(;;) /* Loop to open library */
{
pahteLib = (AHTEPTR ) FetchSym(mpifhrhte[ifhLibCur],FALSE);
/* Get name from hash table */
if(OpenLibrary(GetFarSb(pahteLib->cch))) break;
/* Break if lib opened okay */
if(fNoprompt)
Fatal(ER_libopn,1 + GetFarSb(pahteLib->cch));
else
{
sbLib[0] = '\0'; /* No string yet */
UpdateFileParts(sbLib,GetFarSb(pahteLib->cch));
(*pfPrompt)(sbNew,ER_libopn, /* Prompt for new filespec */
(int) (__int64) (1 + GetFarSb(pahteLib->cch)),
P_EnterNewFileSpec, 0);
}
if(fNoprompt || !sbNew[0])
{
mpifhrhte[ifhLibCur] = RHTENIL;
/* Do not bother next time */
return(FALSE); /* Unsuccessful */
}
#if OSMSDOS
UpdateFileParts(sbLib,sbNew); /* Update file name with new parts */
PropSymLookup(sbLib,ATTRFIL,TRUE);
/* Add library to symbol table */
mpifhrhte[ifhLibCur] = vrhte; /* Save virtual address */
AddLibPath(ifhLibCur); /* Add default path spec, maybe */
#endif
}
vfLibOpen = (FTYPE) TRUE; /* A library is open */
libcpnHash = mpifhcpnHash[ifhLibCur];
libAlign = mpifhAlign[ifhLibCur];
if (mpifhDict[ifhLibCur] == NULL) /* If dictionary not allocated, do it */
GetDictionary();
return(TRUE); /* Success */
}
#pragma check_stack(off)
/****************************************************************
* *
* ProcessAnUndef: *
* *
* This function takes as its arguments two pointers, two *
* RBTYPEs, and a flag. It does not return a meaningful *
* value. Most of the parameters to this function are *
* dummies; this function's address is passed as a parameter, *
* and its parameter list must match those of all the *
* functions whose addresses can be passed as a parameter to *
* the same function to which ProcessAnUndef's address is *
* passed. Called by EnSyms. *
* *
****************************************************************/
LOCAL void ProcessAnUndef(APROPNAMEPTR papropUndef,
RBTYPE rhte,
RBTYPE rprop__NotUsed__,
WORD fNewHte__NotUsed__)
{
AHTEPTR pahte; /* Pointer to hash table entry */
WORD pn; /* Library page number */
APROPUNDEFPTR pUndef;
ATTRTYPE attr;
#if NOT NEWSYM
SBTYPE sb; /* Undefined symbol */
#endif
fUndefHit = FALSE;
pUndef = (APROPUNDEFPTR ) papropUndef;
attr = pUndef->au_flags;
// don't pull out any "weak" externs or unused aliased externals
if (((attr & WEAKEXT) && !(attr & UNDECIDED)) ||
((attr & SUBSTITUTE) && !(attr & SEARCH_LIB)))
{
fUndefHit = TRUE; // this item is effectively resolved...
return;
}
fUndefsSeen = (FTYPE) TRUE; /* Set flag */
if(!mpifhDict[ifhLibCur] && !vfLibOpen)
return; /* Return if unable to get library */
pahte = (AHTEPTR ) FetchSym(rhte,FALSE);
/* Fetch name from symbol table */
#if NOT NEWSYM
memcpy(sb,pahte->cch,B2W(pahte->cch[0]) + 1);
/* Copy name */
#endif
#if LIBDEBUG
fprintf(stdout,"Looking for '%s' - ", 1+GetFarSb(pahte->cch));
fflush(stdout);
#endif
#if NEWSYM
if(pn = LookupLibSym(GetFarSb(pahte->cch)))
#else
if(pn = LookupLibSym(sb)) /* If symbol defined in this library */
#endif
{
fUndefHit = TRUE;
#if LIBDEBUG
fprintf(stdout,"Symbol found at page %xH\r\n", pn);
fflush(stdout);
#endif
/* We now try to stuff the page number (pn) into a table that will
* be sorted later.
*/
if (ipnMac < PNSORTMAX)
{
pnSort[ipnMac++] = pn;
return;
}
/*
* No room to save the file offset so save file directly.
*/
pahte = (AHTEPTR ) FetchSym(mpifhrhte[ifhLibCur],FALSE);
/*
* If SaveInput returns 0, then module was seen before. Means
* that dictionary says symbol is defined in this module but
* for some reason, such as IMPDEF, the definition wasn't
* accepted. In this case, we return.
*/
if(!SaveInput(GetFarSb(pahte->cch), (long)pn << libAlign, ifhLibCur, 0))
return;
/*
* If first module extracted, save start of file list.
*/
if(!fFileExtracted)
{
vrpNewList = vrpropTailFile;
fFileExtracted = (FTYPE) TRUE;
}
}
#if LIBDEBUG
else
{
fprintf(stdout, "Symbol NOT found\r\n"); /* Debug message */
fflush(stdout);
}
#endif
}
#if NEW_LIB_SEARCH
void StoreUndef(APROPNAMEPTR papropUndef, RBTYPE rhte,
RBTYPE rprop, WORD fNewHte)
{
UND * pund;
APROPUNDEFPTR pUndef;
ATTRTYPE attr;
pUndef = (APROPUNDEFPTR ) papropUndef;
attr = pUndef->au_flags;
// don't pull out any "weak" externs or unused aliased externals
if (((attr & WEAKEXT) && !(attr & UNDECIDED)) ||
((attr & SUBSTITUTE) && !(attr & SEARCH_LIB)))
return;
#ifdef LIBDEBUG
{
AHTEPTR pahte;
pahte = (AHTEPTR) FetchSym(rhte,FALSE);
fprintf(stdout,"Adding '%s'\r\n", 1+GetFarSb(pahte->cch));
fflush(stdout);
}
#endif
if (pundFree) // check free list
{
pund = pundFree;
pundFree = pundFree->pNext;
}
else if (iundPool < C_UNDS_POOL) // check pool
{
pund = &pundpoolCur->und[iundPool];
iundPool++;
}
else
{
// allocate new pool...
pundpoolCur = (UNDPOOL *)GetMem(sizeof(UNDPOOL));
pundpoolCur->pNext = pundpoolHead;
pundpoolHead = pundpoolCur;
pund = &pundpoolCur->und[0];
iundPool = 1; // entry zero is already used up
}
pund->dwLibMask = 0;
pund->pNext = pundListHead;
pund->papropUndef = papropUndef;
pund->rhte = rhte;
pundListHead = pund;
}
#endif
/*
* Greater-than comparator to be used by Sort routine.
*/
LOCAL int cdecl FGtNum(const WORD *pn1, const WORD *pn2)
{
if (*pn1 < *pn2)
return(-1);
if (*pn1 > *pn2)
return(1);
return(0);
}
/************************************************************************
* Extended Dictionary
*
* The extended dictionary occurs at the end of the regular dictionary
* and contains a first-level dependency tree for all the modules
* in the library.
************************************************************************/
#define LIBEXD 0xf2 /* Library EXtended Dictionary */
/****************************************************************
* *
* Extended Dictionary Format: *
* *
* *
* BYTE =0xF2 Extended Dictionary header *
* WORD length of extended dictionary in bytes *
* excluding 1st 3 bytes *
* *
* Start of ext. dictionary: *
* *
* WORD number of modules in library = N *
* *
* Module table, indexed by module number, with N + 1 fixed- *
* length entries: *
* *
* WORD module page number *
* WORD offset from start of ext. dictionary to list *
* of required modules *
* *
* Last entry is null. *
* *
* Module dependency lists, N variable-length lists: *
* *
* WORD list length (number of required modules) *
* WORD module index, 0-based; this is index to module *
* . . . table at the begin of ext. dictionary. *
* . . . *
* *
* *
****************************************************************/
#pragma loop_opt(on)
/*
* LookMod : look up a module by index in the extended dictionary
*
* Get the list of modules required by the given module. If not
* already marked, save index in sorting table (which will be
* converted to page number later) and mark the entry in the
* module table as seen by setting the low bit of the list offset.
*
* Parameters:
* modtab: Pointer to module table
* iMod: Index into table, 0-based
*/
LOCAL void NEAR LookMod (edmt *modtab, WORD iMod)
{
WORD *pw; /* Pointer to list of indexes */
WORD n; /* List counter */
/*
* Get the pointer to the list. Mask off low bit since it is used
* as a marker.
*/
pw = (WORD *) ((char *) modtab + (modtab[iMod].list & ~1));
/*
* For every entry in the list, if the corresponding entry in the
* module table is not marked, save the index in pnSort and mark
* the entry in the module table.
*/
for(n = *pw++; n--; pw++)
{
if(!(modtab[*pw].list & 1))
{
/*
* Check for table overflow.
*/
if(ipnMac == PNSORTMAX)
return;
pnSort[ipnMac++] = *pw;
modtab[*pw].list |= 1;
}
}
}
/*
* LookPage : Look up a module in the module table by page number
*
* Use binary search. If page is found, call LookMod() on the
* matching entry.
*
* Parameters:
* modtab: Pointer to module table
* cMod: Number of entries in table
* page: Page number
* ASSUMES:
* The highest entry in the table has a page number of 0xffff.
*/
LOCAL void NEAR LookPage (edmt *modtab, WORD cMod, WORD page)
{
WORD mid; /* Current mid point */
WORD lo, hi; /* Current low and high points */
lo = 0; /* Table is 0-based. */
hi = (WORD) (cMod - 1);
while(lo <= hi)
{
if(modtab[mid = (WORD) ((lo + hi) >> 1)].page == page)
{
modtab[mid].list |= 1;
LookMod(modtab,mid);
return;
}
else if(modtab[mid].page < page)
lo = (WORD) (mid + 1);
else
hi = (WORD) (mid - 1);
}
}
#pragma loop_opt(off)
/*
* ProcExtDic : Process Extended Dictionary
*
* Store in pnSort all the secondary modules required by
* the modules obtained from the regular dictionary lookup.
*
* Parameters:
* pExtDic: Pointer to extended dictionary
*/
LOCAL void NEAR ProcExtDic (pExtDic)
char *pExtDic;
{
WORD *p;
WORD *pEnd;
WORD cMod;
edmt *modtab;
cMod = getword(pExtDic);
modtab = (edmt *) (pExtDic + 2);
/* For the binary search algorithm, we make an artifical last entry
* with a page # at least as high as anything else.
*/
modtab[cMod].page = 0xffff;
/* Process by page numbers */
for(p = pnSort, pEnd = &pnSort[ipnMac]; p < pEnd; ++p)
LookPage(modtab, cMod, *p);
/* Now pnSort from pEnd to lfaSort[ipnMac] contains module
* index numbers. Process by index number and convert to page.
*/
for( ; p < &pnSort[ipnMac]; ++p)
{
LookMod(modtab,*p);
*p = modtab[*p].page;
}
}
/*
* GetExtDic - Get Extended Dictionary
*/
LOCAL char * NEAR GetExtDic ()
{
char *p;
int length;
if(!vfLibOpen)
if(!GetLib())
return(NULL);
/* WARNING: we must just have read dictionary for this to work,
* otherwise an fseek() is required here.
*/
if (!mpifhDict[ifhLibCur])
{
fflush(bsInput);
fseek(bsInput, libHTAddr + (libcpnHash << LG2PAG), 0);
}
if(getc(bsInput) != LIBEXD)
return(NULL);
if((p = GetMem(length = WSGets())) != NULL)
if(fread(p,1,length,bsInput) != length)
{
FreeMem(p);
p = NULL;
}
return(p);
}
char *pExtDic = NULL; /* Pointer to extended dictionary */
/****************************************************************
* *
* LibrarySearch: *
* *
* This function takes no arguments. It searches all open *
* libraries to resolve undefined externals. It does not *
* return a meaningful value. *
* *
****************************************************************/
void NEAR LibrarySearch(void)
{
RBTYPE vrpTmpFileFirst;
WORD ifhLibMacInit; /* Initial number of libs to search */
FTYPE searchMore; /* Search continue flag */
WORD bufpnSort[PNSORTMAX];
/* Actual space for pnSort */
SBTYPE sbLibname; /* Name of current library */
AHTEPTR pahte; /* Pointer to hash table entry */
REGISTER WORD i;
FTYPE fLibPass1 = (FTYPE) TRUE;
/* True if on 1st pass thru libs */
FTYPE *fUsedInPass1; /* True if lib used in 1st pass thru libs */
FTYPE fFirstTime; /* True if lib seen for the first time */
extern FTYPE fNoExtDic; /* True if /NOEXTDICTIONARY */
#if NEW_LIB_SEARCH
UND *pund; /* pointer in undef lookaside list */
UND *pundPrev; /* pointer to previous undef entry */
UND *pundNext; /* pointer to next undef entry */
#endif
fUndefsSeen = (FTYPE) TRUE; /* There are undefined externals */
vfLibOpen = FALSE; /* No libraries open yet */
pnSort = bufpnSort; /* Initialize sort table pointer */
ifhLibMacInit = ifhLibMac;
fUsedInPass1 = (FTYPE *) GetMem(ifhLibMac * sizeof(FTYPE));
if (fUsedInPass1 != NULL)
memset(fUsedInPass1, TRUE, ifhLibMac);
#if NEW_LIB_SEARCH
// build up the the lookaside list
EnSyms(StoreUndef,ATTRUND);
fStoreUndefsInLookaside = TRUE;
#endif
do /* Loop to search libraries */
{
searchMore = FALSE; /* Assume on final pass */
for(ifhLibCur = 0; ifhLibCur < ifhLibMac && FUndefsLeft(); ++ifhLibCur)
{ /* While undefs and libraries */
#if NEW_LIB_SEARCH
DWORD libMask = (1<<ifhLibCur);
if (pundListHead->dwLibMask & libMask)
continue; // no need to search this library
// the first item in the list has already
// been searched...
#endif
if(!GetLib())
continue;
/*
* If this is first pass through the libraries and /NOEXT was
* not given, try to get the extended dictionary. We assume that
* if there is one then only one library pass is needed.
*/
if(fLibPass1 && !fNoExtDic)
pExtDic = GetExtDic();
else
pExtDic = NULL;
/* If no extended dictionary, reduce buffer size because more
* seeking will be done. This will affect remaining libraries
* in search; we don't care about mixed extended and non-
* extended libraries.
*/
if(!pExtDic)
setvbuf(bsInput,bsInput->_base,_IOFBF,1024);
pahte = (AHTEPTR ) FetchSym(mpifhrhte[ifhLibCur],FALSE);
/* Get library name */
memcpy(sbLibname,GetFarSb(pahte->cch),B2W(pahte->cch[0])+1);
#if WIN_3 OR C8_IDE
sbLibname[B2W(*sbLibname)+1] = '\0';
#endif
#if WIN_3
StatMsgWin( "%s\r\n", sbLibname+1);
#endif
#if C8_IDE
if(fC8IDE)
{
sprintf(msgBuf, "@I4%s\r\n", sbLibname+1);
_write(fileno(stderr), msgBuf, strlen(msgBuf));
}
#endif
fFirstTime = (FTYPE) TRUE;
while(FUndefsLeft()) /* While there are undefs seen */
{
fFileExtracted = FALSE; /* Assume we won't take anything */
fUndefsSeen = FALSE; /* Assume no more undefs */
ipnMac = 0; /* Initialize sort table count */
#if NOT NEW_LIB_SEARCH
EnSyms(ProcessAnUndef,ATTRUND);
#else
pund = pundListHead;
pundPrev = NULL;
while (pund)
{
if (pund->dwLibMask & libMask)
{
break; // since items are added to the head,
// as soon as we find one item that has
// already been searched, the rest have
// also already been searched...
// pundPrev = pund;
// pund = pund->pNext;
// continue;
}
pundNext = pund->pNext;
if (pund->papropUndef->an_attr == ATTRUND)
ProcessAnUndef(pund->papropUndef, pund->rhte, 0, 0);
else
fUndefHit = TRUE; // no longer undefined -- remove
if (fUndefHit)
{
// remove this item from the undef list...
if (pundPrev)
pundPrev->pNext = pundNext;
else
pundListHead = pundNext;
pund->pNext = pundFree;
pundFree = pund;
}
else
{
pund->dwLibMask |= libMask;
pundPrev = pund;
}
pund = pundNext;
}
#endif
/* Try to resolve references */
/* If no modules obtained, exit loop. */
if(!ipnMac)
{
#if NEWIO
if (fLibPass1)
{
/*
* If this library is seen for the first time in
* the first pass thru libraries and we don't
* pull out any modules from it, then close this
* library, because there are big chances this
* library is not needed.
*/
if (fFirstTime)
{
_close(mpifhfh[ifhLibCur]);
mpifhfh[ifhLibCur] = 0;
/*
* Mark it also as not used in pass 1
* so, we can closed it also in the
* next passes thru libs.
*/
if (fUsedInPass1)
fUsedInPass1[ifhLibCur] = FALSE;
}
}
else if (fUsedInPass1 && !fUsedInPass1[ifhLibCur])
{
/*
* In pass "n" thru libs close libraries
* not used in pass 1.
*/
_close(mpifhfh[ifhLibCur]);
mpifhfh[ifhLibCur] = 0;
}
#endif
break;
}
fFirstTime = FALSE; /* No longer first time seen */
/* If extended dictionary present, process it. */
if(pExtDic)
ProcExtDic(pExtDic);
/* Sort modules by page offset. */
qsort(pnSort, ipnMac, sizeof(WORD),
(int (__cdecl *)(const void *, const void *)) FGtNum);
/*
* Save each module represented in the table.
*/
for (i = 0; i < ipnMac; i++)
{
/*
* If SaveInput returns 0, the module was already seen. See
* above comment in ProcessAnUndef().
*/
if(!SaveInput(sbLibname, (long)pnSort[i] << libAlign, ifhLibCur, 0))
continue;
if(!fFileExtracted) /* If no files extracted yet */
{
vrpNewList = vrpropTailFile;
/* Save start of file list */
fFileExtracted = (FTYPE) TRUE;
/* We have extracted a file */
}
}
if(!fFileExtracted)
break; /* If we didn't take anything, break */
/* Library might not be open because we may have searched
* an already-loaded dictionary. If necessary, re-open
* library.
*/
if(!vfLibOpen)
GetLib();
searchMore = (FTYPE) TRUE; /* Otherwise it's worth another pass */
vrpTmpFileFirst = rprop1stFile;
/* Save head of module list */
rprop1stFile = vrpNewList;
/* Put new modules at head of list */
fLibPass = (FTYPE) TRUE; /* Processing object from library */
DrivePass(ProcP1); /* Do pass 1 on object from library */
fLibPass = FALSE; /* No longer processing lib. object */
rprop1stFile = vrpTmpFileFirst;
/* Restore original head of list */
if (fUsedInPass1 && ifhLibMacInit < ifhLibMac)
{
/* DrivePass added more libraries to search */
/* Reallocate fUsedInPass1 */
FTYPE *p; /* Temporary pointer */
p = (FTYPE *) GetMem(ifhLibMac * sizeof(FTYPE));
if (p == NULL)
{
FFREE(fUsedInPass1);
fUsedInPass1 = NULL;
}
else
{
memset(p, TRUE, ifhLibMac);
memcpy(p, fUsedInPass1, ifhLibMacInit);
FFREE(fUsedInPass1);
fUsedInPass1 = p;
}
ifhLibMacInit = ifhLibMac;
}
}
/* Free space for extended dictionary if present */
if(pExtDic)
FFREE(pExtDic);
if(vfLibOpen)
{
#if NOT NEWIO
fclose(bsInput); /* Close the library */
#endif
vfLibOpen = FALSE; /* No library open */
}
}
/* No longer on 1st pass thru libraries. */
fLibPass1 = FALSE;
}
while(searchMore && FUndefsLeft()); /* Do until search done */
FreeMem(fUsedInPass1);
FreeDictionary(); /* Free dictionary space */
/*
* Restore large buffer size in case it was reduced.
*/
setvbuf(bsInput,bsInput->_base,_IOFBF,LBUFSIZ);
#if NEW_LIB_SEARCH
fStoreUndefsInLookaside = FALSE;
while (pundpoolHead)
{
pundpoolCur = pundpoolHead->pNext;
FFREE(pundpoolHead);
pundpoolHead = pundpoolCur;
}
#endif
}
#if CMDMSDOS
/*
* GetLibAll:
*
* Process all the modules in a given library in Pass 1.
* Create property cells for them and insert into the file list.
*/
void NEAR GetLibAll(sbLib)
BYTE *sbLib;
{
WORD ifh; /* (fake) library index */
long lfa; /* Current file offset */
IOVTYPE iov; /* Overlay number */
RBTYPE rbFileNext; /* Pointer to next file property */
RBTYPE rbFileNew; /* Pointer to new file property */
APROPFILEPTR apropFile, apropFilePrev;
BYTE *sbInput; /* Asciiz filename */
int fh; /* File handle */
fDrivePass = FALSE;
sbInput = sbLib + 1;
/* Get the ifh, iov, and pointer to the next file from the current
* file pointer.
*/
apropFile = (APROPFILEPTR ) FetchSym(vrpropFile,TRUE);
ifh = apropFile->af_ifh;
iov = apropFile->af_iov;
rbFileNext = apropFile->af_FNxt;
#if NEWIO
fh = SmartOpen(sbInput,ifh);
if (fh <= 0 && lpszLIB != NULL)
fh = SearchPathLink(lpszLIB, sbInput, ifh, TRUE);
if (fh > 0)
{
fflush(bsInput);
bsInput->_file = (char) fh;
}
else
Fatal(ER_fileopn,sbInput);
#else
if((bsInput = fopen(sbInput,RDBIN)) == NULL)
Fatal(ER_fileopn,sbInput);
#endif
if(getc(bsInput) != LIBHDR) /* Check for valid record type */
Fatal(ER_badlib,sbInput);
cbRec = (WORD) (3 + WSGets()); /* Get record length */
for(libAlign = 15; libAlign && !(cbRec & (1 << libAlign)); --libAlign);
/* Calculate alignment factor */
fDrivePass = (FTYPE) TRUE;
/* Reset current file's lfa from 0 to offset of 1st module */
apropFile->af_lfa = lfa = 1L << libAlign;
/* Go to the first module */
fseek(bsInput,lfa,0);
/* Process the library as follows: Process the current module.
* Go to the next module; if it starts with DICHDR then we're
* done. Else, create a new file property cell for the next
* module, insert it in the file list, and go to start of loop.
*/
rect = (WORD) getc(bsInput);
while (rect != DICHDR)
{
ungetc(rect, bsInput);
lfaLast = apropFile->af_lfa = ftell(bsInput);
ProcP1();
while (TYPEOF(rect) != MODEND)
{
rect = (WORD) getc(bsInput);
fseek(bsInput, (cbRec = WSGets()), 1);
}
do
{
rect = (WORD) getc(bsInput);
}
while (rect != THEADR && rect != DICHDR && rect != EOF);
if (rect == DICHDR)
{
if (rbFileNext == RHTENIL)
vrpropTailFile = vrpropFile;
#if NOT NEWIO
fclose(bsInput);
#else
rbFilePrev = vrpropFile;
#endif
return;
}
if (rect == EOF)
Fatal(ER_libeof);
// Make a new file property cell
apropFile = (APROPFILEPTR ) PropAdd(vrhteFile, ATTRFIL);
rbFileNew = vrprop;
#if ILINK
apropFile->af_imod = ++imodCur; // allocate a module number
apropFile->af_cont = 0;
apropFile->af_ientOnt = 0;
#endif
apropFile->af_rMod = 0;
apropFile->af_ifh = (char) ifh;
apropFile->af_iov = (IOVTYPE) iov;
apropFile->af_FNxt = rbFileNext;
#if SYMDEB
apropFile->af_publics = NULL;
apropFile->af_Src = NULL;
apropFile->af_SrcLast = NULL;
apropFile->af_cvInfo = NULL;
#endif
apropFile->af_ComDat = 0L;
apropFile->af_ComDatLast = 0L;
MARKVP();
// Get the just-processed property file cell
apropFilePrev = (APROPFILEPTR ) FetchSym(vrpropFile,TRUE);
apropFilePrev->af_FNxt = rbFileNew;
vrpropFile = rbFileNew;
};
// Remove an empty Lib from the chain of files
if (vrpropFile == rprop1stFile)
{
// If the empty lib is first on list
rprop1stFile = rbFileNext;
}
else
{
#if NEWIO
apropFilePrev = (APROPFILEPTR)FetchSym(rbFilePrev, TRUE);
apropFilePrev->af_FNxt = apropFile->af_FNxt;
#endif
}
#if NEWIO
if (rbFileNext == RHTENIL)
vrpropTailFile = rbFilePrev; // In case we removed the last file
_close(fileno(bsInput));
rbFilePrev = vrpropFile;
#endif
}
#endif /*CMDMSDOS*/