prt0comn.asm 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. ; common startup code for all the memory models
  2. ; uncomment this, if you want to use i8086 section based smartlinking:
  3. ;%define __I8086_SMARTLINK_SECTIONS__
  4. %ifdef __TINY__
  5. %define __NEAR_CODE__
  6. %define __NEAR_DATA__
  7. %elifdef __SMALL__
  8. %define __NEAR_CODE__
  9. %define __NEAR_DATA__
  10. %elifdef __MEDIUM__
  11. %define __FAR_CODE__
  12. %define __NEAR_DATA__
  13. %elifdef __COMPACT__
  14. %define __NEAR_CODE__
  15. %define __FAR_DATA__
  16. %elifdef __LARGE__
  17. %define __FAR_CODE__
  18. %define __FAR_DATA__
  19. %elifdef __HUGE__
  20. %define __FAR_CODE__
  21. %define __FAR_DATA__
  22. %else
  23. %fatal "Memory model not defined."
  24. %endif
  25. %ifdef __FAR_CODE__
  26. extra_param_offset equ 2
  27. %else
  28. extra_param_offset equ 0
  29. %endif
  30. %ifdef __FAR_DATA__
  31. extra_data_offset equ 2
  32. %else
  33. extra_data_offset equ 0
  34. %endif
  35. cpu 8086
  36. segment _TEXT use16 class=CODE
  37. extern PASCALMAIN
  38. extern __fpc_PrefixSeg
  39. extern dos_version
  40. extern __Test8086
  41. extern _edata ; defined by WLINK, indicates start of BSS
  42. extern _end ; defined by WLINK, indicates end of BSS
  43. extern __stklen
  44. extern __stktop
  45. extern __stkbottom
  46. extern __nearheap_start
  47. extern __nearheap_end
  48. extern ___heap
  49. %ifdef __NEAR_DATA__
  50. extern __fpc_stackplusmaxheap_in_para
  51. %endif
  52. %ifndef __TINY__
  53. %ifdef __FAR_DATA__
  54. extern ___stack
  55. %endif
  56. %ifdef __NEAR_DATA__
  57. extern ___stacktop
  58. %endif
  59. %endif
  60. extern __SaveInt00
  61. extern __SaveInt10
  62. extern __SaveInt75
  63. extern __fpu_status
  64. extern FPC_HANDLE_I8086_ERROR
  65. %ifdef __TINY__
  66. resb 0100h
  67. %endif
  68. ..start:
  69. %ifndef __HUGE__
  70. %ifdef __TINY__
  71. mov bx, cs
  72. %else
  73. mov bx, DGROUP
  74. %ifdef __NEAR_DATA__
  75. ; init the stack
  76. mov ss, bx
  77. mov sp, ___stacktop wrt DGROUP
  78. %endif
  79. %endif
  80. ; zero fill the BSS section
  81. mov es, bx
  82. mov di, _edata wrt DGROUP
  83. mov cx, _end wrt DGROUP
  84. sub cx, di
  85. xor al, al
  86. cld
  87. rep stosb
  88. %endif ; not __HUGE__
  89. ; save the Program Segment Prefix
  90. push ds
  91. ; init DS
  92. %ifdef __HUGE__
  93. mov bx, SYSTEM_DATA
  94. mov ds, bx
  95. %else
  96. mov ds, bx
  97. %endif
  98. ; pop the PSP from stack and store it in the pascal variable PrefixSeg
  99. pop ax
  100. mov word [__fpc_PrefixSeg], ax
  101. ; get DOS version and save it in the pascal variable dos_version
  102. mov ax, 3000h
  103. int 21h
  104. xchg al, ah
  105. mov word [dos_version], ax
  106. ; detect CPU
  107. xor bx, bx ; 0=8086/8088/80186/80188/NEC V20/NEC V30
  108. ; on pre-286 processors, bits 12..15 of the FLAGS registers are always set
  109. pushf
  110. pop ax
  111. and ah, 0fh
  112. push ax
  113. popf
  114. pushf
  115. pop ax
  116. and ah, 0f0h
  117. cmp ah, 0f0h
  118. je cpu_detect_done
  119. ; at this point we have a 286 or higher
  120. inc bx
  121. ; on a true 286 in real mode, bits 12..15 are always clear
  122. pushf
  123. pop ax
  124. or ah, 0f0h
  125. push ax
  126. popf
  127. pushf
  128. pop ax
  129. and ah, 0f0h
  130. jz cpu_detect_done
  131. ; we have a 386+
  132. inc bx
  133. cpu_detect_done:
  134. mov [__Test8086], bl
  135. %ifdef __NEAR_DATA__
  136. ; ****************************************************************************
  137. ; ** near data memory layout setup **
  138. ; ****************************************************************************
  139. ; allocate max heap
  140. ; first we determine in paragraphs ax:=min(64kb, data+bss+stack+maxheap)
  141. mov ax, _end wrt DGROUP
  142. add ax, 15
  143. mov cl, 4
  144. shr ax, cl
  145. add ax, word [__fpc_stackplusmaxheap_in_para]
  146. cmp ax, 1000h ; 1000h = 64k in paragraphs
  147. jbe data_with_maxheap_less_than_64k
  148. mov ax, 1000h
  149. data_with_maxheap_less_than_64k:
  150. ; try to resize our main DOS memory block until the end of the data segment (or even smaller, if maxheap is small)
  151. mov cx, word [__fpc_PrefixSeg]
  152. %ifdef __TINY__
  153. mov dx, cs
  154. %else
  155. mov dx, DGROUP
  156. %endif
  157. sub dx, cx ; dx = (ds - psp) in paragraphs
  158. push dx ; save (ds - psp)
  159. add dx, 1000h ; 64kb in paragraphs
  160. ; get our MCB size in paragraphs
  161. dec cx
  162. mov es, cx
  163. mov bx, word [es:3]
  164. ; is it smaller than the maximum data segment size?
  165. cmp bx, dx
  166. jbe skip_mem_realloc
  167. mov bx, dx
  168. inc cx
  169. mov es, cx
  170. mov ah, 4Ah
  171. int 21h
  172. jc mem_realloc_err
  173. skip_mem_realloc:
  174. ; bx = the new size in paragraphs
  175. pop cx ; cx = (ds - psp)
  176. sub bx, cx
  177. mov cl, 4
  178. shl bx, cl
  179. sub bx, 2
  180. mov sp, bx
  181. mov word [__stktop], sp
  182. add bx, 2
  183. sub bx, word [__stklen]
  184. and bl, 0FEh
  185. mov word [__stkbottom], bx
  186. mov ax, _end wrt DGROUP
  187. cmp bx, ax
  188. jb not_enough_mem
  189. ; heap is between [ds:_end wrt DGROUP] and [ds:__stkbottom - 1]
  190. add ax, 3
  191. and al, 0FCh
  192. mov word [__nearheap_start], ax
  193. and bl, 0FCh
  194. mov word [__nearheap_end], bx
  195. ; ****************************************************************************
  196. ; ** near data setup done **
  197. ; ****************************************************************************
  198. %endif
  199. %ifdef __FAR_DATA__
  200. mov word [__stktop], sp
  201. mov word [__stkbottom], 0
  202. mov ax, ss
  203. mov word [__stkbottom + 2], ax
  204. mov word [__stktop + 2], ax
  205. mov dx, sp
  206. add dx, 15
  207. mov cl, 4
  208. shr dx, cl
  209. add ax, dx
  210. mov word [__nearheap_start], 0
  211. mov word [__nearheap_start + 2], ax
  212. ; get our MCB size in paragraphs
  213. mov cx, word [__fpc_PrefixSeg]
  214. dec cx
  215. mov es, cx
  216. mov bx, word [es:3]
  217. add bx, cx
  218. inc bx
  219. ; __nearheap_end := end_of_dos_memory_block
  220. mov word [__nearheap_end], 0
  221. mov word [__nearheap_end + 2], bx
  222. %endif
  223. %ifdef __FAR_CODE__
  224. jmp far PASCALMAIN
  225. %else
  226. jmp PASCALMAIN
  227. %endif
  228. %ifdef __NEAR_DATA__
  229. not_enough_mem:
  230. mov dx, not_enough_mem_msg
  231. jmp error_msg
  232. mem_realloc_err:
  233. ; at this point there's still (ds-psp) pushed on the stack, but we won't
  234. ; bother popping it, because we exit to DOS with an error message here
  235. mov dx, mem_realloc_err_msg
  236. error_msg:
  237. mov ah, 9
  238. int 21h
  239. mov ax, 4CFFh
  240. int 21h
  241. %endif
  242. global FPC_INT00_HANDLER
  243. FPC_INT00_HANDLER:
  244. pushf
  245. sub sp, 4 ; reserve space on the stack for the iret
  246. push cx
  247. push ds
  248. push bp
  249. ; init ds
  250. %ifdef __TINY__
  251. mov bp, cs
  252. %elifdef __HUGE__
  253. mov bp, SYSTEM_DATA
  254. %else
  255. mov bp, DGROUP
  256. %endif
  257. mov ds, bp
  258. %ifdef __NEAR_DATA__
  259. ; in memory models, where SS=DS, also
  260. ; check whether we're running on the same stack
  261. mov cx, ss
  262. cmp bp, cx
  263. jne .call_previous_handler00
  264. %endif
  265. %ifndef __FAR_CODE__
  266. ; check whether we're coming from the same code segment
  267. mov bp, sp
  268. mov cx, [bp + 3*2 + 6 + 2] ; get caller segment
  269. mov bp, cs
  270. cmp bp, cx
  271. jne .call_previous_handler00
  272. %endif
  273. ; Call Fpc_Handle_I8086_Error, with err=0
  274. mov bp, sp
  275. mov cx, [bp + 3*2 + 6] ; get caller offset
  276. %ifdef __FAR_CODE__
  277. mov dx, [bp + 3*2 + 6 + 2] ; get caller segment
  278. %endif
  279. pop bp
  280. add sp, 2*2 + 6 + 6
  281. xor ax, ax
  282. push ax
  283. mov ax, 0
  284. push ax
  285. %ifdef __FAR_CODE__
  286. push dx
  287. %endif
  288. push cx
  289. cld
  290. sti
  291. %ifdef __FAR_CODE__
  292. jmp far FPC_HANDLE_I8086_ERROR
  293. %else
  294. jmp FPC_HANDLE_I8086_ERROR
  295. %endif
  296. .call_previous_handler00:
  297. mov bp, sp
  298. mov cx, [__SaveInt00]
  299. mov [bp + 3*2], cx
  300. mov cx, [__SaveInt00+2]
  301. mov [bp + 3*2 + 2], cx
  302. pop bp
  303. pop ds
  304. pop cx
  305. iret ; jumps to the previous handler with all registers and stack intact
  306. global FPC_INT10_HANDLER
  307. FPC_INT10_HANDLER:
  308. pushf
  309. sub sp, 4 ; reserve space on the stack for the iret
  310. push cx
  311. push ds
  312. push bp
  313. ; init ds
  314. %ifdef __TINY__
  315. mov bp, cs
  316. %elifdef __HUGE__
  317. mov bp, SYSTEM_DATA
  318. %else
  319. mov bp, DGROUP
  320. %endif
  321. mov ds, bp
  322. ; Check that an unmasked exception is indeed set
  323. fnstsw word [__fpu_status]
  324. test byte [__fpu_status], 80h ; really just this bit is enough, see i8087 datasheet
  325. je .call_previous_handler10
  326. %ifdef __NEAR_DATA__
  327. ; in memory models, where SS=DS, also
  328. ; check whether we're running on the same stack
  329. mov cx, ss
  330. cmp bp, cx
  331. jne .call_previous_handler10
  332. %endif
  333. %ifndef __FAR_CODE__
  334. ; check whether we're coming from the same code segment
  335. mov bp, sp
  336. mov cx, [bp + 3*2 + 6 + 2] ; get caller segment
  337. mov bp, cs
  338. cmp bp, cx
  339. jne .call_previous_handler10
  340. %endif
  341. ; Call Fpc_Handle_I8086_Error, with err=$10
  342. mov bp, sp
  343. mov cx, [bp + 3*2 + 6] ; get caller offset
  344. %ifdef __FAR_CODE__
  345. mov dx, [bp + 3*2 + 6 + 2] ; get caller segment
  346. %endif
  347. pop bp
  348. add sp, 2*2 + 6 + 6
  349. xor ax, ax
  350. push ax
  351. mov ax, 10h
  352. push ax
  353. %ifdef __FAR_CODE__
  354. push dx
  355. %endif
  356. push cx
  357. cld
  358. sti
  359. %ifdef __FAR_CODE__
  360. jmp far FPC_HANDLE_I8086_ERROR
  361. %else
  362. jmp FPC_HANDLE_I8086_ERROR
  363. %endif
  364. .call_previous_handler10:
  365. mov bp, sp
  366. mov cx, [__SaveInt10]
  367. mov [bp + 3*2], cx
  368. mov cx, [__SaveInt10+2]
  369. mov [bp + 3*2 + 2], cx
  370. pop bp
  371. pop ds
  372. pop cx
  373. iret ; jumps to the previous handler with all registers and stack intact
  374. global FPC_INT75_HANDLER
  375. FPC_INT75_HANDLER:
  376. pushf
  377. sub sp, 4 ; reserve space on the stack for the iret
  378. push cx
  379. push ds
  380. push bp
  381. ; init ds
  382. %ifdef __TINY__
  383. mov bp, cs
  384. %elifdef __HUGE__
  385. mov bp, SYSTEM_DATA
  386. %else
  387. mov bp, DGROUP
  388. %endif
  389. mov ds, bp
  390. %ifdef __NEAR_DATA__
  391. ; in memory models, where SS=DS, also
  392. ; check whether we're running on the same stack
  393. mov cx, ss
  394. cmp bp, cx
  395. jne .call_previous_handler75
  396. %endif
  397. %ifndef __FAR_CODE__
  398. ; check whether we're coming from the same code segment
  399. mov bp, sp
  400. mov cx, [bp + 3*2 + 6 + 2] ; get caller segment
  401. mov bp, cs
  402. cmp bp, cx
  403. jne .call_previous_handler75
  404. %endif
  405. ; Call Fpc_Handle_I8086_Error, with err=$75
  406. mov bp, sp
  407. mov cx, [bp + 3*2 + 6] ; get caller offset
  408. %ifdef __FAR_CODE__
  409. mov dx, [bp + 3*2 + 6 + 2] ; get caller segment
  410. %endif
  411. pop bp
  412. add sp, 2*2 + 6 + 6
  413. xor ax, ax
  414. push ax
  415. mov ax, 75h
  416. push ax
  417. %ifdef __FAR_CODE__
  418. push dx
  419. %endif
  420. push cx
  421. cld
  422. ; Reset IRQ/#IGNNE latch; signal EOI; enable interrupts
  423. mov al,20h
  424. out 0F0h,al ; al=any
  425. out 0A0h,al
  426. out 020h,al
  427. sti
  428. %ifdef __FAR_CODE__
  429. jmp far FPC_HANDLE_I8086_ERROR
  430. %else
  431. jmp FPC_HANDLE_I8086_ERROR
  432. %endif
  433. .call_previous_handler75:
  434. mov bp, sp
  435. mov cx, [__SaveInt75]
  436. mov [bp + 3*2], cx
  437. mov cx, [__SaveInt75+2]
  438. mov [bp + 3*2 + 2], cx
  439. pop bp
  440. pop ds
  441. pop cx
  442. retf ; jumps to the previous handler with all registers and stack intact
  443. global FPC_INSTALL_INTERRUPT_HANDLERS
  444. FPC_INSTALL_INTERRUPT_HANDLERS:
  445. %ifdef __HUGE__
  446. push ds
  447. mov ax, SYSTEM_DATA
  448. mov ds, ax
  449. %endif
  450. ; save old int 00 handler
  451. mov ax, 3500h
  452. int 21h
  453. mov [__SaveInt00], bx
  454. mov bx, es
  455. mov [__SaveInt00+2], bx
  456. ; install the new int 00 handler
  457. %ifndef __TINY__
  458. push ds
  459. push cs
  460. pop ds
  461. %endif
  462. mov dx, FPC_INT00_HANDLER
  463. mov ax, 2500h
  464. int 21h
  465. %ifndef __TINY__
  466. pop ds
  467. %endif
  468. ; save old int $10 handler
  469. mov ax, 3510h
  470. int 21h
  471. mov [__SaveInt10], bx
  472. mov bx, es
  473. mov [__SaveInt10+2], bx
  474. ; install the new int $10 handler
  475. %ifndef __TINY__
  476. push ds
  477. push cs
  478. pop ds
  479. %endif
  480. mov dx, FPC_INT10_HANDLER
  481. mov ax, 2510h
  482. int 21h
  483. %ifndef __TINY__
  484. pop ds
  485. %endif
  486. ; save old int $75 handler
  487. mov ax, 3575h
  488. int 21h
  489. mov [__SaveInt75], bx
  490. mov bx, es
  491. mov [__SaveInt75+2], bx
  492. ; install the new int $75 handler
  493. %ifndef __TINY__
  494. push ds
  495. push cs
  496. pop ds
  497. %endif
  498. mov dx, FPC_INT75_HANDLER
  499. mov ax, 2575h
  500. int 21h
  501. %ifndef __TINY__
  502. pop ds
  503. %endif
  504. %ifdef __HUGE__
  505. pop ds
  506. %endif
  507. %ifdef __FAR_CODE__
  508. retf
  509. %else
  510. ret
  511. %endif
  512. global FPC_RESTORE_INTERRUPT_HANDLERS
  513. FPC_RESTORE_INTERRUPT_HANDLERS:
  514. %ifdef __HUGE__
  515. push ds
  516. mov ax, SYSTEM_DATA
  517. mov ds, ax
  518. %endif
  519. push ds
  520. mov ax, 2500h
  521. lds dx, [__SaveInt00]
  522. int 21h
  523. pop ds
  524. push ds
  525. mov ax, 2510h
  526. lds dx, [__SaveInt10]
  527. int 21h
  528. pop ds
  529. push ds
  530. mov ax, 2575h
  531. lds dx, [__SaveInt75]
  532. int 21h
  533. pop ds
  534. %ifdef __HUGE__
  535. pop ds
  536. %endif
  537. %ifdef __FAR_CODE__
  538. retf
  539. %else
  540. ret
  541. %endif
  542. global FPC_MSDOS_CARRY
  543. FPC_MSDOS_CARRY:
  544. stc
  545. global FPC_MSDOS
  546. FPC_MSDOS:
  547. mov al, 21h ; not ax, because only the low byte is used
  548. pop dx
  549. %ifdef __FAR_CODE__
  550. pop bx
  551. %endif
  552. pop cx
  553. %ifdef __FAR_DATA__
  554. pop si
  555. %endif
  556. push ax
  557. %ifdef __FAR_DATA__
  558. push si
  559. %endif
  560. push cx
  561. %ifdef __FAR_CODE__
  562. push bx
  563. %endif
  564. push dx
  565. global FPC_INTR
  566. FPC_INTR:
  567. push bp
  568. mov bp, sp
  569. mov al, byte [bp + 6 + extra_param_offset + extra_data_offset]
  570. mov byte [cs:int_number], al
  571. mov si, [bp + 4 + extra_param_offset]
  572. push ds
  573. %ifdef __FAR_DATA__
  574. mov ax, [bp + 6 + extra_param_offset]
  575. mov ds, ax
  576. %endif
  577. mov ax, word [si + 16]
  578. mov es, ax
  579. mov ax, word [si + 14] ; ds
  580. push ax
  581. mov ax, word [si]
  582. mov bx, word [si + 2]
  583. mov cx, word [si + 4]
  584. mov dx, word [si + 6]
  585. mov bp, word [si + 8]
  586. mov di, word [si + 12]
  587. mov si, word [si + 10]
  588. pop ds
  589. db 0CDh ; opcode of INT xx
  590. int_number:
  591. db 255
  592. pushf
  593. push ds
  594. push si
  595. push bp
  596. mov bp, sp
  597. %ifdef __FAR_DATA__
  598. mov si, [bp + 16 + extra_param_offset]
  599. %else
  600. mov si, word [bp + 8]
  601. %endif
  602. mov ds, si
  603. mov si, word [bp + 14 + extra_param_offset]
  604. mov word [si], ax
  605. mov word [si + 2], bx
  606. mov word [si + 4], cx
  607. mov word [si + 6], dx
  608. mov word [si + 12], di
  609. mov ax, es
  610. mov word [si + 16], ax
  611. pop ax
  612. mov word [si + 8], ax
  613. pop ax
  614. mov word [si + 10], ax
  615. pop ax
  616. mov word [si + 14], ax
  617. pop ax
  618. mov word [si + 18], ax
  619. pop ds
  620. pop bp
  621. %ifdef __FAR_CODE__
  622. retf 4 + extra_data_offset
  623. %else
  624. ret 4 + extra_data_offset
  625. %endif
  626. %ifndef __TINY__
  627. global FPC_CHECK_NULLAREA
  628. FPC_CHECK_NULLAREA:
  629. %ifdef __HUGE__
  630. mov ax, DGROUP
  631. mov es, ax
  632. %else
  633. push ds
  634. pop es
  635. %endif
  636. xor di, di
  637. mov cx, 32
  638. mov al, 1
  639. cld
  640. repe scasb
  641. je .skip
  642. dec ax ; 1 byte shorter than dec al
  643. .skip:
  644. %ifdef __FAR_CODE__
  645. retf
  646. %else
  647. ret
  648. %endif
  649. %endif
  650. %ifdef __HUGE__
  651. ; reference the system unit's data segment
  652. segment SYSTEM_DATA use16 class=FAR_DATA align=2
  653. %endif
  654. segment data class=DATA align=2
  655. %ifdef __NEAR_DATA__
  656. mem_realloc_err_msg:
  657. db 'Memory allocation error', 13, 10, '$'
  658. not_enough_mem_msg:
  659. db 'Not enough memory', 13, 10, '$'
  660. %endif
  661. ; add reference to the beginning of the minimal heap, so the object
  662. ; module, containing the heap segment doesn't get smartlinked away
  663. dw ___heap
  664. segment bss class=BSS align=2
  665. %ifndef __TINY__
  666. segment _NULL align=16 class=BEGDATA
  667. global __nullarea
  668. __nullarea:
  669. dd 01010101h, 01010101h, 01010101h, 01010101h
  670. dd 01010101h, 01010101h, 01010101h, 01010101h
  671. segment _AFTERNULL align=2 class=BEGDATA
  672. dw 0
  673. %ifdef __NEAR_DATA__
  674. segment stack stack class=STACK align=16
  675. %else
  676. segment data
  677. ; add reference to the beginning of stack, so the object module,
  678. ; containing the stack segment doesn't get smartlinked away
  679. dw ___stack
  680. %endif
  681. %endif
  682. %ifdef __TINY__
  683. group DGROUP _TEXT data bss
  684. %else
  685. %ifdef __NEAR_DATA__
  686. group DGROUP _NULL _AFTERNULL data bss stack
  687. %else
  688. group DGROUP _NULL _AFTERNULL data bss
  689. %endif
  690. %ifdef __I8086_SMARTLINK_SECTIONS__
  691. group CGROUP _TEXT
  692. %endif
  693. %endif