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.

1259 lines
53 KiB

  1. /*
  2. * TITLE
  3. * newent.c
  4. * Pete Stewart
  5. * (C) Copyright Microsoft Corp 1984-1989
  6. * 1 October 1984
  7. *
  8. * DESCRIPTION
  9. * This file contains routines for the DOS 4.0 linker
  10. * that manage per-segment entry point information.
  11. *
  12. * It also contains routines that manage per-segment
  13. * relocation information.
  14. *
  15. * Modifications:
  16. *
  17. * 09-Feb-1989 RB Fix Insert().
  18. */
  19. #include <minlit.h> /* Basic type definitions */
  20. #include <bndtrn.h> /* Constants and compound types */
  21. #include <bndrel.h> /* Types and constants */
  22. #include <lnkio.h> /* I/O definitions */
  23. #include <newexe.h> /* DOS & 286 .EXE format data structures */
  24. #if EXE386
  25. #include <exe386.h> /* 386 .EXE format data structures */
  26. #endif
  27. #include <lnkmsg.h> /* Error messages */
  28. #include <extern.h> /* External declarations */
  29. #include <impexp.h>
  30. #define hashra(ra) (WORD) ((ra) % HEPLEN)
  31. /* Function to hash offset */
  32. #if NOT EXE386
  33. #define hashrlc(r) (((NR_SEGNO(*r) << NR_STYPE(*r)) + NR_ENTRY(*r)) & HASH_SIZE - 1)
  34. /* Hash relocation item */
  35. #define EOC ((RATYPE) 0xFFFF)
  36. /* End-of-chain marker */
  37. #endif
  38. #define IsInSet(x) ((pOrdinalSet[(x) >> 3] & BitMask[(x) & 0x07]) != 0)
  39. #define NotInSet(x) ((pOrdinalSet[(x) >> 3] & BitMask[(x) & 0x07]) == 0)
  40. #define SetBit(x) (pOrdinalSet[(x) >> 3] |= BitMask[(x) & 0x07])
  41. #define MaxIndex 8192
  42. #define ET_END 0xffff
  43. /*
  44. * FUNCTION PROTOTYPES
  45. */
  46. LOCAL void NEAR NewBundle(unsigned short type);
  47. LOCAL WORD NEAR MatchRlc(RLCPTR rlcp0,
  48. RLCPTR rlcp1);
  49. #if NOT QCLINK
  50. LOCAL void NEAR NewEntry(unsigned short sa,
  51. RATYPE ra,
  52. unsigned char flags,
  53. unsigned short hi,
  54. unsigned short ord);
  55. LOCAL void SavExp1(APROPNAMEPTR apropexp,
  56. RBTYPE rhte,
  57. RBTYPE rprop,
  58. WORD fNewHte);
  59. LOCAL void SavExp2(APROPNAMEPTR apropexp,
  60. RBTYPE rhte,
  61. RBTYPE rprop,
  62. WORD fNewHte);
  63. LOCAL WORD NEAR BuildList(WORD NewOrd, RBTYPE NewProp);
  64. LOCAL WORD NEAR FindFreeRange(void);
  65. LOCAL WORD NEAR Insert(RBTYPE NewProp);
  66. #endif
  67. /*
  68. * LOCAL DATA
  69. */
  70. #if NOT QCLINK
  71. #pragma pack(1)
  72. typedef struct _BUNDLE
  73. {
  74. BYTE count;
  75. BYTE type;
  76. }
  77. BUNDLE;
  78. #pragma pack()
  79. LOCAL WORD ceCurBnd; /* No. of entries in current bundle */
  80. LOCAL WORD offCurBnd; /* Offset of current bundle header */
  81. LOCAL WORD tyCurBnd; /* Type of current bundle */
  82. LOCAL WORD ordMac; /* Highest entry ordinal number */
  83. LOCAL BYTE *pOrdinalSet;
  84. #if EXE386
  85. LOCAL APROPEXPPTR pExport; /* Pointer to export property cell */
  86. #endif
  87. LOCAL struct {
  88. WORD ord; /* Current available ordinal */
  89. WORD count; /* Number of free ordinals in range */
  90. }
  91. FreeRange;
  92. LOCAL BYTE BitMask[] = { /* Bit mask used in set operations */
  93. 0x01,
  94. 0x02,
  95. 0x04,
  96. 0x08,
  97. 0x10,
  98. 0x20,
  99. 0x40,
  100. 0x80 };
  101. LOCAL WORD MinOrd = 0; /* Min ordinal number see so far */
  102. LOCAL WORD MaxOrd = 0; /* Max ordinal number see so far */
  103. RBTYPE pMinOrd = NULL; /* Pointer to property cell with MinOrd */
  104. LOCAL RBTYPE pMaxOrd = NULL; /* Pointer to property cell with MaxOrd */
  105. LOCAL RBTYPE pStart;
  106. #ifndef UNPOOLED_RELOCS
  107. LOCAL void * pPoolRlc; /* memory pool for relocations */
  108. #endif
  109. #if NOT EXE386
  110. LOCAL void NEAR NewBundle(type) /* Make a new bundle */
  111. WORD type; /* Type of new bundle */
  112. {
  113. BUNDLE FAR *pBnd; /* Ptr to start of bundle or entry */
  114. BUNDLE bnd;
  115. if (EntryTable.byteMac != 0)
  116. {
  117. // If there is a previous bundle patch the count filed
  118. pBnd = (BUNDLE FAR *) &(EntryTable.rgByte[offCurBnd]);
  119. pBnd->count = (BYTE) ceCurBnd;
  120. }
  121. bnd.count = 0;
  122. bnd.type = (BYTE) type;
  123. offCurBnd = AddEntry((BYTE *) &bnd, sizeof(BUNDLE));
  124. ceCurBnd = 0;
  125. tyCurBnd = type;
  126. if (type == ET_END)
  127. EntryTable.byteMac--;
  128. }
  129. #endif
  130. /****************************************************************
  131. * *
  132. * NAME: NewEntry *
  133. * *
  134. * DESCRIPTION: *
  135. * *
  136. * This function makes an entry in the Entry Table for a *
  137. * given file segment number, offset, and flag set. It also *
  138. * makes an entry in the entry address hash table on the *
  139. * given hash chain for the new entry point. N.B.: this *
  140. * function assumes the static variable ordMac is set to the *
  141. * desired ordinal value for the entry being added. *
  142. * *
  143. * ARGUMENTS: *
  144. * *
  145. * SATYPE sa File segment number *
  146. * RATYPE ra Offset *
  147. * FTYPE flags Entry point flags *
  148. * WORD hi Hash table index *
  149. * WORD ord New ordinal *
  150. * *
  151. * RETURNS: *
  152. * *
  153. * WORD Offset in Entry Table *
  154. * *
  155. * SIDE EFFECTS: *
  156. * *
  157. * Maintains a hash table hashing file segment/offset pairs *
  158. * to entry table offsets. Builds in virtual memory the *
  159. * Entry Table. Updates the following variables: *
  160. * *
  161. * WORD offCurBnd Offset of start of current *
  162. * bundle of entries. *
  163. * WORD ceCurBnd Count of entries in cur- *
  164. * rent bundle. *
  165. * WORD tyCurBnd Type of current bundle. *
  166. * WORD cbEntTab Size of Entry Table in *
  167. * bytes. *
  168. * *
  169. * NOTE: THIS FUNCTION CALLS THE VIRTUAL MEMORY MANAGER. *
  170. * *
  171. ****************************************************************/
  172. LOCAL void NEAR NewEntry(sa,ra,flags,hi,ord)
  173. SATYPE sa; /* File segment number */
  174. RATYPE ra; /* Segment offset */
  175. FTYPE flags; /* Entry point flags */
  176. WORD hi; /* Hash table index */
  177. WORD ord; /* New ordinal */
  178. {
  179. EPTYPE FAR *ep; /* Entry point node */
  180. #if NOT EXE386
  181. WORD tyEntry; /* Entry type */
  182. WORD cbEntry; /* Length of entry in bytes */
  183. BYTE entry[6]; /* The entry itself - NE version */
  184. #endif
  185. #if EXE386
  186. static WORD prevEntryOrd; // Previous export ordinal
  187. DWORD eatEntry; /* The entry itself - LE version */
  188. #endif
  189. #if NOT EXE386
  190. if(sa == SANIL) /* If absolute symbol */
  191. tyEntry = BNDABS; /* use fake segment # */
  192. else if (TargetOs == NE_OS2)
  193. tyEntry = NonConfIOPL(mpsaflags[sa]) ? BNDMOV: sa;
  194. else
  195. tyEntry = (mpsaflags[sa] & NSMOVE)? BNDMOV: sa;
  196. /* Get the entry type */
  197. /* If not library, or realmode and not solo data, clear local data bit. */
  198. if(!(vFlags & NENOTP) || (!(vFlags & NEPROT) && !(vFlags & NESOLO)))
  199. flags &= ~2;
  200. entry[0] = (BYTE) flags; /* Set the entry flags */
  201. if(tyEntry == BNDMOV /* If entry is in movable segment */
  202. #if O68K
  203. && iMacType == MAC_NONE
  204. #endif
  205. )
  206. {
  207. ++cMovableEntries; /* Increment movable entries count */
  208. cbEntry = 6; /* Entry is six bytes long */
  209. entry[1] = 0xCD; /* INT... */
  210. entry[2] = 0x3F; /* ...3FH */
  211. entry[3] = (BYTE) sa; /* File segment number */
  212. entry[4] = (BYTE) ra; /* Lo-byte of offset */
  213. entry[5] = (BYTE)(ra >> BYTELN);/* Hi-byte of offset */
  214. }
  215. else /* Else if fixed entry */
  216. {
  217. cbEntry = 3; /* Entry is three bytes long */
  218. entry[1] = (BYTE) ra; /* Lo-byte of offset */
  219. entry[2] = (BYTE)(ra >> BYTELN);/* Hi-byte of offset */
  220. }
  221. #endif
  222. #if EXE386
  223. /*
  224. * This function creates one entry in the Export Address Table.
  225. * The EAT table is stored in linker's VM in area AREAEAT. The
  226. * global variable cbEntTab always points to free space in the
  227. * AREAEAT.
  228. */
  229. eatEntry = 0L;
  230. if ((prevEntryOrd != 0) && (ord > prevEntryOrd + 1))
  231. {
  232. // Write unused entries in the Export Address Table
  233. for (; prevEntryOrd < ord - 1; prevEntryOrd++)
  234. {
  235. if (cbEntTab + sizeof(DWORD) > MEGABYTE)
  236. Fatal(ER_eatovf, MEGABYTE);
  237. vmmove(sizeof(DWORD), &eatEntry, (long)(AREAEAT + cbEntTab), TRUE);
  238. cbEntTab += sizeof(DWORD);
  239. }
  240. }
  241. prevEntryOrd = ord;
  242. // FLAT address
  243. eatEntry = mpsaBase[sa] + ra;
  244. /* Check for Entry Table overflow */
  245. if (cbEntTab + sizeof(DWORD) > MEGABYTE)
  246. Fatal(ER_eatovf, MEGABYTE);
  247. #endif
  248. /* Insert the new entry */
  249. #if NOT EXE386
  250. if (tyCurBnd != tyEntry || ceCurBnd == BNDMAX)
  251. NewBundle(tyEntry); /* Make a new bundle if needed */
  252. ++ceCurBnd; /* Increment counter */
  253. #endif
  254. /* Save entry in virtual memory */
  255. #if EXE386
  256. vmmove(sizeof(DWORD), &eatEntry, (long)(AREAEAT + cbEntTab), TRUE);
  257. #else
  258. AddEntry(entry, cbEntry);
  259. #endif
  260. ep = (EPTYPE FAR *) GetMem(sizeof(EPTYPE));
  261. ep->ep_next = htsaraep[hi]; /* Link old chain to new node */
  262. ep->ep_sa = sa; /* Save the file segment number */
  263. ep->ep_ra = ra; /* Save offset */
  264. ep->ep_ord = ord; /* Save Entry Table ordinal */
  265. htsaraep[hi] = ep; /* Make new node head of chain */
  266. }
  267. /****************************************************************
  268. * *
  269. * NAME: MpSaRaEto *
  270. * *
  271. * DESCRIPTION: *
  272. * *
  273. * This function returns an Entry Table ordinal given a *
  274. * file segment number (sa) for a segment and an offset in *
  275. * that segment. *
  276. * *
  277. * ARGUMENTS: *
  278. * *
  279. * SATYPE sa File segment number *
  280. * RATYPE ra Offset *
  281. * *
  282. * RETURNS: *
  283. * *
  284. * WORD Entry Table ordinal *
  285. * *
  286. * SIDE EFFECTS: *
  287. * *
  288. * Calls NewEntry(). Increments ordMac. *
  289. * *
  290. * NOTE: THIS FUNCTION CALLS THE VIRTUAL MEMORY MANAGER. *
  291. * *
  292. ****************************************************************/
  293. WORD NEAR MpSaRaEto(sa,ra)
  294. SATYPE sa; /* File segment number */
  295. RATYPE ra; /* Segment offset */
  296. {
  297. WORD hi; /* Hash table index */
  298. EPTYPE FAR *ep; /* Entry point node */
  299. hi = hashra(ra); /* Hash the offset */
  300. for (ep = htsaraep[hi]; ep != NULL; ep = ep->ep_next)
  301. { /* Loop through hash chain */
  302. if (ep->ep_sa == sa && ep->ep_ra == ra)
  303. return(ep->ep_ord);
  304. /* If match found, return number */
  305. }
  306. // At this point, we know a new entry must be created.
  307. NewEntry(sa, ra, 0, hi, ++ordMac); /* Add a new entry */
  308. return(ordMac); /* Return Entry Table ordinal */
  309. }
  310. /****************************************************************
  311. * *
  312. * NAME: BuildList *
  313. * *
  314. * DESCRIPTION: *
  315. * *
  316. * This function links the property cells of exports with *
  317. * preassigned ordinals into list. Global pointers pMinOrd *
  318. * and pMaxOrd points to the begin and end of this list. The *
  319. * preassigned ordinals are stored in the set pointed by the *
  320. * global pointer pOrdinalSet. *
  321. * *
  322. * ARGUMENTS: *
  323. * *
  324. * WORD NewOrd New preassigned ordinal *
  325. * RBTYPE NewProp Addr of property cell *
  326. * *
  327. * RETURNS: *
  328. * *
  329. * TRUE if ordinal seen for the first time, otherwise FALSE. *
  330. * *
  331. * SIDE EFFECTS: *
  332. * *
  333. * Changes pMinOrd and pMaxOrd pointers, sets bits in ordinal *
  334. * set and sets MinOrd, MaxOrd seen so far. *
  335. * *
  336. ****************************************************************/
  337. LOCAL WORD NEAR BuildList(WORD NewOrd, RBTYPE NewProp)
  338. {
  339. RBTYPE pTemp; /* Temporary pointer to property cell */
  340. APROPEXPPTR pExpCurr; /* Export record pointer */
  341. APROPEXPPTR pExpPrev; /* Export record pointer */
  342. if (!MinOrd && !MaxOrd)
  343. { /* First time call */
  344. MinOrd = MaxOrd = NewOrd;
  345. pMinOrd = pMaxOrd = NewProp;
  346. SetBit(NewOrd);
  347. return TRUE;
  348. }
  349. if (IsInSet(NewOrd))
  350. return FALSE; /* Ordinal all ready used */
  351. SetBit(NewOrd); /* Set bit in ordinal set */
  352. if (NewOrd > MaxOrd)
  353. { /* Add new at the list end */
  354. pExpCurr = (APROPEXPPTR ) FetchSym(pMaxOrd,TRUE);
  355. pExpCurr->ax_NextOrd = NewProp;
  356. MARKVP();
  357. pMaxOrd = NewProp;
  358. MaxOrd = NewOrd;
  359. pExpCurr = (APROPEXPPTR ) FetchSym(NewProp,TRUE);
  360. pExpCurr->ax_NextOrd = NULL;
  361. MARKVP();
  362. }
  363. else if (NewOrd < MinOrd)
  364. { /* Add new at list begin */
  365. pExpCurr = (APROPEXPPTR ) FetchSym(NewProp,TRUE);
  366. pExpCurr->ax_NextOrd = pMinOrd;
  367. MARKVP();
  368. pMinOrd = NewProp;
  369. MinOrd = NewOrd;
  370. }
  371. else
  372. { /* Add new in the middle of list */
  373. pTemp = pMinOrd;
  374. do
  375. {
  376. pExpPrev = (APROPEXPPTR ) FetchSym(pTemp,TRUE);
  377. pExpCurr = (APROPEXPPTR ) FetchSym(pExpPrev->ax_NextOrd,TRUE);
  378. if (NewOrd < pExpCurr->ax_ord)
  379. {
  380. pTemp = pExpPrev->ax_NextOrd;
  381. pExpPrev->ax_NextOrd = NewProp;
  382. MARKVP();
  383. pExpCurr = (APROPEXPPTR ) FetchSym(NewProp,TRUE);
  384. pExpCurr->ax_NextOrd = pTemp;
  385. MARKVP();
  386. break;
  387. }
  388. pTemp = pExpPrev->ax_NextOrd;
  389. } while (pTemp);
  390. }
  391. if(NewOrd > ordMac) ordMac = NewOrd; /* Remember largest ordinal */
  392. return TRUE;
  393. }
  394. /****************************************************************
  395. * *
  396. * NAME: FindFreeRange *
  397. * *
  398. * DESCRIPTION: *
  399. * *
  400. * This function finds in the ordinal set first available *
  401. * free range of ordinals. *
  402. * *
  403. * ARGUMENTS: *
  404. * *
  405. * Nothing. *
  406. * *
  407. * RETURNS: *
  408. * *
  409. * TRUE if free range found, otherwise FALSE. *
  410. * *
  411. * SIDE EFFECTS: *
  412. * *
  413. * Changes FreeRange descriptor by setting first free ordinal *
  414. * and the lenght of range. *
  415. * *
  416. ****************************************************************/
  417. LOCAL WORD NEAR FindFreeRange(void)
  418. {
  419. int ByteIndex;
  420. int BitIndex;
  421. ByteIndex = FreeRange.ord >> 3;
  422. BitIndex = FreeRange.ord & 0x07;
  423. while ((pOrdinalSet[ByteIndex] & BitMask[BitIndex]) &&
  424. ByteIndex < MaxIndex)
  425. { /* Skip all used ordinals */
  426. FreeRange.ord++;
  427. BitIndex = (BitIndex + 1) & 0x07;
  428. if (!BitIndex)
  429. ByteIndex++;
  430. }
  431. if (ByteIndex < MaxIndex)
  432. {
  433. if (FreeRange.ord > MaxOrd)
  434. {
  435. FreeRange.count = 0xffff - MaxOrd;
  436. return TRUE;
  437. }
  438. do
  439. { /* Count all unused ordinals */
  440. FreeRange.count++;
  441. BitIndex = (BitIndex + 1) & 0x07;
  442. if (!BitIndex)
  443. ByteIndex++;
  444. } while (!(pOrdinalSet[ByteIndex] & BitMask[BitIndex]) &&
  445. ByteIndex < MaxIndex);
  446. return TRUE;
  447. }
  448. return FALSE;
  449. }
  450. /****************************************************************
  451. * *
  452. * NAME: Insert *
  453. * *
  454. * DESCRIPTION: *
  455. * *
  456. * This function inserts into the exports list new property *
  457. * cell without preassigned ordinal. It assigns new ordinal. *
  458. * *
  459. * ARGUMENTS: *
  460. * *
  461. * RBTYPE NewProp New property cell to insert *
  462. * *
  463. * RETURNS: *
  464. * *
  465. * New assigned ordinal. *
  466. * *
  467. * SIDE EFFECTS: *
  468. * *
  469. * Changes FreeRange descriptor and MaxOrd assigned so far. *
  470. * *
  471. ****************************************************************/
  472. LOCAL WORD NEAR Insert(RBTYPE NewProp)
  473. {
  474. APROPEXPPTR pExpCurr; /* Export record pointer */
  475. APROPEXPPTR pExpPrev; /* Export record pointer */
  476. WORD NewOrd;
  477. RBTYPE pTemp, rbPrev, rbCur;
  478. /*
  479. * On entry, pStart points to the place in the export list where
  480. * NewProp should be inserted. If NULL, the list is empty.
  481. */
  482. if (!FreeRange.count)
  483. {
  484. /* No more space left in current free range; find the next one. */
  485. if (!FindFreeRange())
  486. Fatal(ER_expmax);
  487. /*
  488. * Update pStart (the insertion point) by walking down the list and
  489. * finding the first element whose ordinal is greater than the new
  490. * ordinal, or the end of the list if none is found.
  491. */
  492. rbPrev = RHTENIL;
  493. for (rbCur = pStart; rbCur != RHTENIL; rbCur = pExpCurr->ax_NextOrd)
  494. {
  495. pExpCurr = (APROPEXPPTR) FetchSym(rbCur, FALSE);
  496. if (pExpCurr->ax_ord > FreeRange.ord)
  497. break;
  498. rbPrev = rbCur;
  499. }
  500. /* Set pStart to the insertion point. */
  501. pStart = rbPrev;
  502. }
  503. /* Insert new property cell */
  504. NewOrd = FreeRange.ord++;
  505. FreeRange.count--;
  506. SetBit(NewOrd);
  507. pExpCurr = (APROPEXPPTR ) FetchSym(NewProp,TRUE);
  508. pExpCurr->ax_ord = NewOrd;
  509. MARKVP();
  510. if (pStart != NULL)
  511. {
  512. // We're not inserting at head of list. Append new cell to previous
  513. // cell.
  514. pExpPrev = (APROPEXPPTR ) FetchSym(pStart,TRUE);
  515. pTemp = pExpPrev->ax_NextOrd;
  516. pExpPrev->ax_NextOrd = NewProp;
  517. MARKVP();
  518. }
  519. else
  520. {
  521. // We're inserting at head of list. Set head list pointer to new
  522. // cell.
  523. pTemp = pMinOrd;
  524. pMinOrd = NewProp;
  525. }
  526. /*
  527. * Set the next pointer to the following element in the list.
  528. */
  529. pExpCurr = (APROPEXPPTR ) FetchSym(NewProp,TRUE);
  530. pExpCurr->ax_NextOrd = pTemp;
  531. MARKVP();
  532. /*
  533. * Update MaxOrd and pStart.
  534. */
  535. if (NewOrd > MaxOrd)
  536. MaxOrd++;
  537. pStart = NewProp;
  538. return NewOrd;
  539. }
  540. /****************************************************************
  541. * *
  542. * NAME: SavExp1 *
  543. * *
  544. * DESCRIPTION: *
  545. * *
  546. * This function places the virtual addresses of property *
  547. * cells for exports with preassigned ordinals into a table *
  548. * which will later be used to create the first part of the *
  549. * entry table. It also verifies the validity of the ex- *
  550. * ports. *
  551. * *
  552. * ARGUMENTS: *
  553. * *
  554. * APROPEXPPTR apropexp Export record pointer *
  555. * RBTYPE rhte Addr of hash table entry *
  556. * RBTYPE rprop Address of export record *
  557. * FTYPE fNewHte New hash table entry flag *
  558. * *
  559. * RETURNS: *
  560. * *
  561. * Nothing. *
  562. * *
  563. * SIDE EFFECTS: *
  564. * *
  565. * Entries are made in a table on the stack to which the *
  566. * local static variable prb points. The global variable *
  567. * ordMac is set to the highest ordinal value found. Pro- *
  568. * perty cells for exports are updated to contain the file *
  569. * segment number and offset of the entry point. *
  570. * *
  571. * NOTE: THIS FUNCTION CALLS THE VIRTUAL MEMORY MANAGER. *
  572. * *
  573. ****************************************************************/
  574. LOCAL void SavExp1(APROPNAMEPTR apropexp,
  575. RBTYPE rhte,
  576. RBTYPE rprop,
  577. WORD fNewHte)
  578. {
  579. AHTEPTR ahte; /* Pointer to hash table entry */
  580. LOCAL APROPNAMEPTR apropnam; /* Public definition record pointer */
  581. LOCAL APROPPTR aprop; /* temp. pointer */
  582. WORD ord; /* Entry ordinal */
  583. SATYPE sa; /* File segment number */
  584. RATYPE ra; /* Offset in segment */
  585. WORD fStartSeen=0; /* Have we seen the start of the list */
  586. APROPEXPPTR pExport;
  587. char *p;
  588. ASSERT(fNewHte); /* Only once per customer */
  589. pExport = (APROPEXPPTR ) apropexp;
  590. if((ord = pExport->ax_ord) >= EXPMAX)
  591. { /* If ordinal too big */
  592. pExport->ax_ord = 0; /* Treat as unspecified */
  593. ord = 0;
  594. MARKVP(); /* Page has changed */
  595. /* Issue error message */
  596. ahte = (AHTEPTR ) FetchSym(rhte,FALSE);
  597. OutError(ER_ordmax,1 + GetFarSb(ahte->cch));
  598. }
  599. apropnam = (APROPNAMEPTR ) FetchSym(pExport->ax_symdef,FALSE);
  600. /* Fetch the public symbol def. */
  601. for (aprop = (APROPPTR) apropnam; aprop->a_attr != ATTRPNM;)
  602. {
  603. if(aprop->a_attr == ATTRALIAS) /* If an alias */
  604. {
  605. aprop = (APROPPTR) FetchSym(
  606. ((APROPALIASPTR)aprop)->al_sym, FALSE );
  607. if (aprop->a_attr == ATTRPNM) /* The substitute is a public-OK */
  608. break;
  609. }
  610. aprop = (APROPPTR) FetchSym (aprop->a_next, FALSE);
  611. if (aprop->a_next == NULL && aprop->a_attr == ATTRNIL) /* Beginning of list */
  612. {
  613. aprop = (APROPPTR) FetchSym ( ((AHTEPTR)aprop)->rprop, FALSE);
  614. fStartSeen ++;
  615. }
  616. if ((aprop != (APROPPTR) apropnam) && (fStartSeen<2))
  617. continue; /* Find an ALIAS or the starting point */
  618. /* Issue error message */
  619. if(SbCompare(GetPropName(FetchSym(rhte,FALSE)), GetPropName(FetchSym(pExport->ax_symdef,FALSE)), 0))
  620. {
  621. /* skip the (alias %s) part */
  622. OutError(ER_expund,1 + GetPropName(FetchSym(rhte,FALSE)), " ");
  623. }
  624. else
  625. {
  626. if(p = GetMem(SBLEN + 20))
  627. sprintf(p, " (alias %s) ", 1 + GetPropName(FetchSym(pExport->ax_symdef,FALSE)));
  628. OutError(ER_expund,1 + GetPropName(FetchSym(rhte,FALSE)),p);
  629. if(p) FreeMem(p);
  630. }
  631. /* Flag export as undefined */
  632. pExport = (APROPEXPPTR ) FetchSym(rprop,TRUE);
  633. pExport->ax_symdef = RHTENIL;
  634. return;
  635. }
  636. apropnam = (APROPNAMEPTR) aprop;
  637. sa = mpsegsa[mpgsnseg[apropnam->an_gsn]];
  638. /* Get the file segment number */
  639. ra = apropnam->an_ra; /* Get the offset in the segment */
  640. #if NOT EXE386
  641. if(apropnam->an_flags & FIMPORT) /* If public is an import */
  642. {
  643. /* Issue error message */
  644. OutError(ER_expimp,1 + GetPropName(FetchSym(rhte,FALSE)),
  645. 1 + GetPropName(FetchSym(pExport->ax_symdef,FALSE)));
  646. /* Flag export as undefined */
  647. pExport = (APROPEXPPTR ) FetchSym(rprop,TRUE);
  648. pExport->ax_symdef = RHTENIL;
  649. return;
  650. }
  651. if (!IsIOPL(mpsaflags[sa])) /* If not I/O privileg segment */
  652. pExport->ax_flags &= 0x07; /* force parameter words to 0 */
  653. #endif
  654. pExport = (APROPEXPPTR ) FetchSym(rprop,TRUE);
  655. /* Fetch the export property cell */
  656. pExport->ax_sa = sa; /* Set the file segment number */
  657. pExport->ax_ra = ra; /* Set the offset in the segment */
  658. MARKVP();
  659. if(ord == 0) return; /* Skip unspecified ordinals for now */
  660. if(!BuildList(ord, rprop)) /* If ordinal conflict found */
  661. {
  662. /*
  663. * Issue error message for ordinal conflict
  664. */
  665. OutError(ER_ordmul,ord,1 + GetPropName(FetchSym(rhte,FALSE)));
  666. return;
  667. }
  668. }
  669. /****************************************************************
  670. * *
  671. * NAME: SavExp2 *
  672. * *
  673. * DESCRIPTION: *
  674. * *
  675. * This function enters those exports without preassigned *
  676. * ordinal numbers into the table to which prb refers. It *
  677. * also builds the resident and non-resident name tables. *
  678. * *
  679. * ARGUMENTS: *
  680. * *
  681. * APROPEXPPTR apropexp Export record pointer *
  682. * RBTYPE rhte Addr of hash table entry *
  683. * RBTYPE rprop Address of export record *
  684. * FTYPE fNewHte New hash table entry flag *
  685. * *
  686. * RETURNS: *
  687. * *
  688. * Nothing. *
  689. * *
  690. * SIDE EFFECTS: *
  691. * *
  692. * Entries are made in a table in virtual memory. A global *
  693. * variable is set to contain the highest ordinal value seen. *
  694. * *
  695. * NOTE: THIS FUNCTION CALLS THE VIRTUAL MEMORY MANAGER. *
  696. * *
  697. ****************************************************************/
  698. LOCAL void SavExp2(APROPNAMEPTR apropexp,
  699. RBTYPE rhte,
  700. RBTYPE rprop,
  701. WORD fNewHte)
  702. {
  703. AHTEPTR ahte; /* Pointer to hash table entry */
  704. APROPNAMEPTR apropnam; /* Public definition record pointer */
  705. WORD ord; /* Ordinal number */
  706. WORD cb; /* # of bytes in name table entry */
  707. SATYPE sa; /* File segment number */
  708. FTYPE fResNam; /* True if name is resident */
  709. FTYPE fNoName; /* True if discard name */
  710. APROPEXPPTR pExport;
  711. SBTYPE sbName;
  712. pExport = (APROPEXPPTR ) apropexp;
  713. if (pExport->ax_symdef == RHTENIL) return;
  714. /* Skip undefined exports */
  715. apropnam = (APROPNAMEPTR ) FetchSym(pExport->ax_symdef,FALSE);
  716. /* Fetch the public symbol def. */
  717. sa = mpsegsa[mpgsnseg[apropnam->an_gsn]];
  718. /* Get the file segment number */
  719. #if NOT EXE386
  720. if (!IsIOPL(mpsaflags[sa])) /* If not I/O privileg segment */
  721. pExport->ax_flags &= 0x07; /* force parameter words to 0 */
  722. #endif
  723. if ((ord = pExport->ax_ord) == 0) /* If unassigned export found */
  724. {
  725. ord = Insert(rprop); /* Add new export to the list */
  726. fResNam = (FTYPE) TRUE; /* Name is resident */
  727. }
  728. else
  729. fResNam = (FTYPE) ((pExport->ax_nameflags & RES_NAME) != 0);
  730. /* Else set resident name flag */
  731. fNoName = (FTYPE) ((pExport->ax_nameflags & NO_NAME) != 0);
  732. ahte = (AHTEPTR ) FetchSym(rhte,FALSE);
  733. /* Get external name */
  734. cb = B2W(ahte->cch[0]) + 1; /* Number of bytes incl. length byte */
  735. #if EXE386
  736. /*
  737. * For linear-executable build the Export Name Pointers Table and
  738. * Export Name Table. For linear-executable all exported names
  739. * are put in one Exported Name Table; there is no distiction
  740. * between resident and non-resident tables. We still support
  741. * the NONAME keyword by removing the exported name
  742. * from the Export Name Table.
  743. */
  744. if (!fNoName)
  745. {
  746. if (cb > sizeof(sbName) - sizeof(BYTE))
  747. cb = sizeof(sbName) - sizeof(BYTE);
  748. memcpy(sbName, GetFarSb(ahte->cch), cb + 1);
  749. /* Copy the name to local buffer */
  750. if (fIgnoreCase)
  751. SbUcase(sbName); /* Make upper case if ignoring case */
  752. // Store the pointer to the name; for now it is an offset from
  753. // the begin of Export Name Table (be sure that name doesn't
  754. // cross VM page boundary). Later when the size of the
  755. // Export Directory Table plus the size of Export Address Table
  756. // becomes known we update the entries in the Export Name Pointer
  757. // Table to become a relative virtual address from the Export
  758. // Directory Table.
  759. if ((cbExpName & (PAGLEN - 1)) + cb > PAGLEN)
  760. cbExpName = (cbExpName + PAGLEN - 1) & ~(PAGLEN - 1);
  761. vmmove(sizeof(DWORD), &cbExpName, AREANAMEPTR + cbNamePtr, TRUE);
  762. cbNamePtr += sizeof(DWORD);
  763. if (cbNamePtr > NAMEPTRSIZE)
  764. Fatal(ER_nameptrovf, NAMEPTRSIZE);
  765. // Store exported name
  766. vmmove(cb, &sbName[1], AREAEXPNAME + cbExpName, TRUE);
  767. cbExpName += cb;
  768. if (cbExpName > EXPNAMESIZE)
  769. Fatal(ER_expnameovf, EXPNAMESIZE);
  770. }
  771. #else
  772. /* Add exported name to segmented-executable name tables */
  773. if (fResNam || !fNoName)
  774. {
  775. if (cb > sizeof(sbName) - sizeof(BYTE))
  776. cb = sizeof(sbName) - sizeof(BYTE);
  777. memcpy(sbName, GetFarSb(ahte->cch), cb + 1);
  778. /* Copy the name to local buffer */
  779. if (fIgnoreCase
  780. #if NOT OUT_EXP
  781. || TargetOs == NE_WINDOWS
  782. #endif
  783. )
  784. SbUcase(sbName); /* Make upper case if ignoring case */
  785. AddName(fResNam ? &ResidentName : &NonResidentName,
  786. sbName, ord);
  787. }
  788. #endif
  789. }
  790. #pragma check_stack(on)
  791. void NEAR InitEntTab()
  792. {
  793. BYTE OrdinalSet[MaxIndex];
  794. /* Ordinal numbers set */
  795. #if NOT EXE386
  796. APROPEXPPTR exp; /* Pointer to export property cell */
  797. #endif
  798. WORD i; /* Index */
  799. tyCurBnd = 0xFFFF; /* Won't match any legal types */
  800. ceCurBnd = 0; /* No entries yet */
  801. offCurBnd = 0; /* First bundle at beginning */
  802. ordMac = 0; /* Assume no exported entries */
  803. pOrdinalSet = OrdinalSet; /* Set global pointer */
  804. memset(OrdinalSet,0,MaxIndex*sizeof(BYTE));
  805. /* Initialize set to empty */
  806. EnSyms(SavExp1,ATTREXP); /* Enumerate exports with ordinals */
  807. FreeRange.ord = 1; /* Initialize free range of ordinals */
  808. FreeRange.count = 0;
  809. pStart = pMinOrd;
  810. EnSyms(SavExp2,ATTREXP); /* Enumerate exports without ordinals */
  811. if (MaxOrd > ordMac)
  812. ordMac = MaxOrd;
  813. pStart = pMinOrd;
  814. for(i = 1; i <= ordMac && pStart != NULL; ++i)
  815. { /* Loop to start Entry Table */
  816. #if EXE386
  817. pExport = (APROPEXPPTR ) FetchSym(pStart,FALSE);
  818. /* Fetch symbol from virtual memory */
  819. pStart = pExport->ax_NextOrd; /* Go down on list */
  820. NewEntry(pExport->ax_sa, pExport->ax_ra, pExport->ax_flags,
  821. hashra(pExport->ax_ra), pExport->ax_ord);
  822. #else
  823. if(NotInSet(i)) /* If a hole found */
  824. {
  825. if (tyCurBnd != BNDNIL || ceCurBnd == BNDMAX)
  826. NewBundle(BNDNIL);
  827. /* Make a new bundle if needed */
  828. ++ceCurBnd; /* Increment counter */
  829. continue; /* Next iteration */
  830. }
  831. exp = (APROPEXPPTR ) FetchSym(pStart,FALSE);
  832. /* Fetch symbol from virtual memory */
  833. pStart = exp->ax_NextOrd; /* Go down on list */
  834. NewEntry(exp->ax_sa,exp->ax_ra,exp->ax_flags,hashra(exp->ax_ra),i);
  835. #endif
  836. /* Create Entry Table entry */
  837. }
  838. #if EXE386
  839. SortPtrTable();
  840. pExport = NULL;
  841. #endif
  842. }
  843. #pragma check_stack(off)
  844. #if NOT EXE386
  845. /****************************************************************
  846. * *
  847. * NAME: OutEntTab *
  848. * *
  849. * DESCRIPTION: *
  850. * *
  851. * This function writes the Entry Table to the executable *
  852. * file. First it writes an empty bundle to mark the end of *
  853. * the table. *
  854. * *
  855. * ARGUMENTS: *
  856. * *
  857. * None *
  858. * *
  859. * RETURNS: *
  860. * *
  861. * Nothing. *
  862. * *
  863. * SIDE EFFECTS: *
  864. * *
  865. * A table is written to the file specified by the global *
  866. * file pointer, bsRunfile. This function calls OutVm(), *
  867. * which CALLS THE VIRTUAL MEMORY MANAGER. *
  868. * *
  869. ****************************************************************/
  870. void NEAR OutEntTab()
  871. {
  872. NewBundle(ET_END); /* Append an empty bundle */
  873. WriteByteArray(&EntryTable); /* Write the table */
  874. }
  875. #endif
  876. #endif /* NOT QCLINK */
  877. #if NOT EXE386
  878. /****************************************************************
  879. * *
  880. * NAME: MatchRlc *
  881. * *
  882. * DESCRIPTION: *
  883. * *
  884. * This function compares two relocation records and returns *
  885. * TRUE if they match. Two records are said to match if they *
  886. * agree on the fixup type and the target specification. The *
  887. * location being fixed up does not have to match. *
  888. * *
  889. * ARGUMENTS: *
  890. * *
  891. * struct new_rlc *rlcp0 Ptr to relocation record *
  892. * struct new_rlc *rlcp1 Ptr to relocation record *
  893. * *
  894. * RETURNS: *
  895. * *
  896. * FTYPE *
  897. * *
  898. * SIDE EFFECTS: *
  899. * *
  900. * None. *
  901. * *
  902. ****************************************************************/
  903. LOCAL WORD NEAR MatchRlc(rlcp0,rlcp1)
  904. RLCPTR rlcp0; /* Ptr to struct new_rlc record */
  905. RLCPTR rlcp1; /* Ptr to struct new_rlc record */
  906. {
  907. if(NR_STYPE(*rlcp0) != NR_STYPE(*rlcp1) ||
  908. NR_FLAGS(*rlcp0) != NR_FLAGS(*rlcp1)) return(FALSE);
  909. /* Check flags and type */
  910. if((NR_FLAGS(*rlcp0) & NRRTYP) == NRRINT)
  911. { /* If internal reference */
  912. return((NR_SEGNO(*rlcp0) == NR_SEGNO(*rlcp1)) &&
  913. (NR_ENTRY(*rlcp0) == NR_ENTRY(*rlcp1)));
  914. /* Check internal references */
  915. }
  916. return((NR_MOD(*rlcp0) == NR_MOD(*rlcp1)) &&
  917. (NR_PROC(*rlcp0) == NR_PROC(*rlcp1)));
  918. /* Check imports */
  919. }
  920. /****************************************************************
  921. * *
  922. * NAME: SaveFixup *
  923. * *
  924. * DESCRIPTION: *
  925. * *
  926. * This function saves a fixup record for emission later. In *
  927. * addition, if the fixup is not additive, it builds chains. *
  928. * *
  929. * ARGUMENTS: *
  930. * *
  931. * SATYPE saLoc Segment of location to fix *
  932. * relocation *rlcp Ptr to relocation record *
  933. * *
  934. * RETURNS: *
  935. * *
  936. * RATYPE *
  937. * Returns the previous head of the fixup chain so that it *
  938. * can be stuffed into the location being fixed up. If the *
  939. * fixup is additive, however, it always returns EOC. *
  940. * *
  941. ****************************************************************/
  942. RATYPE NEAR SaveFixup(SATYPE saLoc, RLCPTR rlcp)
  943. {
  944. WORD hi; // Hash index
  945. RLCHASH FAR *pHt; // Hash table
  946. RLCBUCKET FAR *pBucket; // Relocation bucket
  947. WORD fi; // fixup bucket index
  948. RLCPTR pRlc; // Pointer to relocation record
  949. WORD tmp;
  950. RATYPE ra;
  951. void FAR *pTmp;
  952. #ifndef UNPOOLED_RELOCS
  953. if (pPoolRlc == NULL)
  954. pPoolRlc = PInit();
  955. #endif
  956. if (mpsaRlc[saLoc] == NULL)
  957. {
  958. // Allocate hash vector for physical segment saLoc
  959. #ifndef UNPOOLED_RELOCS
  960. mpsaRlc[saLoc] = (RLCHASH FAR *) PAlloc(pPoolRlc, sizeof(RLCHASH));
  961. #else
  962. mpsaRlc[saLoc] = (RLCHASH FAR *) GetMem(sizeof(RLCHASH));
  963. #endif
  964. }
  965. pHt = mpsaRlc[saLoc];
  966. tmp = hashrlc(rlcp);
  967. hi = (WORD) tmp;
  968. pBucket = pHt->hash[hi];
  969. #if FALSE
  970. if (saLoc == 2 && hi == 8)
  971. {
  972. fprintf(stdout, "Storing fixup for segment: %d\r\n", saLoc);
  973. fprintf(stdout, " Source offset: %x; type: %x\r\n", NR_SOFF(*rlcp), NR_STYPE(*rlcp));
  974. fprintf(stdout, " Hash index: %d\r\n", hi);
  975. }
  976. #endif
  977. if (pBucket && !(NR_FLAGS(*rlcp) & NRADD))
  978. {
  979. // For non-additive fixups search the bucket for
  980. // matching relocation records
  981. for(fi = 0; fi < pBucket->count; fi++)
  982. {
  983. pRlc = &(pBucket->rgRlc[fi]);
  984. if (MatchRlc(pRlc, rlcp))
  985. {
  986. // Relocation records match - chain them
  987. ra = (WORD) NR_SOFF(*pRlc);
  988. // Save previous head of chain
  989. NR_SOFF(*pRlc) = NR_SOFF(*rlcp);
  990. // Insert new head of chain
  991. #if FALSE
  992. if (saLoc == 2 && hi == 8)
  993. fprintf(stdout, " Match found with fixup @%x\r\n", ra);
  994. #endif
  995. return(ra); // Return previous head of chain
  996. }
  997. }
  998. }
  999. // At this point, we know we have to add a new entry
  1000. // to the bucket we are examining.
  1001. pHt->count++; // Increment count of fixups per segment
  1002. #if FALSE
  1003. if (saLoc == 2 && hi == 8)
  1004. fprintf(stdout, " New entry; Count: %d\r\n", pHt->count);
  1005. #endif
  1006. // Check space in the bucket
  1007. if (pBucket == NULL)
  1008. {
  1009. // Allocate new fixup bucket
  1010. #ifndef UNPOOLED_RELOCS
  1011. pBucket = (RLCBUCKET FAR *) PAlloc(pPoolRlc, sizeof(RLCBUCKET));
  1012. pBucket->rgRlc = (RLCPTR) PAlloc(pPoolRlc, BUCKET_DEF * sizeof(RELOCATION));
  1013. #else
  1014. pBucket = (RLCBUCKET FAR *) GetMem(sizeof(RLCBUCKET));
  1015. pBucket->rgRlc = (RLCPTR) GetMem(BUCKET_DEF * sizeof(RELOCATION));
  1016. #endif
  1017. pBucket->countMax = BUCKET_DEF;
  1018. pHt->hash[hi] = pBucket;
  1019. }
  1020. else if (pBucket->count >= pBucket->countMax)
  1021. {
  1022. // Realloc fixup bucket
  1023. #ifndef UNPOOLED_RELOCS
  1024. // REVIEW: for now we just throw away the old memory, we'll free
  1025. // REVIEW: it later, we do this infrequently anyways...
  1026. pTmp = PAlloc(pPoolRlc, (pBucket->countMax << 1) * sizeof(RELOCATION));
  1027. FMEMCPY(pTmp, pBucket->rgRlc, pBucket->countMax * sizeof(RELOCATION));
  1028. // FFREE(pBucket->rgRlc); NOT MUCH MEMORY WASTED HERE
  1029. #else
  1030. pTmp = GetMem((pBucket->countMax << 1) * sizeof(RELOCATION));
  1031. FMEMCPY(pTmp, pBucket->rgRlc, pBucket->countMax * sizeof(RELOCATION));
  1032. FFREE(pBucket->rgRlc);
  1033. #endif
  1034. pBucket->rgRlc = pTmp;
  1035. pBucket->countMax <<= 1;
  1036. }
  1037. // Add new relocation record at the end of bucket
  1038. NR_RES(*rlcp) = '\0'; // Zero the reserved field
  1039. pBucket->rgRlc[pBucket->count] = *rlcp;
  1040. ++pBucket->count; // Increment count of fixups
  1041. return(EOC); // Return end-of-chain marker
  1042. }
  1043. /****************************************************************
  1044. * *
  1045. * NAME: OutFixTab *
  1046. * *
  1047. * DESCRIPTION: *
  1048. * *
  1049. * This fuction writes the load-time relocation (fixup) table *
  1050. * for a given file segment to the execuatble file. *
  1051. * *
  1052. * ARGUMENTS: *
  1053. * *
  1054. * SATYPE sa File segment number *
  1055. * *
  1056. * RETURNS: *
  1057. * *
  1058. * Nothing. *
  1059. * *
  1060. * SIDE EFFECTS: *
  1061. * *
  1062. * A table is written to the file specified by the global *
  1063. * file pointer, bsRunfile. *
  1064. * *
  1065. ****************************************************************/
  1066. void NEAR OutFixTab(SATYPE sa)
  1067. {
  1068. WORD hi; // Hash table index
  1069. RLCHASH FAR *pHt;
  1070. RLCBUCKET FAR *pBucket;
  1071. pHt = mpsaRlc[sa];
  1072. WriteExe(&(pHt->count), CBWORD); // Write the number of relocations
  1073. for (hi = 0; hi < HASH_SIZE; hi++)
  1074. {
  1075. pBucket = pHt->hash[hi];
  1076. if (pBucket != NULL)
  1077. {
  1078. WriteExe(pBucket->rgRlc, pBucket->count * sizeof(RELOCATION));
  1079. #ifdef UNPOOLED_RELOCS
  1080. FFREE(pBucket->rgRlc);
  1081. #endif
  1082. }
  1083. }
  1084. #ifdef UNPOOLED_RELOCS
  1085. FFREE(pHt);
  1086. #endif
  1087. }
  1088. /****************************************************************
  1089. * *
  1090. * NAME: ReleaseRlcMemory *
  1091. * *
  1092. * DESCRIPTION: *
  1093. * *
  1094. * This function releases the pool(s) of memory that held the *
  1095. * segment relocations *
  1096. * *
  1097. * RETURNS: *
  1098. * *
  1099. * Nothing. *
  1100. * *
  1101. * SIDE EFFECTS: *
  1102. * *
  1103. * pPoolRlc is set to NULL so that we will fail if we should *
  1104. * ever try to allocate more relocations after this point *
  1105. * *
  1106. ****************************************************************/
  1107. void NEAR ReleaseRlcMemory()
  1108. {
  1109. #ifndef UNPOOLED_RELOCS
  1110. // free all the memory associated with the saved relocation
  1111. if (pPoolRlc) {
  1112. PFree(pPoolRlc);
  1113. pPoolRlc = NULL;
  1114. }
  1115. #endif
  1116. }
  1117. #endif /* NOT EXE386 */