Leaked source code of windows server 2003
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.

1767 lines
45 KiB

  1. /* asmemit.c -- microsoft 80x86 assembler
  2. **
  3. ** microsoft (r) macro assembler
  4. ** copyright (c) microsoft corp 1986. all rights reserved
  5. **
  6. ** randy nevin
  7. **
  8. ** 10/90 - Quick conversion to 32 bit by Jeff Spencer
  9. */
  10. #include <stdio.h>
  11. #include <io.h>
  12. #include <string.h>
  13. #include "asm86.h"
  14. #include "asmfcn.h"
  15. #define LINBUFSIZE EMITBUFSIZE - 20 /* line # records can't as big */
  16. #define OMFBYTE(c) *ebufpos++ = (unsigned char)(c)
  17. #define FIXBYTE(c) *efixpos++ = (unsigned char)(c)
  18. #define LINBYTE(c) *elinpos++ = (unsigned char)(c)
  19. #define EBUFOPEN(c) (ebufpos+(c) <= emitbuf+EMITBUFSIZE)
  20. #define EFIXOPEN(c) (efixpos+(c) < efixbuffer+EMITBUFSIZE)
  21. #define ELINOPEN(c) (elinpos+(c) <= elinbuffer+LINBUFSIZE)
  22. UCHAR emitbuf[EMITBUFSIZE];
  23. UCHAR efixbuffer[EMITBUFSIZE];
  24. UCHAR elinbuffer[LINBUFSIZE];
  25. UCHAR *ebufpos = emitbuf;
  26. UCHAR *efixpos = efixbuffer;
  27. UCHAR *elinpos = elinbuffer;
  28. UCHAR ehoffset = 0; /* number of bytes into segment index */
  29. UCHAR emitrecordtype = 0;
  30. OFFSET ecuroffset;
  31. USHORT ecursegment;
  32. long oOMFCur;
  33. SHORT FixupOp = 0;
  34. SHORT LedataOp = 0xA0;
  35. USHORT linSegment;
  36. UCHAR fLineUsed32;
  37. SHORT fUnderScore;
  38. UCHAR fIniter = TRUE;
  39. UCHAR fNoMap; /* hack to disable fixup mapping for CV */
  40. extern PFPOSTRUCT pFpoHead;
  41. extern PFPOSTRUCT pFpoTail;
  42. extern unsigned long numFpoRecords;
  43. VOID CODESIZE edump( VOID );
  44. VOID PASCAL CODESIZE emitoffset( OFFSET, SHORT );
  45. /* The calls to the routines in this module appear in the following group
  46. order. Ordering within a group is unspecified:
  47. Group 1:
  48. emodule (Pname)
  49. Group 2:
  50. emitsymbol (Psymb)
  51. Group 3:
  52. emitsegment (Psymb)
  53. emitglobal (Psymb)
  54. emitextern (Psymb)
  55. Group 4:
  56. emitcbyte (BYTE)
  57. emitobject(pDSC)
  58. emitcword (WORD)
  59. emitdup (???)
  60. Group 5:
  61. emitdone (Psymb)
  62. */
  63. /*** emitsword - feed a word into the buffer
  64. *
  65. * emitsword (w);
  66. *
  67. * Entry w = word to feed into omf buffer
  68. * Exit word placed in buffer low byte first
  69. * Returns none
  70. */
  71. VOID PASCAL CODESIZE
  72. emitsword (
  73. USHORT w
  74. ){
  75. OMFBYTE(w);
  76. OMFBYTE(w >> 8);
  77. }
  78. /* emitoff - write an offset, either 16 or 32 bits, depending upon
  79. * use32. note conditional compilation trick with sizeof(OFFSET).
  80. * with more cleverness, this could be a macro. -Hans */
  81. VOID PASCAL CODESIZE
  82. emitoffset(
  83. OFFSET off,
  84. SHORT use32
  85. ){
  86. emitsword((USHORT)off);
  87. if (sizeof(OFFSET) > 2 && use32)
  88. emitsword((USHORT)highWord(off));
  89. }
  90. /*** emitSymbol - output name string
  91. *
  92. * Entry
  93. * pSY - pointer to symbol table entry to dump
  94. */
  95. VOID PASCAL CODESIZE
  96. emitSymbol(
  97. SYMBOL FARSYM *pSY
  98. ){
  99. if (pSY->attr & M_CDECL)
  100. fUnderScore++;
  101. if (pSY->lcnamp)
  102. emitname ((NAME FAR *)pSY->lcnamp);
  103. else
  104. emitname (pSY->nampnt);
  105. }
  106. /*** emitname - write FAR name preceeded by length into omf buffer
  107. *
  108. * emitname (name);
  109. *
  110. * Entry name = FAR pointer to name string
  111. * Exit length of name followed by name written to omf buffer
  112. * Returns none
  113. */
  114. VOID PASCAL CODESIZE
  115. emitname (
  116. NAME FAR *nam
  117. ){
  118. char FAR *p;
  119. OMFBYTE(STRFLEN ((char FAR *)nam->id)+fUnderScore);
  120. if (fUnderScore) { /* leading _ for C language */
  121. fUnderScore = 0;
  122. OMFBYTE('_');
  123. }
  124. for (p = (char FAR *)nam->id; *p; p++)
  125. OMFBYTE(*p);
  126. }
  127. /*** flushbuffer - write out linker record
  128. *
  129. * flushbuffer ();
  130. *
  131. * Entry ebufpos = next address in emitbuf
  132. * emitbuf = data buffer
  133. * emitrecordtype = type of omf data in buffer
  134. * ehoffset = length of segment index data in buffer
  135. * Exit data written to obj->fil if data in buffer
  136. * buffer set empty (ebufpos = emitbuf)
  137. * segment index length set to 0
  138. * Returns none
  139. */
  140. VOID PASCAL CODESIZE
  141. flushbuffer ()
  142. {
  143. /* Don't put out an empty data record, but can do empty
  144. * anything else */
  145. if ((emitrecordtype&~1) != 0xA0 ||
  146. (ebufpos - emitbuf) != ehoffset) /* RN */
  147. ebuffer (emitrecordtype, ebufpos, emitbuf);
  148. ebufpos = emitbuf;
  149. ehoffset = 0;
  150. }
  151. /*** flushfixup, flushline, write out fixup/line record
  152. *
  153. * flushfixup ();
  154. *
  155. * Entry efixbuffer = fixup buffer
  156. * efixpos = address of next byte in fixup buffer
  157. * Exit fixup buffer written to file if not empty
  158. * fixup buffer set empty (efixpos = efixbuffer)
  159. * Returns none
  160. */
  161. VOID PASCAL CODESIZE
  162. flushfixup ()
  163. {
  164. ebuffer (FixupOp, efixpos, efixbuffer);
  165. FixupOp = 0;
  166. efixpos = efixbuffer;
  167. }
  168. VOID PASCAL CODESIZE
  169. flushline ()
  170. {
  171. USHORT recordT;
  172. recordT = emitrecordtype;
  173. ebuffer ( (USHORT)(fLineUsed32? 0x95: 0x94), elinpos, elinbuffer);
  174. elinpos = elinbuffer;
  175. emitrecordtype = (unsigned char)recordT;
  176. }
  177. /*** emitsetrecordtype - set record type and flush buffers if necessary
  178. *
  179. * emitsetrecordtype (t);
  180. *
  181. * Entry t = type of omf record
  182. * Exit emit and fixup buffers flushed if t != current record type
  183. * segment index written to buffer if data or dup omf record
  184. * emit segment set to current segment
  185. * emit offset set to offset within current segment
  186. * Returns none
  187. */
  188. VOID PASCAL CODESIZE
  189. emitsetrecordtype (
  190. UCHAR t
  191. ){
  192. if (emitrecordtype && emitrecordtype != t) {
  193. /* flush emit and fixup buffers if active and not of same type */
  194. flushbuffer ();
  195. flushfixup ();
  196. switch(t)
  197. {
  198. case 0xA0:
  199. case 0xA1: /* LEDATA or */
  200. case 0xA2: /* LIDATA (dup) record */
  201. case 0xA3:
  202. if (pcsegment) {
  203. /* create a new header */
  204. ecursegment = pcsegment->symu.segmnt.segIndex;
  205. ecuroffset = pcoffset;
  206. emitsindex (pcsegment->symu.segmnt.segIndex);
  207. /* if we are getting to the end of the buffer
  208. * and its a 32 bit segment, we need to start
  209. * using 32 bit offsets in the LEDATA header.
  210. * -Hans */
  211. if (wordsize == 4)
  212. {
  213. if (t>= 0xA2)
  214. t = 0xA3;
  215. /* there is a bug in the current linker--
  216. * all ledata or lidata records within
  217. * a module have to be either 16 or 32.
  218. * comment out optimization until this
  219. * is fixed */
  220. else /* if (pcoffset>0x0ffffL-EMITBUFSIZE) */
  221. LedataOp = t = 0xA1;
  222. }
  223. emitoffset((OFFSET)pcoffset, (SHORT)(t&1));
  224. if (t&1)
  225. ehoffset += 2; /* RN */
  226. break;
  227. }
  228. else
  229. errorc (E_ENS);
  230. default:
  231. break;
  232. }
  233. }
  234. if (t == 0xA4) {
  235. t = 0xA1;
  236. }
  237. emitrecordtype = t;
  238. }
  239. /*** emitsindex - output 'index' of segment, external, etc.
  240. *
  241. * emitsindex (i);
  242. *
  243. * Entry i = index
  244. * Exit index written to emit buffer
  245. * ehoffset = 3 if single byte index
  246. * ehoffset = 4 if double byte index
  247. * Returns none
  248. */
  249. VOID PASCAL CODESIZE
  250. emitsindex (
  251. register USHORT i
  252. ){
  253. ehoffset = 3;
  254. if (i >= 0x80) {
  255. OMFBYTE((i >> 8) + 0x80);
  256. ehoffset++;
  257. }
  258. OMFBYTE(i);
  259. }
  260. /*** emodule - output module name record
  261. *
  262. * emodule (pmodule);
  263. *
  264. * Entry pmodule = pointer to module name
  265. * Exit module name written to obj->fil
  266. * current emit segment and offset set to 0
  267. * Returns none
  268. */
  269. VOID PASCAL CODESIZE
  270. emodule (
  271. NAME FAR *pmodule
  272. ){
  273. char FAR *p;
  274. emitsetrecordtype (0x80);
  275. emitname (pmodule);
  276. flushbuffer ();
  277. if (fDosSeg) {
  278. emitsetrecordtype (0x88);
  279. emitsword((USHORT)(0x9E00 | 0x80)); /* nopurge + class = DOSSEG */
  280. flushbuffer ();
  281. }
  282. if (codeview == CVSYMBOLS){
  283. /* output speical comment record to handle symbol section */
  284. emitsetrecordtype (0x88);
  285. OMFBYTE(0);
  286. emitsword(0x1a1);
  287. emitsword('V'<< 8 | 'C');
  288. flushbuffer ();
  289. }
  290. while (pLib) {
  291. emitsetrecordtype (0x88);
  292. emitsword((USHORT) (0x9F00 | 0x80)); /* nopurge + class = Library*/
  293. for (p = (char FAR *)pLib->text; *p; p++)
  294. OMFBYTE(*p);
  295. flushbuffer ();
  296. pLib = pLib->strnext;
  297. }
  298. ecuroffset = 0; /* initial for pass2 */
  299. ecursegment = 0;
  300. }
  301. /*** emitlname - put symbols into bufer to form 'lnames' record
  302. *
  303. * emitlname (psym);
  304. *
  305. * Entry psym = pointer to symbol structure
  306. * Exit current record type set to LNAMES and buffer flushed if
  307. * necessary. The name string is written to the emit buffer.
  308. * Returns none
  309. */
  310. VOID PASCAL CODESIZE
  311. emitlname (
  312. SYMBOL FARSYM *psym
  313. ){
  314. emitsetrecordtype (0x96);
  315. if (lnameIndex == 3) /* 1st time around */
  316. OMFBYTE(0); /* output the NULL name */
  317. if (!EBUFOPEN(STRFLEN (psym->nampnt->id) + 1)) {
  318. flushbuffer ();
  319. emitsetrecordtype (0x96);
  320. }
  321. emitSymbol(psym);
  322. }
  323. /*** emitsegment - output a segment definition record
  324. *
  325. * emitsegment (pseg);
  326. *
  327. * Entry pseg = pointer to segment name
  328. * Exit record type set to SEGDEF and emit buffer flushed if necessary.
  329. * SEGDEF record written to emit buffer
  330. * Returns none
  331. */
  332. VOID PASCAL CODESIZE
  333. emitsegment (
  334. SYMBOL FARSYM *pseg
  335. ){
  336. UCHAR comb;
  337. UCHAR algn;
  338. SHORT use32=0;
  339. /* use32 is whether to put out 16 or 32 bit offsets. it
  340. * only works if segmnt.use32 is enabled. the D bit
  341. * is keyed off segmnt.use32 -Hans */
  342. if (sizeof(OFFSET)>2 &&
  343. (pseg->symu.segmnt.use32 > 2) &&
  344. pseg->symu.segmnt.seglen > 0xffffL)
  345. use32 = 1;
  346. emitsetrecordtype ((UCHAR)(0x98+use32)); /* SEGDEF */
  347. algn = pseg->symu.segmnt.align;
  348. comb = pseg->symu.segmnt.combine;
  349. #ifdef V386
  350. if (!use32 && pseg->symu.segmnt.seglen == 0x10000L) /* add 'big' bit? */
  351. if (pseg->symu.segmnt.use32 > 2)
  352. OMFBYTE((algn<<5) + (comb<<2) + 3); /* add 'D' bit */
  353. else
  354. OMFBYTE((algn<<5) + (comb<<2) + 2);
  355. else
  356. #endif
  357. if (pseg->symu.segmnt.use32 > 2)
  358. OMFBYTE((algn<<5) + (comb<<2) + 1); /* add 'D' bit */
  359. else
  360. OMFBYTE((algn<<5) + (comb<<2));
  361. if (algn == 0 || algn == (UCHAR)-1) {
  362. /* segment number of seg */
  363. emitsword ((USHORT)pseg->symu.segmnt.locate);
  364. OMFBYTE(0);
  365. }
  366. emitoffset(pseg->symu.segmnt.seglen, use32);
  367. emitsindex (pseg->symu.segmnt.lnameIndex);
  368. pseg->symu.segmnt.segIndex = segmentnum++;
  369. /* seg, class number */
  370. if (!pseg->symu.segmnt.classptr) /* Use blank name */
  371. emitsindex (1);
  372. else
  373. emitsindex((USHORT)((pseg->symu.segmnt.classptr->symkind == SEGMENT) ?
  374. pseg->symu.segmnt.classptr->symu.segmnt.lnameIndex:
  375. pseg->symu.segmnt.classptr->symu.ext.extIndex));
  376. emitsindex (1);
  377. flushbuffer ();
  378. }
  379. /*** emitgroup - output a group record
  380. *
  381. * emitgroup (pgrp);
  382. *
  383. * Entry pgrp = pointer to group name
  384. * Exit
  385. * Returns
  386. * Calls
  387. */
  388. VOID PASCAL CODESIZE
  389. emitgroup (
  390. SYMBOL FARSYM *pgrp
  391. ){
  392. SYMBOL FARSYM *pseg;
  393. emitsetrecordtype (0x9A);
  394. emitsindex (pgrp->symu.grupe.groupIndex);
  395. pgrp->symu.grupe.groupIndex = groupnum++;
  396. pseg = pgrp->symu.grupe.segptr;
  397. while (pseg) {
  398. if (pseg->symu.segmnt.segIndex){
  399. OMFBYTE(((pseg->attr == XTERN)? 0xFE: 0xFF));
  400. emitsindex (pseg->symu.segmnt.segIndex);
  401. }
  402. pseg = pseg->symu.segmnt.nxtseg;
  403. }
  404. flushbuffer ();
  405. }
  406. /*** emitglobal - output a global declaration
  407. *
  408. * emitglobal (pglob);
  409. *
  410. * Entry pglob = pointer to global name
  411. * Exit
  412. * Returns
  413. * Calls
  414. */
  415. VOID PASCAL CODESIZE
  416. emitglobal (
  417. SYMBOL FARSYM *pglob
  418. ){
  419. static SHORT gIndexCur = -1, sIndexCur = -1;
  420. register SHORT gIndex, sIndex, cbNeeded;
  421. OFFSET pubvalue;
  422. SHORT use32 = 0x90;
  423. pubvalue = pglob->offset;
  424. if ((unsigned long)pubvalue >= 0x10000l)
  425. use32 = 0x91;
  426. /* A public EQU can be negative, so must adjust value */
  427. /* this is happening because masm keeps numbers
  428. * in 17/33 bit sign magnitude representation */
  429. if ((pglob->symkind == EQU) && pglob->symu.equ.equrec.expr.esign)
  430. pubvalue = (short)(((use32==0x91? 0xffffffffl : 65535) - pglob->offset) + 1);
  431. /* Match Intel action, If a global is code, it should
  432. belong to the group of the CS assume at the time of
  433. definition, if there is one */
  434. /* Output group index for data labels too */
  435. sIndex = gIndex = 0;
  436. if (((1 << pglob->symkind) & (M_PROC | M_CLABEL))
  437. && pglob->symu.clabel.csassume
  438. && pglob->symu.clabel.csassume->symkind == GROUP
  439. && pglob->symsegptr && pglob->symsegptr->symu.segmnt.grouptr)
  440. gIndex = pglob->symu.clabel.csassume->symu.grupe.groupIndex;
  441. if (pglob->symsegptr)
  442. sIndex = pglob->symsegptr->symu.segmnt.segIndex;
  443. cbNeeded = STRFLEN ((char FAR *)pglob->nampnt->id) + 13;
  444. if (gIndex != gIndexCur ||
  445. sIndex != sIndexCur ||
  446. emitrecordtype != use32 ||
  447. !EBUFOPEN(cbNeeded)) { /* start a new record */
  448. flushbuffer();
  449. emitsetrecordtype ((UCHAR)use32);
  450. gIndexCur = gIndex;
  451. sIndexCur = sIndex;
  452. emitsindex (gIndexCur);
  453. emitsindex (sIndexCur);
  454. if (sIndex == 0) /* absolutes require a 0 frame # */
  455. emitsword (sIndex);
  456. }
  457. emitSymbol(pglob);
  458. emitoffset(pubvalue, (SHORT)(use32&1));
  459. if (codeview == CVSYMBOLS) {
  460. if (pglob->symkind == EQU) /* type not stored */
  461. emitsindex(typeFet(pglob->symtype));
  462. else
  463. emitsindex (pglob->symu.clabel.type);
  464. }
  465. else
  466. emitsindex(0); /* untyped */
  467. }
  468. /*** emitextern - emit an external
  469. *
  470. * emitextern (psym)
  471. *
  472. * Entry *psym = symbol entry for external
  473. * Exit
  474. * Returns
  475. * Calls
  476. */
  477. VOID PASCAL CODESIZE
  478. emitextern (
  479. SYMBOL FARSYM *psym
  480. ){
  481. USHORT recType;
  482. recType = 0x8c;
  483. if (psym->symkind == EQU){
  484. /* this an extrn lab:abs definition, which is allocated as
  485. * an EQU record which doesn't have space for a index so
  486. * it stored in the unused length field */
  487. psym->length = externnum++;
  488. }
  489. else {
  490. psym->symu.ext.extIndex = externnum++;
  491. if (psym->symu.ext.commFlag)
  492. recType = 0xb0;
  493. }
  494. fKillPass1 |= pass2;
  495. emitsetrecordtype ((UCHAR)recType);
  496. if (!EBUFOPEN(STRFLEN (psym->nampnt->id) + 9)) {
  497. flushbuffer ();
  498. emitsetrecordtype ((UCHAR)recType);
  499. }
  500. emitSymbol(psym);
  501. if (codeview == CVSYMBOLS)
  502. emitsindex(typeFet(psym->symtype));
  503. else
  504. OMFBYTE(0);
  505. if (recType == 0xb0) { /* output commdef variate */
  506. if (psym->symu.ext.commFlag == 1) { /* near item */
  507. OMFBYTE(0x62);
  508. /* size of field */
  509. OMFBYTE(0x81);
  510. emitsword((USHORT)(psym->symu.ext.length * psym->symtype));
  511. }
  512. else {
  513. OMFBYTE(0x61); /* far item */
  514. OMFBYTE(0x84); /* # of elements */
  515. emitsword((USHORT)psym->symu.ext.length);
  516. OMFBYTE(psym->symu.ext.length >> 16);
  517. OMFBYTE(0x81); /* element size */
  518. emitsword(psym->symtype);
  519. }
  520. }
  521. }
  522. /*** emitfltfix - emit fixup for floating point
  523. *
  524. * emitfltfix (group, extidx);
  525. *
  526. * Entry
  527. * *extidx = external id (0 if not assigned)
  528. * Exit
  529. * Returns
  530. * Calls
  531. */
  532. VOID PASCAL CODESIZE
  533. emitfltfix (
  534. USHORT group,
  535. USHORT item,
  536. USHORT *extidx
  537. ){
  538. register SHORT i;
  539. if (*extidx == 0) {
  540. /* Must define it */
  541. if (!moduleflag)
  542. dumpname ();
  543. /* All fixups are FxyRQQ */
  544. *extidx = externnum++;
  545. if (!EBUFOPEN(7))
  546. flushbuffer ();
  547. emitsetrecordtype (0x8C);
  548. /* Name length */
  549. OMFBYTE(6);
  550. OMFBYTE('F');
  551. OMFBYTE(group); /* Group I or J */
  552. OMFBYTE(item); /* Item D, W, E, C, S, A */
  553. OMFBYTE('R');
  554. OMFBYTE('Q');
  555. OMFBYTE('Q');
  556. OMFBYTE(0);
  557. }
  558. if (pass2) { /* Must put out a extern ref */
  559. if (!EFIXOPEN(5))
  560. emitdumpdata ( (UCHAR)LedataOp);
  561. emitsetrecordtype ( (UCHAR) LedataOp);
  562. FixupOp = 0x9C + (LedataOp & 1);
  563. /* output location */
  564. i = (SHORT)(ebufpos - emitbuf - ehoffset);
  565. FIXBYTE(0xC4 + (i >> 8));
  566. FIXBYTE(i);
  567. FIXBYTE(0x46);
  568. if (*extidx >= 0x80) /* Output 2 byte link # */
  569. FIXBYTE ((UCHAR)((*extidx >> 8) + 0x80));
  570. FIXBYTE(*extidx);
  571. }
  572. }
  573. /*** emitline - output a line number offset pair
  574. *
  575. * emitline(pcOffset)
  576. *
  577. * Entry pcoffset: code offset to output
  578. * src->line: for the current line number
  579. * Exit none
  580. */
  581. VOID PASCAL CODESIZE
  582. emitline()
  583. {
  584. static UCHAR fCurrent32;
  585. if (codeview < CVLINE || !pass2 || !objing || !pcsegment)
  586. return;
  587. if (macrolevel == 0 ||
  588. !fPutFirstOp) {
  589. fCurrent32 = (emitrecordtype == 0xA1);
  590. if (linSegment != pcsegment->symu.segmnt.segIndex ||
  591. ! ELINOPEN(2 + wordsize) ||
  592. fLineUsed32 != fCurrent32 ) {
  593. flushline();
  594. /* Start a new line # segment */
  595. linSegment = pcsegment->symu.segmnt.segIndex;
  596. fLineUsed32 = fCurrent32;
  597. /* start record with group index and segment index */
  598. LINBYTE(0); /* no group */
  599. if (linSegment >= 0x80) /* Output 2 byte link # */
  600. LINBYTE ((UCHAR)((linSegment >> 8) + 0x80));
  601. LINBYTE(linSegment);
  602. }
  603. LINBYTE(pFCBCur->line); /* First line # */
  604. LINBYTE(pFCBCur->line >> 8);
  605. LINBYTE(pcoffset); /* then offset */
  606. LINBYTE(pcoffset >> 8);
  607. if (fLineUsed32) { /* 32 bit offset for large segments */
  608. LINBYTE(highWord(pcoffset));
  609. LINBYTE(highWord(pcoffset) >> 8);
  610. }
  611. }
  612. if (macrolevel != 0)
  613. fPutFirstOp = TRUE;
  614. }
  615. /*** fixroom - check for space in fix buffer
  616. *
  617. * flag = fixroom (n);
  618. *
  619. * Entry n = number of bytes to insert in buffer
  620. * Exit none
  621. * Returns TRUE if n bytes will fit in buffer
  622. * FALSE if n bytes will not fit in buffer
  623. */
  624. UCHAR PASCAL CODESIZE
  625. fixroom (
  626. register UCHAR n
  627. ){
  628. return (EFIXOPEN(n));
  629. }
  630. /*** emitcleanq - check for buffer cleaning
  631. *
  632. * flag = emitcleanq (n);
  633. *
  634. * Entry n = number of bytes to insert in buffer
  635. * Exit E_ENS error message issued if pcsegment is null
  636. * Returns TRUE if
  637. */
  638. UCHAR PASCAL CODESIZE
  639. emitcleanq (
  640. UCHAR n
  641. ){
  642. if (!pcsegment)
  643. errorc (E_ENS);
  644. else
  645. return (ecursegment != pcsegment->symu.segmnt.segIndex ||
  646. pcoffset != ecuroffset ||
  647. !EBUFOPEN(n));
  648. }
  649. /*** emitdumpdata - clean data buffer and set up for data record
  650. *
  651. * emitdumpdata (recordnum);
  652. *
  653. * Entry recordnum = record type
  654. * Exit
  655. * Returns
  656. * Calls
  657. */
  658. VOID PASCAL CODESIZE
  659. emitdumpdata (
  660. UCHAR recordnum
  661. ){
  662. flushbuffer ();
  663. /* force dump of buffer */
  664. emitrecordtype = 0xFF;
  665. emitsetrecordtype (recordnum);
  666. }
  667. /*** emitcbyte - emit constant byte into segment
  668. *
  669. * emitcbyte (b)
  670. *
  671. * Entry b = byte
  672. * pcsegment = pointer to segment symbol entry
  673. * pcoffset = offset into segment
  674. * Exit
  675. * Returns
  676. * Calls
  677. */
  678. VOID PASCAL CODESIZE
  679. emitcbyte (
  680. UCHAR b
  681. ){
  682. /* if the segment is changed or the offset is not current or there
  683. is no room in the buffer then flush buffer and start over */
  684. if (emitcleanq (1))
  685. emitdumpdata ((UCHAR)LedataOp);
  686. emitsetrecordtype ((UCHAR)LedataOp);
  687. OMFBYTE(b);
  688. ecuroffset++;
  689. }
  690. /*** emitcword - place a constant word into data record
  691. *
  692. * emitcword (w);
  693. *
  694. * Entry w = word
  695. * Exit
  696. * Returns
  697. * Calls
  698. */
  699. VOID PASCAL CODESIZE
  700. emitcword (
  701. OFFSET w
  702. ){
  703. if (emitcleanq (2))
  704. emitdumpdata ((UCHAR)LedataOp);
  705. emitsetrecordtype ((UCHAR)LedataOp);
  706. emitsword ((USHORT)w);
  707. ecuroffset += 2;
  708. }
  709. /*** emitcdword - place a constant word into data record
  710. *
  711. * emitcword (w);
  712. *
  713. * Entry w = word
  714. * Exit
  715. * Returns
  716. * Calls
  717. */
  718. VOID PASCAL CODESIZE
  719. emitcdword (
  720. OFFSET w
  721. ){
  722. if (emitcleanq (4))
  723. emitdumpdata ((UCHAR)LedataOp);
  724. emitsetrecordtype ((UCHAR)LedataOp);
  725. emitsword ((USHORT)w);
  726. emitsword (highWord(w));
  727. ecuroffset += 4;
  728. }
  729. /*** emitlong - emit a long constant
  730. *
  731. * emitlong (pdsc);
  732. *
  733. * Entry *pdsc = duprecord
  734. * Exit
  735. * Returns
  736. * Calls
  737. */
  738. VOID PASCAL CODESIZE
  739. emitlong (
  740. struct duprec FARSYM *pdsc
  741. ){
  742. UCHAR *cp;
  743. OFFSET tmpstart;
  744. OFFSET tmpcurr;
  745. OFFSET tmplimit;
  746. tmpstart = pcoffset;
  747. cp = pdsc->duptype.duplong.ldata;
  748. tmplimit = (pcoffset + pdsc->duptype.duplong.llen) - 1;
  749. for (tmpcurr = tmpstart; tmpcurr <= tmplimit; ++tmpcurr) {
  750. pcoffset = tmpcurr;
  751. emitcbyte ((UCHAR)*cp++);
  752. }
  753. pcoffset = tmpstart;
  754. }
  755. VOID PASCAL CODESIZE
  756. emitnop ()
  757. {
  758. errorc(E_NOP);
  759. emitopcode(0x90);
  760. }
  761. /*** emitobject - emit object in dup or iter record to OMF stream
  762. *
  763. * emitobject (pdesc);
  764. *
  765. * Entry *pdesc = parse stack entry
  766. * Global - fInter -> FALSE if in iterated DUP
  767. */
  768. VOID PASCAL CODESIZE
  769. emitobject (
  770. register struct psop *pso
  771. ){
  772. register SHORT i;
  773. if (!pcsegment) {
  774. errorc (E_ENS);
  775. return;
  776. }
  777. mapFixup(pso);
  778. if (fIniter) {
  779. i = LedataOp;
  780. if (wordsize == 4 || pso->fixtype >= F32POINTER)
  781. i |= 1;
  782. emitsetrecordtype ((UCHAR)i);
  783. }
  784. /* Data or DUP record */
  785. if (pso->fixtype == FCONSTANT) {
  786. if (!fIniter) {
  787. if (pso->dsize == 1)
  788. OMFBYTE(pso->doffset);
  789. else if (pso->dsize == 2)
  790. emitsword ((USHORT)pso->doffset);
  791. else
  792. for (i = pso->dsize; i; i--)
  793. OMFBYTE(0);
  794. }
  795. else switch(pso->dsize) {
  796. case 1:
  797. emitcbyte ((UCHAR)pso->doffset);
  798. break;
  799. case 2:
  800. emit2:
  801. emitcword (pso->doffset);
  802. break;
  803. case 4:
  804. emit4:
  805. emitcdword (pso->doffset);
  806. break;
  807. default:
  808. /* the indeterminate case had been set up
  809. by emit2byte as 2. we are now leaving
  810. it as zero and doing the mapping here. */
  811. if (wordsize==4)
  812. goto emit4;
  813. else
  814. goto emit2;
  815. }
  816. }
  817. else
  818. emitfixup (pso);
  819. }
  820. /*** emitfixup - emit fixup data into fixup buffer
  821. *
  822. * emitfixup (pso)
  823. *
  824. * Entry PSO for object
  825. */
  826. VOID PASCAL CODESIZE
  827. emitfixup (
  828. register struct psop *pso
  829. ){
  830. UCHAR fixtype;
  831. USHORT dlen; /* length of operand */
  832. UCHAR flen; /* length of fixup */
  833. SYMBOL FARSYM *pframe;
  834. SYMBOL FARSYM *ptarget;
  835. register USHORT tmp;
  836. SHORT i;
  837. fixtype = fixvalues[pso->fixtype];
  838. emitgetspec (&pframe, &ptarget, pso);
  839. /* magic numbers for omf types. */
  840. dlen = pso->dsize;
  841. if (ptarget){
  842. if ((M_XTERN & ptarget->attr) &&
  843. !pframe && (fixtype == 2 || fixtype == 3))
  844. pframe = ptarget;
  845. }
  846. else
  847. return;
  848. flen = 7;
  849. if (pso->doffset) /* target displacement */
  850. flen += 2 + ((emitrecordtype&1) << 1);
  851. /* make sure that we have enough room in the various buffers */
  852. if (fIniter)
  853. if (emitcleanq ((UCHAR)dlen) || !EFIXOPEN(flen))
  854. emitdumpdata ((UCHAR)(LedataOp +2 - 2 * fIniter)); /* RN */
  855. /* set fixup type--32 or 16 */
  856. if (emitrecordtype&1)
  857. {
  858. if (FixupOp == 0x9C)
  859. errorc(E_PHE); /* is there a better message? */
  860. FixupOp = 0x9D;
  861. }
  862. else
  863. {
  864. if (FixupOp == 0x9D)
  865. errorc(E_PHE); /* is there a better message? */
  866. FixupOp = 0x9C;
  867. }
  868. /* build high byte of location */
  869. tmp = 0x80 + (fixtype << 2);
  870. if (!(M_SHRT & pso->dtype)) /* set 'M' bit */
  871. tmp |= 0x40;
  872. i = (SHORT)(ebufpos - emitbuf - ehoffset);
  873. FIXBYTE(tmp + (i >> 8));
  874. /* build low byte of location */
  875. FIXBYTE(i);
  876. /* output fixup data */
  877. FIXBYTE(efixdat (pframe, ptarget, pso->doffset));
  878. tmp = (pframe->symkind == EQU) ?
  879. pframe->length: pframe->symu.ext.extIndex;
  880. if (tmp >= 0x80)
  881. FIXBYTE((tmp >> 8) + 0x80);
  882. FIXBYTE(tmp);
  883. tmp = (ptarget->symkind == EQU) ?
  884. ptarget->length: ptarget->symu.ext.extIndex;
  885. /* send target spec */
  886. if (tmp >= 0x80)
  887. FIXBYTE((tmp >> 8) + 0x80);
  888. FIXBYTE(tmp);
  889. if (pso->doffset) {
  890. FIXBYTE(pso->doffset);
  891. FIXBYTE((UCHAR)(pso->doffset >> 8));
  892. #ifdef V386
  893. if (FixupOp == 0x9D)
  894. {
  895. FIXBYTE((UCHAR)highWord(pso->doffset));
  896. FIXBYTE((UCHAR)(highWord(pso->doffset) >> 8));
  897. }
  898. #endif
  899. }
  900. ecuroffset += dlen;
  901. /* put zero bytes into data buffer */
  902. while (dlen--)
  903. OMFBYTE(0);
  904. }
  905. /*** mapFixup - map relocatable objects into the correct fixup type
  906. *
  907. *
  908. * Entry *pdesc = parse stack entry
  909. * Returns
  910. * Sets fixtype and dsize
  911. */
  912. VOID PASCAL CODESIZE
  913. mapFixup (
  914. register struct psop *pso
  915. ){
  916. if (fNoMap)
  917. return;
  918. if ((1 << pso->fixtype & (M_FCONSTANT | M_FNONE)) &&
  919. (pso->dsegment || pso->dflag == XTERNAL))
  920. pso->fixtype = FOFFSET;
  921. #ifdef V386
  922. /* Remap OFFSET and POINTERS into there 32 bit types */
  923. if (pso->mode > 4 || pso->dsize > 4 ||
  924. (pso->dsegment && pso->dsegment->symkind == SEGMENT &&
  925. pso->dsegment->symu.segmnt.use32 == 4) ||
  926. pso->dcontext == pFlatGroup && pso->dsize == 4)
  927. switch(pso->fixtype) {
  928. case FOFFSET:
  929. if (pso->dsize != 4)
  930. errorc(E_IIS & ~E_WARN1);
  931. else
  932. pso->fixtype = F32OFFSET;
  933. break;
  934. case FPOINTER:
  935. if (pso->dsize != 6)
  936. errorc(E_IIS & ~E_WARN1);
  937. else
  938. pso->fixtype = F32POINTER;
  939. break;
  940. /* default is to do no mapping */
  941. }
  942. #endif
  943. }
  944. /*** emitgetspec - set frame and target of parse entry
  945. *
  946. * emitgetspec (pframe, ptarget, pdesc);
  947. *
  948. * Entry pframe
  949. * Exit
  950. * Returns
  951. * Calls
  952. */
  953. VOID PASCAL CODESIZE
  954. emitgetspec (
  955. SYMBOL FARSYM * *pframe,
  956. SYMBOL FARSYM * *ptarget,
  957. register struct psop *pso
  958. ){
  959. if (pso->fixtype != FCONSTANT &&
  960. pso->dflag == XTERNAL) {
  961. *ptarget = pso->dextptr;
  962. *pframe = pso->dsegment;
  963. #ifndef FEATURE
  964. /* externs without segments and the current assume is to
  965. * flat space get a flat space segment frame */
  966. if (! *pframe && pso->dextptr &&
  967. regsegment[isCodeLabel(pso->dextptr) ? CSSEG: DSSEG] == pFlatGroup)
  968. *pframe = pFlatGroup;
  969. #endif
  970. if (pso->dcontext)
  971. *pframe = pso->dcontext;
  972. }
  973. else {
  974. *ptarget = pso->dsegment; /* containing segment */
  975. *pframe = pso->dcontext; /* context(?) of value */
  976. }
  977. if (!*pframe)
  978. *pframe = *ptarget;
  979. }
  980. /*** efixdat - return fixdat byte
  981. *
  982. * routine (pframe, ptarget, roffset);
  983. *
  984. * Entry *pframe =
  985. * *ptarget =
  986. * roffset =
  987. * Exit
  988. * Returns
  989. * Calls
  990. */
  991. UCHAR PASCAL CODESIZE
  992. efixdat (
  993. SYMBOL FARSYM *pframe,
  994. SYMBOL FARSYM *ptarget,
  995. OFFSET roffset
  996. ){
  997. register UCHAR tmp;
  998. /* build fixdat byte */
  999. tmp = 0;
  1000. /* 'F' bit is off */
  1001. /* 'T' bit is off */
  1002. if (roffset == 0) /* 'P' bit is on */
  1003. tmp = 4;
  1004. if (pframe)
  1005. if (M_XTERN & pframe->attr)
  1006. tmp += 2 << 4;
  1007. else if (pframe->symkind == GROUP)
  1008. tmp += 1 << 4;
  1009. /* frame part of fixdat */
  1010. if (ptarget)
  1011. if (M_XTERN & ptarget->attr)
  1012. tmp += 2;
  1013. else if (ptarget->symkind == GROUP)
  1014. tmp += 1;
  1015. return (tmp);
  1016. }
  1017. /*** edupitem - emit single dup item and count size
  1018. *
  1019. * edupitem (pdup);
  1020. *
  1021. * Entry *pdup = dup record
  1022. * Exit
  1023. * Returns
  1024. * Calls
  1025. */
  1026. VOID PASCAL CODESIZE
  1027. edupitem (
  1028. struct duprec FARSYM *pdup
  1029. ){
  1030. register USHORT len;
  1031. UCHAR *cp;
  1032. if (nestCur > nestMax)
  1033. nestMax++;
  1034. if (ebufpos - emitbuf != EMITBUFSIZE + 1) {
  1035. len = wordsize+2;
  1036. if (pdup->dupkind == LONG)
  1037. len += pdup->duptype.duplong.llen + 1;
  1038. else if (pdup->dupkind == ITEM)
  1039. len += pdup->duptype.dupitem.ddata->dsckind.opnd.dsize + 1;
  1040. if (!EBUFOPEN(len))
  1041. ebufpos = emitbuf + EMITBUFSIZE + 1;
  1042. else {
  1043. emitsword ((USHORT)(pdup->rptcnt));
  1044. /* repeat count */
  1045. if (emitrecordtype & 1)
  1046. emitsword((USHORT)(pdup->rptcnt >> 16));
  1047. /* block count */
  1048. emitsword (pdup->itemcnt);
  1049. if (pdup->dupkind == LONG) {
  1050. cp = pdup->duptype.duplong.ldata;
  1051. len = pdup->duptype.duplong.llen;
  1052. OMFBYTE(len);
  1053. do {
  1054. OMFBYTE(*cp++);
  1055. } while (--len);
  1056. }
  1057. else if (pdup->dupkind == ITEM) {
  1058. OMFBYTE(pdup->duptype.dupitem.ddata->dsckind.opnd.dsize);
  1059. fIniter--;
  1060. emitobject (&pdup->duptype.dupitem.ddata->dsckind.opnd);
  1061. fIniter++;
  1062. }
  1063. }
  1064. }
  1065. }
  1066. /*** emitdup - emit dup record and appropriate fixup record
  1067. *
  1068. * emitdup (pdup);
  1069. *
  1070. * Entry *pdup = dup record
  1071. * Exit
  1072. * Returns FALSE if dup is too large to fit in buffer
  1073. * Calls
  1074. */
  1075. UCHAR PASCAL CODESIZE
  1076. emitdup (
  1077. struct duprec FARSYM *pdup
  1078. ){
  1079. SHORT op;
  1080. op = (f386already) ? 0xA3 : 0xA2;
  1081. nestCur = nestMax = 0;
  1082. emitdumpdata ((UCHAR)op);
  1083. emitsetrecordtype ((UCHAR)op);
  1084. /* scan dup tree and emit dup items */
  1085. scandup (pdup, edupitem);
  1086. if (ebufpos - emitbuf == EMITBUFSIZE + 1) {
  1087. ebufpos = emitbuf;
  1088. ehoffset = 0;
  1089. efixpos = efixbuffer;
  1090. return(FALSE);
  1091. }
  1092. else {
  1093. flushbuffer ();
  1094. flushfixup ();
  1095. emitrecordtype = 0xFF;
  1096. }
  1097. return (nestMax <= 18);
  1098. }
  1099. /*** emitEndPass1 - emit end of pass1 info
  1100. *
  1101. */
  1102. VOID PASCAL emitEndPass1()
  1103. {
  1104. emitsetrecordtype (0x88);
  1105. oEndPass1 = oOMFCur + 5; /* note offset of end of pass1 OMF record */
  1106. OMFBYTE(0);
  1107. emitsword(0x100 | 0xA2);
  1108. flushbuffer ();
  1109. }
  1110. /*** emitdone - produce end record
  1111. *
  1112. * emitdone (pdesc);
  1113. *
  1114. * Entry *pdesc = parse tree entry
  1115. * Exit
  1116. * Returns
  1117. * Calls
  1118. */
  1119. VOID PASCAL
  1120. emitdone (
  1121. DSCREC *pdesc
  1122. ){
  1123. SYMBOL FARSYM *pframe;
  1124. SYMBOL FARSYM *ptarget;
  1125. OFFSET u;
  1126. UCHAR endOMFtype;
  1127. flushline();
  1128. if (!pdesc)
  1129. {
  1130. emitsetrecordtype (0x8A); /* RN */
  1131. /* emit null entry point marked in MOD TYP */
  1132. /* there is a point of contention here. some people
  1133. * (and decode.c, old assemblers and other things) say
  1134. * the low order bit is zero. others, such as the
  1135. * omf documentation, say the low order bit should be
  1136. * 1. since I dont know, and am trying to be compatable,
  1137. * I will obey the old tools. maybe I'll change this
  1138. * later... -Hans
  1139. * OMFBYTE(1); /* RN */
  1140. OMFBYTE(0);
  1141. }
  1142. else {
  1143. fKillPass1++;
  1144. u = pdesc->dsckind.opnd.doffset;
  1145. emitgetspec (&pframe, &ptarget, &pdesc->dsckind.opnd);
  1146. if (!ptarget || !pframe)
  1147. return;
  1148. endOMFtype = (cputype & P386)? 0x8B: 0x8A;
  1149. if (M_XTERN & ptarget->attr)
  1150. pframe = ptarget;
  1151. emitsetrecordtype (endOMFtype);
  1152. /* emit entry point information */
  1153. OMFBYTE(0xC1);
  1154. OMFBYTE(efixdat (pframe, ptarget, u) & ~4);
  1155. emitsindex (pframe->symu.segmnt.segIndex);
  1156. emitsindex (ptarget->symu.segmnt.segIndex);
  1157. emitsword((USHORT)u); /* output offset */
  1158. #ifdef V386
  1159. if (endOMFtype == 0x8B)
  1160. emitsword((USHORT)highWord(u));
  1161. #endif
  1162. }
  1163. flushbuffer ();
  1164. }
  1165. #ifndef M8086OPT
  1166. /*** EBYTE - Emit byte macro
  1167. *
  1168. * EBYTE ( ch )
  1169. *
  1170. * The bytes are buffered in obj.buf until the buffer fills
  1171. * then the buffer is written to disk via edump.
  1172. *
  1173. */
  1174. #define EBYTE( ch ){\
  1175. if( !obj.cnt){\
  1176. edump();\
  1177. }\
  1178. obj.cnt--;\
  1179. checksum += *obj.pos++ = (char)ch;\
  1180. }
  1181. /*** ebuffer - write out object buffer
  1182. *
  1183. * Writes the record type, record length, record data, and checksum to
  1184. * the obj file. This is done via EBYTE which buffers the writes into
  1185. * obj.buf.
  1186. *
  1187. * Modifies obj.cnt, obj.pos, objerr, emitrecordtype
  1188. * Exit none
  1189. * Returns
  1190. * Calls farwrite
  1191. */
  1192. VOID CODESIZE
  1193. ebuffer (
  1194. USHORT rectyp,
  1195. UCHAR *bufpos,
  1196. UCHAR *buffer
  1197. ){
  1198. register UCHAR checksum;
  1199. register i;
  1200. USHORT nb;
  1201. if ((bufpos != buffer) && objing) {
  1202. nb = (USHORT)(bufpos - buffer + 1);
  1203. oOMFCur += nb + 3;
  1204. checksum = 0;
  1205. EBYTE(rectyp)
  1206. i = nb & 0xFF;
  1207. EBYTE( i )
  1208. i = nb >> 8;
  1209. EBYTE( i )
  1210. while (buffer < bufpos){
  1211. EBYTE( *buffer++ )
  1212. }
  1213. checksum = -checksum;
  1214. EBYTE( checksum );
  1215. }
  1216. emitrecordtype = 0;
  1217. }
  1218. /*** edump - dump the emit buffer
  1219. *
  1220. * edump ();
  1221. *
  1222. * The bytes buffered in obj.buf are dumped to disk. And
  1223. * the count and buffer position are reinitialized.
  1224. *
  1225. * Modifies obj.cnt, obj.pos, objerr
  1226. * Exit none
  1227. * Returns
  1228. * Calls farwrite
  1229. */
  1230. VOID CODESIZE
  1231. edump()
  1232. {
  1233. # if defined MSDOS && !defined FLATMODEL
  1234. farwrite( obj.fh, obj.buf, (SHORT)(obj.siz - obj.cnt) );
  1235. # else
  1236. if (_write( obj.fh, obj.buf, obj.siz - obj.cnt )
  1237. != obj.siz - obj.cnt)
  1238. objerr = -1;
  1239. # endif /* MSDOS */
  1240. obj.cnt = obj.siz;
  1241. obj.pos = obj.buf;
  1242. }
  1243. #endif /* M8086OPT */
  1244. #if !defined M8086OPT && !defined FLATMODEL
  1245. unsigned short _far _pascal DosWrite( unsigned short, unsigned char far *, unsigned short, unsigned short far *);
  1246. VOID farwrite( handle, buffer, count )
  1247. int handle;
  1248. UCHAR FAR * buffer;
  1249. SHORT count;
  1250. {
  1251. USHORT usWritten;
  1252. if( DosWrite( handle, buffer, count, &usWritten ) ){
  1253. objerr = -1;
  1254. }
  1255. }
  1256. #endif
  1257. int emitFpo()
  1258. {
  1259. struct nameStruct {
  1260. SHORT hashval;
  1261. char id[20];
  1262. } nam = {0, ".debug$F"};
  1263. PFPOSTRUCT pFpo = pFpoHead;
  1264. SYMBOL sym;
  1265. UCHAR comb = 2; // public
  1266. UCHAR algn = 5; // relocatable
  1267. USHORT tmp = 0;
  1268. unsigned long offset = 0;
  1269. unsigned long data_offset = 0;
  1270. if (!pFpo) {
  1271. return TRUE;
  1272. }
  1273. /*
  1274. * write out the externs for all fpo procs
  1275. * this must be done during pass1 so that the extdefs
  1276. * are written to the omf file before the pubdefs
  1277. */
  1278. if (!pass2) {
  1279. flushbuffer();
  1280. for (pFpo=pFpoHead; pFpo; pFpo=pFpo->next) {
  1281. pFpo->extidx = externnum++;
  1282. emitsetrecordtype (0x8C);
  1283. emitSymbol(pFpo->pSym);
  1284. OMFBYTE(0);
  1285. flushbuffer();
  1286. }
  1287. return TRUE;
  1288. }
  1289. /*
  1290. * create the lnames record for the .debug$F section
  1291. */
  1292. emitsetrecordtype (0x96);
  1293. memset(&sym,0,sizeof(SYMBOL));
  1294. sym.nampnt = (NAME*) &nam;
  1295. emitSymbol(&sym);
  1296. flushbuffer();
  1297. /*
  1298. * create the segdef record for the .debug$F section
  1299. */
  1300. emitsetrecordtype (0x98);
  1301. OMFBYTE((algn<<5) + (comb<<2) + 1);
  1302. emitoffset(numFpoRecords*sizeof(FPO_DATA), 0);
  1303. emitsindex (lnameIndex);
  1304. emitsindex (1);
  1305. emitsindex (1);
  1306. flushbuffer();
  1307. /*
  1308. * now we have to cruise thru the list of fpo directives and
  1309. * fixup any cases where there are multiple fpo directives for
  1310. * a single procedure. the procedure size needs to be changed
  1311. * to account for the multiple directives.
  1312. */
  1313. pFpo=pFpoHead;
  1314. flushbuffer();
  1315. do {
  1316. if ((pFpo->next) && (pFpo->next->pSym == pFpo->pSym)) {
  1317. // we must have a group (2 or more) fpo directives
  1318. // that are in the same function so lets fix them
  1319. do {
  1320. pFpo->fpoData.cbProcSize =
  1321. pFpo->next->fpoData.ulOffStart - pFpo->fpoData.ulOffStart;
  1322. pFpo = pFpo->next;
  1323. // now we must output a pubdef and a extdef for the
  1324. // fpo record. this is necessary because otherwise the
  1325. // linker will resolve the fixups to the first fpo record
  1326. // function.
  1327. pFpo->extidx = externnum++;
  1328. emitsetrecordtype (0x8C);
  1329. emitSymbol(pFpo->pSymAlt);
  1330. OMFBYTE(0);
  1331. flushbuffer();
  1332. emitglobal(pFpo->pSymAlt);
  1333. } while ((pFpo->next) && (pFpo->next->pSym == pFpo->pSym));
  1334. pFpo->fpoData.cbProcSize =
  1335. (pFpo->pSym->offset + pFpo->pSym->symu.plabel.proclen) -
  1336. pFpo->fpoData.ulOffStart;
  1337. }
  1338. else {
  1339. pFpo->fpoData.cbProcSize = pFpo->pSym->symu.plabel.proclen;
  1340. }
  1341. pFpo = pFpo->next;
  1342. } while (pFpo);
  1343. /*
  1344. * finally we scan the list of fpo directives and output the
  1345. * actual fpo records and associated fixups
  1346. */
  1347. for (pFpo=pFpoHead; pFpo; pFpo=pFpo->next) {
  1348. /*
  1349. * emit the fpo record
  1350. */
  1351. emitsetrecordtype (0xA4);
  1352. emitsindex (segmentnum);
  1353. emitoffset(data_offset,1);
  1354. data_offset += sizeof(FPO_DATA);
  1355. offset = pFpo->fpoData.ulOffStart;
  1356. pFpo->fpoData.ulOffStart = 0;
  1357. memcpy((void*)ebufpos, (void*)&pFpo->fpoData, sizeof(FPO_DATA));
  1358. ebufpos += sizeof(FPO_DATA);
  1359. /*
  1360. * emit the fixup record
  1361. */
  1362. emitsetrecordtype (0x9D);
  1363. OMFBYTE(0xB8); // m=0, loc=14, offset=0
  1364. OMFBYTE(0x00); // offset=0
  1365. OMFBYTE(0x92); // f=1, frame=1, t=0, p=0, target=2
  1366. tmp = pFpo->extidx;
  1367. if (tmp >= 0x80) {
  1368. OMFBYTE((tmp >> 8) + 0x80);
  1369. }
  1370. OMFBYTE(tmp);
  1371. OMFBYTE(offset);
  1372. OMFBYTE(offset >> 8);
  1373. OMFBYTE(offset >> 16);
  1374. OMFBYTE(offset >> 24);
  1375. }
  1376. flushbuffer();
  1377. lnameIndex++;
  1378. segmentnum++;
  1379. return TRUE;
  1380. }