home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / SECDR13A.ZIP / CRYPT2.ASM < prev    next >
Assembly Source File  |  1993-11-19  |  20KB  |  763 lines

  1.         %PAGESIZE        59        ; Turbo assembler formatting codes
  2.         %BIN        13
  3.         %LINUM        3
  4.  
  5. ; Copyright (c) 1993 Colin Plumb.  This code may be freely
  6. ; distributed under the terms of the GNU General Public Licence.
  7. ; Internet <colin@nyx.cs.du.edu>
  8.  
  9.         .model large
  10.         .code
  11.  
  12. ; A core operation in IDEA is multiplication modulo 65537.
  13. ; The valid inputs, 1 through 66636 inclusive are represented in
  14. ; 16-bit registers modulo 65536.  I.e. a value of 0 means 65536,
  15. ; or -1.  Thus, we need to test for that specially.  -x, modulo
  16. ; 65537, is 65537-x = 1-x.
  17. ; For any other number, represent the product as a*65536+b.  Since
  18. ; 65536 = -1 (mod 65537), this is the same number as b-a.  Should
  19. ; this result be negautive (generate a borrow), -n mod 65537 = 1-n
  20. ; mod 65536.  Or in other words, if you add the borrow bit back on,
  21. ; you get the right answer.
  22.  
  23. ; This is what the assembly code does.  It forms a zero, and adds
  24. ; that on with carry.
  25.  
  26. ; Another useful optimisation takes advantage of the fact that
  27. ; a and b are equal only if the answer is congruent to 0 mod 65537.
  28. ; Since 65537 is prime, this happens only if one of the inputs is
  29. ; congruent to 0 mod 65537.  Since the inputs are all less than 65537,
  30. ; this means it must have been zero.
  31.  
  32. ; The code below tests for a zero result of the subtraction, and if
  33. ; one arises, it branches out of line to figure out what happened.
  34.  
  35.  
  36. ; This code implemets the IDEA encryption algorithm.
  37. ; It follows in pseudo-C, where the * operator operates
  38. ; modulo 65537, as Idea needs.  (If you don't understand,
  39. ; learn IDEA better.)
  40.  
  41. ; IDEA is works on 16-bit units.  If you're processing bytes,
  42. ; it's defined to be big-endian, so an Intel machine needs to
  43. ; swap the bytes around.
  44.  
  45. ; void Idea(u_int16 *in, u_int16 *out, u_int16 *key)
  46. ; {
  47. ;        register u+int16 x0, x1, x2, x3, s1, s2, round;
  48. ;
  49. ;        x0 = *in++;  x1 = *in++;  x2 = *in++;  x3 = *in;
  50. ;
  51. ;        for (round = 0; round < 8; round++) {
  52. ;                x0 *= *key++;
  53. ;                x1 += *key++;
  54. ;                x2 += *key++;
  55. ;                x3 *= *key++;
  56. ;
  57. ;                s1  = x1;  s2  = x2;
  58. ;                x2 ^= x0;  x1 ^= x3;
  59. ;
  60. ;                x2 *= *key++;
  61. ;                x1 += x2;
  62. ;                x1 *= *key++;
  63. ;                x2 += x1;
  64. ;
  65. ;                x0 ^= x1;  x3 ^= x2;
  66. ;                x1 ^= s2;  x2 ^= s1;
  67. ;        }
  68. ;        *out++ = x0 * *key++;
  69. ;        *out++ = x2 + *key++;        /* Yes, this is x2, not x1 */
  70. ;        *out++ = x1 + *key++;
  71. ;        *out   = x3 * *key;
  72. ; }
  73.  
  74. ; ds:si points to key, ax, dx are temps, args in bx, cx, di, bp
  75. ; Trashes *all* registers.  direction flag must be clear.
  76. ; Leaves es zero.
  77.  
  78. ; Since there is no spare register to hold the loop count, I make
  79. ; clever use of the stack, pushing the start of the loop several
  80. ; times and using a ret instruction to do the return.
  81.  
  82. ; Annoyingly, lods is fastest on 8086's, but other techniques are
  83. ; best on 386's.  Well, that's what the manual says, but real
  84. ; life is different.  USELODS wins on a 386SX, at least.
  85. ; Leave it set for all platforms.
  86.  
  87. USELODS        equ        1
  88.  
  89. ; bp must be x0 for some of the code below to work
  90. x0        equ        bp
  91. x1        equ        bx
  92. x2        equ        cx
  93. x3        equ        di
  94. ; di must be x3 for some of the code below to work
  95.  
  96. ;; Now, this is rather interesting.  We test for zero arguments
  97. ;; after the multiply.  Assuming random inputs, one or both are
  98. ;; zero (2^17-1)/2^32, or approximately 1/32786 of the time.
  99. ;; Encryption in any feedback mode produces essentially random
  100. ;; inputs, so average-case analysis is okay.  While we don't
  101. ;; want the out-of-line code to waste time, it is not worth
  102. ;; slowing down the in-line case to speed it up.
  103. ;;
  104. ;; Basically, we start inverting the source x, and if that was 0,
  105. ;; we use the inverse of the key instead.
  106.  
  107. Core1Z:
  108.         neg        x0
  109.         jnz        Core1Za
  110. if USELODS
  111.         sub        x0,[si-2]
  112. else
  113.         sub        x0,[si]
  114. endif
  115. Core1Za:
  116.         inc        x0
  117.         jmp        Core1done
  118. Core2Z:
  119.         neg        x3
  120.         jnz        Core2Za
  121. if USELODS
  122.         sub        x3,[si-2]
  123. else
  124.         sub        x3,[si+6]
  125. endif
  126. Core2Za:
  127.         inc        x3
  128.         jmp        Core2done
  129. Core3Z:
  130.         neg        x2
  131.         jnz        Core3Za
  132. if USELODS
  133.         sub        x2,[si-2]
  134. else
  135.         sub        x2,[si+8]
  136. endif
  137. Core3Za:
  138.         inc        x2
  139.         jmp        Core3done
  140. Core4Z:
  141.         neg        x1
  142.         jnz        Core4Za
  143. if USELODS
  144.         sub        x1,[si-2]
  145. else
  146.         sub        x1,[si+10]
  147. endif
  148. Core4Za:
  149.         inc        x1
  150.         jmp        Core4done
  151.  
  152. ; We need a constant 0 that we can move into a register without affecting
  153. ; the carry flag (as the classic xor ax,ax is wont to do), so we use the
  154. ; es register for a constant 0 source.  This is okay even in protected
  155. ; mode.  (I *told* you this was tricky code!)
  156.  
  157. ; BTW, since you wanted to know, this is 8 + 78*4 + 16 = 336 instructions.
  158.  
  159. Core        proc        near
  160.         xor        ax,ax
  161.         mov        es,ax
  162.         mov        ax,OFFSET Finish
  163.         push        ax
  164.         mov        ax,OFFSET Coreloop
  165.         push        ax        ; Loop 3 times, then return
  166.         push        ax
  167.         push        ax
  168.  
  169. Coreloop:
  170. if USELODS
  171.         lodsw
  172. else
  173.         mov        ax,[si]                ; x0 *= *key++
  174. endif
  175.         mul        x0
  176.         sub        ax,dx
  177.         jz        Core1Z
  178.         mov        x0,es
  179.         adc        x0,ax
  180. Core1done:
  181.  
  182. if USELODS
  183.         lodsw
  184.         add        x1,ax
  185.         lodsw
  186.         add        x2,ax
  187. else
  188.         add        x1,[si+2]        ; x1 += *key++
  189.         add        x2,[si+4]        ; x2 += *key++
  190. endif
  191.  
  192. if USELODS
  193.         lodsw
  194. else
  195.         mov        ax,[si+6]        ; x3 += *key++
  196. endif
  197.         mul        x3
  198.         sub        ax,dx
  199.         jz        Core2Z
  200.         mov        x3,es
  201.         adc        x3,ax
  202. Core2done:
  203.  
  204.         push        x1                  ; s1 = x1
  205.         push        x2                ; s2 = x2
  206.  
  207.         xor        x1,x3                ; x1 ^= x3
  208.         xor        x2,x0                ; x2 ^= x0
  209.  
  210. if USELODS
  211.         lodsw
  212. else
  213.         mov        ax,[si+8]        ; x2 *= *key++
  214. endif
  215.         mul        x2
  216.         sub        ax,dx
  217.         jz        Core3Z
  218.         mov        x2,es
  219.         adc        x2,ax
  220. Core3done:
  221.  
  222.         add        x1,x2                ; x1 += x2
  223.  
  224. if USELODS
  225.         lodsw
  226. else
  227.         mov        ax,[si+10]        ; x1 *= *key++
  228. endif
  229.         mul        x1
  230.         sub        ax,dx
  231.         jz        Core4Z
  232.         mov        x1,es
  233.         adc        x1,ax
  234. Core4done:
  235.  
  236.         add        x2,x1                ; x2 += x1
  237.  
  238.         xor        x0,x1                ; x0 ^= x1
  239.         xor        x3,x2                ; x3 ^= x2
  240.  
  241.         pop        dx
  242.         xor        x1,dx                ; x1 ^= s2
  243.         pop        dx
  244.         xor        x2,dx                ; x2 ^= s1
  245.  
  246. ; Second unrolling of loop
  247. if USELODS
  248.         lodsw
  249. else
  250.         mov     ax,[si+12]          ; x0 *= *key++
  251. endif
  252.         mul        x0
  253.         sub        ax,dx
  254.         jz        Core5Z
  255.         mov        x0,es
  256.         adc        x0,ax
  257. Core5done:
  258.  
  259. if USELODS
  260.         lodsw
  261.         add        x1,ax
  262.         lodsw
  263.         add        x2,ax
  264. else
  265.         add        x1,[si+14]        ; x1 += *key++
  266.         add        x2,[si+16]        ; x2 += *key++
  267. endif
  268.  
  269. if USELODS
  270.         lodsw
  271. else
  272.         mov        ax,[si+18]        ; x3 *= *key++
  273. endif
  274.         mul        x3
  275.         sub        ax,dx
  276.         jz        Core6Z
  277.         mov        x3,es
  278.         adc        x3,ax
  279. Core6done:
  280.  
  281.         push        x1                   ; s1 = x1
  282.         push        x2                ; s2 = x2
  283.  
  284.         xor        x1,x3                ; x1 ^= x3
  285.         xor        x2,x0                ; x2 ^= x0
  286.  
  287. if USELODS
  288.         lodsw
  289. else
  290.         mov        ax,[si+20]        ; x2 *= *key++
  291. endif
  292.         mul        x2
  293.         sub        ax,dx
  294.         jz        Core7Z
  295.         mov        x2,es
  296.         adc        x2,ax
  297. Core7done:
  298.  
  299.         add        x1,x2                ; x1 += x2
  300.  
  301. if USELODS
  302.         lodsw
  303. else
  304.         mov        ax,[si+22]        ; x1 *= *key++
  305. endif
  306.         mul        x1
  307.         sub        ax,dx
  308.         jz        Core8Z
  309.         mov        x1,es
  310.         adc        x1,ax
  311. Core8done:
  312.  
  313.         add        x2,x1                ; x2 += x1
  314.  
  315.         xor        x0,x1                ; x0 ^= x1
  316.         xor        x3,x2                ; x3 ^= x2
  317.  
  318.         pop        dx
  319.         xor        x1,dx                ; x1 ^= s2
  320.         pop        dx
  321.         xor        x2,dx                ; x2 ^= s1
  322.  
  323. ife USELODS
  324.         lea        si,[si+24]
  325. endif
  326.  
  327.         ret        ; Used as a loop instruction!
  328.  
  329. Core5Z:
  330.         neg        x0
  331.         jnz        Core5Za
  332. if USELODS
  333.         sub        x0,[si-2]
  334. else
  335.         sub        x0,[si+12]
  336. endif
  337. Core5Za:
  338.         inc        x0
  339.         jmp        Core5done
  340. Core6Z:
  341.         neg        x3
  342.         jnz        Core6Za
  343. if USELODS
  344.         sub        x3,[si-2]
  345. else
  346.         sub        x3,[si+18]
  347. endif
  348. Core6Za:
  349.         inc        x3
  350.         jmp        Core6done
  351. Core7Z:
  352.         neg        x2
  353.         jnz        Core7Za
  354. if USELODS
  355.         sub        x2,[si-2]
  356. else
  357.         sub        x2,[si+20]
  358. endif
  359. Core7Za:
  360.         inc        x2
  361.         jmp        Core7done
  362. Core8Z:
  363.         neg        x1
  364.         jnz        Core8Za
  365. if USELODS
  366.         sub        x1,[si-2]
  367. else
  368.         sub        x1,[si+22]
  369. endif
  370. Core8Za:
  371.         inc        x1
  372.         jmp        Core8done
  373. Core9Z:
  374.         neg        x0
  375.         jnz        Core9Za
  376. if USELODS
  377.         sub        x0,[si-2]
  378. else
  379.         sub        x0,[si]
  380. endif
  381. Core9Za:
  382.         inc        x0
  383.         jmp        Core9done
  384. ; Special: compute into dx (zero on entry)
  385. Core10Z:
  386.         sub        dx,x3
  387.         jnz        Core10Za
  388. if USELODS
  389.         sub        dx,[si-2]
  390. else
  391.         sub        dx,[si+6]
  392. endif
  393. Core10Za:
  394.         inc        dx
  395. ;        jmp        Core10done
  396.         ret
  397.  
  398.  
  399. Finish:
  400. if USELODS
  401.         lodsw
  402. else
  403.         mov        ax,[si]                ; x0 *= *key++
  404. endif
  405.         mul        x0
  406.         sub        ax,dx
  407.         jz        Core9Z
  408.         mov        x0,es
  409.         adc        x0,ax
  410. Core9done:
  411.  
  412.         xchg        x1,x2
  413. if USELODS
  414.         lodsw
  415.         add        x1,ax
  416.         lodsw
  417.         add        x2,ax
  418. else
  419.         add        x1,[si+2]        ; x1 += *key++
  420.         add        x2,[si+4]       ; x2 += *key++
  421. endif
  422.  
  423. ; This is special: compute into dx, not x3
  424. if USELODS
  425.         lodsw
  426. else
  427.         mov        ax,[si+6]        ; x3 *= *key++
  428. endif
  429.         mul        x3
  430.         sub        ax,dx
  431.         mov        dx,es
  432.         jz        Core10Z
  433.         adc        dx,ax
  434. Core10done:
  435.  
  436.         ret
  437.  
  438.         endp
  439.  
  440.  
  441. ; Args are in, out, key
  442.         public        _Idea2
  443. _Idea2 proc far
  444.         cld
  445.         push        bp           ; Args start at [bp+6]
  446.         mov        bp,sp
  447.         push        si
  448.         push        di
  449.         push        ds        ; 6 more words here, so args are at [sp+12]
  450.         lds        si,[bp+6]        ; in
  451.         lodsw
  452.         xchg        ah,al
  453.         mov        dx,ax
  454.         lodsw
  455.         xchg        ah,al
  456.         mov        x1,ax
  457.         lodsw
  458.         xchg        ah,al
  459.         mov        x2,ax
  460.         lodsw
  461.         xchg        ah,al
  462.         mov        x3,ax
  463.         lds        si,[bp+14]        ; key
  464.  
  465.         mov        x0,dx
  466.  
  467.         call        Core
  468.  
  469.         mov        ax,x0
  470.         mov        bp,sp
  471.         les        di,[bp+16]
  472.         xchg        ah,al
  473.         stosw
  474.         mov        ax,x1
  475.         xchg        ah,al
  476.         stosw
  477.         mov        ax,x2
  478.         xchg        ah,al
  479.         stosw
  480.         mov        ax,dx
  481.         xchg        ah,al
  482.         stosw
  483.  
  484.         pop        ds
  485.         pop        di
  486.         pop        si
  487.         pop        bp
  488.  
  489.         ret
  490.  
  491.         endp
  492.  
  493. ; Okay, the basic plan for the CFB kernel is
  494. ; get x0,x1,x2,x3
  495. ; get key pointer
  496. ; call core
  497. ; get buffer pointers
  498. ;Loop:
  499. ; lodsw
  500. ; xor        ax,x0
  501. ; mov   x0,ax
  502. ; stosw
  503. ; lodsw
  504. ; xor        ax,x1
  505. ; mov        x0,ax
  506. ; stosw
  507. ; lodsw
  508. ; xor        ax,x2
  509. ; mov        x0,ax
  510. ; stosw
  511. ; lodsw
  512. ; xor        ax,x3
  513. ; mov        x3,ax
  514. ; stosw
  515. ; push buffer pointers
  516. ; get key pointer
  517. ; call        core
  518. ; pop buffer pointers
  519. ; loop
  520. ; lodsw/xor/etc.
  521. ;
  522. ;
  523. ; This function is designed to go in the middle of a byte-granularity
  524. ; CFB engine.  It performs "len" encryptions of the IV, encrypting
  525. ; 8*(len-1) bytes from the source to the destination.  The idea is
  526. ; that you first xor any odd leading bytes, then call this function,
  527. ; then xor up to 8 trailing bytes.
  528.  
  529. ; The main loop in this is 38 instructions, plus the 336 for the core
  530. ; makes 374 total.  That's 46.75 instructions per byte.
  531. ; (It's the same for IdeaCFBx)
  532.  
  533. ; IV, key, plain, cipher, len
  534.         public        _IdeaCFB
  535. _IdeaCFB proc far       ; Args are at [sp+4]
  536.         cld
  537.         push        bp
  538.         push        si
  539.         push        di
  540.         push        ds        ; 8 more words here, so args are at [sp+12]
  541. ; To be precise, IV is at 12, key at 16, plain at 20,
  542. ; cipher at 24 and len at 28
  543.         mov        bp,sp
  544.         lds        si,[bp+12]        ; IV
  545. ; Load and byte-swap IV
  546.         mov        ax,[si]
  547.         xchg        ah,al
  548.         mov        x1,[si+2]
  549.         mov        x2,[si+4]
  550.         xchg        bh,bl
  551.         xchg        ch,cl
  552.         mov        dx,[si+6]
  553.         xchg        dh,dl
  554.  
  555.         lds        si,[bp+16]        ; Key
  556.         mov        x0,ax
  557.         mov        x3,dx
  558.  
  559.         call        Core
  560. IdeaCFBLoop:
  561. ;        mov        ax,x0
  562. ;        mov        bp,sp
  563. ;        dec        WORD PTR [bp+28]        ; Decrement count
  564. ;        jz        IdeaCFBEnd
  565. ;        lds        si,[bp+20]
  566. ;        les        di,[bp+24]
  567. ;        mov        x0,ax
  568. ; Alternate code: (which is faster?  Two moves or three segment overrides?)
  569.         mov        si,sp
  570.         dec        WORD PTR ss:[si+28]
  571.         jz        IdeaCFBEnd
  572.         les        di,ss:[si+24]
  573.         lds        si,ss:[si+20]
  574.  
  575.         lodsw
  576.         xchg        ah,al
  577.         xor        ax,x0
  578.         mov        x0,ax
  579.         xchg        ah,al
  580.         stosw
  581.         lodsw
  582.         xchg        ah,al
  583.         xor        ax,x1
  584.         mov        x1,ax
  585.         xchg        ah,al
  586.         stosw
  587.         lodsw
  588.         xchg        ah,al
  589.         xor        ax,x2
  590.         mov        x2,ax
  591.         xchg        ah,al
  592.         stosw
  593.         lodsw
  594.         xchg        ah,al
  595.         xor        ax,dx
  596.         mov        dx,ax
  597.         xchg        ah,al
  598.         stosw
  599.  
  600. ;        mov        ax,x0
  601. ;        mov        bp,sp
  602. ;        mov        [bp+20],si        ; Save source offset
  603. ;        mov        [bp+24],di        ; Save destination offset
  604. ;        lds        si,[bp+16]        ; Key
  605. ;        mov        x0,ax                ; Get x0 in place for another iteration
  606. ; Alternate code for the above: (which is faster?  One move or three ss:?)
  607.         mov        ax,si
  608.         mov        si,sp
  609.         mov        ss:[si+20],ax
  610.         mov        ss:[si+24],di
  611.         lds        si,ss:[si+16]
  612.  
  613.         mov        x3,dx                ; Get x3 in place
  614.         mov        ax,OFFSET IdeaCFBLoop
  615.         push        ax
  616.         jmp        Core
  617.  
  618. IdeaCFBEnd:
  619. ;        lds        si,[bp+12]
  620.         lds        di,ss:[si+12]        ; Get IV for writing back
  621.  
  622.         mov        ax,x0
  623.         xchg        ah,al
  624.         mov        [di],ax                ; Use stosw?
  625.         xchg        bh,bl
  626.         xchg        ch,cl
  627.         mov        [di+2],x1
  628.         mov        [di+4],x2
  629.         xchg        dh,dl
  630.         mov        [di+6],dx
  631.  
  632.         pop        ds
  633.         pop        di
  634.         pop        si
  635.         pop        bp
  636.  
  637.         ret
  638.  
  639.         endp
  640.  
  641. ; This decoding step is similar, except that instead of
  642. ;        lods
  643. ;        xor        x0,ax
  644. ;        mov        ax,x0
  645. ;         stos
  646. ; the feedback step is
  647. ;        lods
  648. ;        xchg        x0,ax
  649. ;        xor        ax,x0
  650. ;        stos
  651.  
  652. ; IV, key, cipher, plain, len
  653.         public        _IdeaCFBx
  654. _IdeaCFBx proc far       ; Args are at [sp+4]
  655.         cld
  656.         push        bp
  657.         push        si
  658.         push        di
  659.         push        ds        ; 8 more words here, so args are at [sp+12]
  660.         mov        bp,sp
  661.         lds        si,[bp+12]        ; IV
  662. ; Load and byte-swap IV
  663.         mov        ax,[si]
  664.         xchg        ah,al
  665.         mov        x1,[si+2]
  666.         mov        x2,[si+4]
  667.         xchg        bh,bl
  668.         xchg        ch,cl
  669.         mov        dx,[si+6]
  670.         xchg        dh,dl
  671.  
  672.         lds        si,[bp+16]        ; Key
  673.         mov        x0,ax
  674.         mov        x3,dx
  675.  
  676.         call        Core
  677. IdeaCFBxLoop:
  678. ;        mov        ax,x0
  679. ;        mov        bp,sp
  680. ;        dec        WORD PTR [bp+28]        ; Decrement count
  681. ;        jz        IdeaCFBxEnd
  682. ;        lds        si,[bp+20]
  683. ;        les        di,[bp+24]
  684. ;        mov        x0,ax
  685. ; Alternate code: (which is faster?  Two moves or three segment overrides)
  686.         mov        si,sp
  687.         dec        WORD PTR ss:[si+28]
  688.         jz        IdeaCFBxEnd
  689.         les        di,ss:[si+24]
  690.         lds        si,ss:[si+20]
  691.  
  692.         lodsw
  693.         xchg        ah,al
  694.         xchg        x0,ax
  695.         xor        ax,x0
  696.         xchg        ah,al
  697.         stosw
  698.         lodsw
  699.         xchg        ah,al
  700.         xchg        x1,ax
  701.         xor        ax,x1
  702.         xchg        ah,al
  703.         stosw
  704.         lodsw
  705.         xchg        ah,al
  706.         xchg        x2,ax
  707.         xor        ax,x2
  708.         xchg        ah,al
  709.         stosw
  710.         lodsw
  711.         xchg        ah,al
  712.         xchg        dx,ax
  713.         xor        ax,dx
  714.         xchg        ah,al
  715.         stosw
  716.  
  717. ;        mov        ax,x0
  718. ;        mov        bp,sp
  719. ;        mov        [bp+20],si        ; Save source offset
  720. ;        mov        [bp+24],di        ; Save destination offset
  721. ;        lds        si,[bp+16]        ; Key
  722. ;        mov        x0,ax                ; Get x0 in place for another iteration
  723. ; Alternate code for the above: (which is faster?  One move or three ss:?)
  724.         mov        ax,si
  725.         mov        si,sp
  726.         mov        ss:[si+20],ax
  727.         mov        ss:[si+24],di
  728.         lds        si,ss:[si+16]
  729.  
  730.         mov        x3,dx                ; Get x3 in place
  731.         mov        ax,OFFSET IdeaCFBxLoop
  732.         push        ax
  733.         jmp        Core
  734.  
  735. IdeaCFBxEnd:
  736. ;        lds        si:[bp+12]
  737.         lds        di,ss:[si+12]        ; Get IV for writing back
  738.  
  739.         mov        ax,x0
  740.         xchg        ah,al
  741.         mov        [di],ax                ; Use stosw?
  742.         xchg        bh,bl
  743.         xchg        ch,cl
  744.         mov        [di+2],x1
  745.         mov        [di+4],x2
  746.         xchg        dh,dl
  747.         mov        [di+6],dx
  748.  
  749.  
  750.         pop        ds
  751.         pop        di
  752.         pop        si
  753.         pop        bp
  754.  
  755.         ret
  756.  
  757.         endp
  758.  
  759.  
  760.  
  761.  
  762.         end
  763.