home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / C / Samples / CASM.ARJ / ALLOC.ASM next >
Assembly Source File  |  1988-05-05  |  15KB  |  771 lines

  1. ;_ alloc.asm   Thu May  5 1988   Modified by: Walter Bright */
  2. ; Copyright (C) 1985-1988 by Northwest Software
  3. ; All rights reserved
  4. ; Written by Walter Bright
  5.  
  6. include    macros.asm
  7.  
  8. ;;;;;;;;;;;;;;;;;;;;;;;;;;
  9. ; Do far pointer normalization
  10. ; SCRATCH is a scratch register we can destroy
  11.  
  12. normptr    macro    MSREG,LSREG,SCRATCH
  13.     mov    SCRATCH,LSREG
  14.     and    LSREG,0Fh
  15.     shr    SCRATCH,1
  16.     shr    SCRATCH,1
  17.     shr    SCRATCH,1
  18.     shr    SCRATCH,1
  19.     add    MSREG,SCRATCH
  20.     endm
  21.  
  22.     if LCODE
  23.     c_extrn    sbrk,far
  24.     else
  25.     c_extrn    sbrk,near
  26.     endif
  27.  
  28.     begcode    alloc
  29.  
  30.     c_public malloc,calloc,realloc,free
  31.  
  32. ; Storage allocator
  33.  
  34.     begdata
  35.     c_public _baslnk
  36.  
  37.     if SPTR
  38.     c_extrn    _pastdata,word, _heapbottom,word
  39.     endif
  40.  
  41. if MSC
  42.     if SPTR
  43. __baslnk    dw    offset DGROUP:__baslnk    ;starting link for
  44.                         ; storage allocator
  45.         dw    0    ;give it a size of 0 so it is never allocated
  46. __allocp    dw    offset DGROUP:__baslnk    ;roving pointer for allocator
  47.     else
  48.  
  49. __baslnk    dw    offset DGROUP:__baslnk
  50.         dw    seg DGROUP:__baslnk
  51.         dw    0
  52.  
  53. __allocp    dw    -1,?
  54.     endif
  55. _allocp    equ    __allocp
  56. _baslnk equ    __baslnk
  57. else
  58.     if SPTR
  59. _baslnk        dw    offset dgroup:_baslnk    ;starting link for
  60.                         ; storage allocator
  61.         dw    0    ;give it a size of 0 so it is never allocated
  62. _allocp        dw    offset dgroup:_baslnk    ;roving pointer for allocator
  63.     else
  64.  
  65. _baslnk    dw    offset dgroup:_baslnk
  66.     dw    seg dgroup:_baslnk
  67.     dw    0
  68.  
  69. _allocp    dw    -1,?
  70.     endif
  71. endif
  72.     enddata
  73.  
  74. ; A block in the free list consists of:
  75. ;    dw    pointer to next block in list
  76. ;    dw    segment of next block in list (for LPTR)
  77. ;    dw    size of block in bytes (must be even) (including both words)
  78.  
  79. ; When it's allocated,
  80. ;    dw    # of bytes in this block including this word
  81. ;    db...    the bytes allocated
  82.  
  83. .if32    macro    r1H,r1L,b,r2H,r2L,lbl
  84.     local    L1
  85.     .if    r1H ne r2H, L1
  86.     cmp    r1L,r2L
  87. L1:    j&b    lbl
  88.     endm
  89.  
  90. mov32    macro    ah,al,bh,bl
  91.     mov    ah,bh
  92.     mov    al,bl
  93.     endm
  94.  
  95. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  96. ; Allocate a block of data and clear it.
  97. ; Use:
  98. ;    p = calloc(numelems,sizeof(elem));
  99. ; Returns:
  100. ;    pointer to allocated data else NULL
  101.  
  102. func    calloc
  103.     push    BP
  104.     mov    BP,SP
  105.     mov    AX,P[BP]    ;get numelems
  106.     mov    BX,P+2[BP]    ;get sizeof(elem)
  107.     .if    BX e 1, C1    ;no need to multiply
  108.     mul    BX
  109.     jc    C3        ;if overflow
  110. C1:    push    AX        ;nbytes
  111.     callm    malloc
  112.     mov    SP,BP
  113.     ifdef MSC
  114.       if SPTR
  115.     tst    AX
  116.       else
  117.     tst    DX
  118.       endif
  119.     else
  120.     tst    AX        ;error?
  121.     endif
  122.     jz    C2        ;yes
  123.     .save    <DI>
  124.     if SPTR
  125.       ife ESeqDS
  126.     mov    DX,DS
  127.     mov    ES,DX
  128.       endif
  129.     mov    DI,AX
  130.     mov    DX,AX        ;save pointer to result
  131.     mov    CX,-2[DI]    ;# of bytes
  132.     else
  133.       ifdef MSC
  134.     mov    ES,DX
  135.     mov    DI,AX
  136.     mov    BX,AX
  137.       else
  138.     mov    ES,AX
  139.     mov    DI,BX
  140.       endif
  141.     mov    CX,ES:-2[DI]
  142.     endif
  143.     shr    CX,1        ;# of words (including byte count)
  144.     dec    CX        ;skip # of bytes
  145.     clr    AX
  146.     cld
  147.     rep    stosw        ;clear the memory
  148.     if SPTR
  149.     mov    AX,DX        ;restore pointer to result
  150.     else
  151.       ifdef MSC
  152.     mov    AX,BX        ;DX:AX is pointer to result
  153.       else
  154.     mov    AX,ES        ;restore pointer to result
  155.       endif
  156.     endif
  157.     .restore <DI>
  158. C2:
  159.     pop    BP
  160.     ret
  161.  
  162.     if SPTR
  163. C3:    clr    AX
  164.     pop    BP
  165.     ret
  166.     endif
  167.     if LPTR
  168. C3:    clr    AX
  169.       ifdef MSC
  170.     cwd
  171.       else
  172.     mov    BX,AX
  173.       endif
  174.     pop    BP
  175.     ret
  176.     endif
  177. c_endp    calloc
  178.  
  179. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  180. ; Allocate a block of data.
  181. ; Use:
  182. ;    char *malloc();
  183. ;    p = malloc(nbytes);
  184. ; Returns:
  185. ;    pointer to allocated data else NULL
  186.  
  187. func    malloc
  188.     if SPTR
  189.     push    BP
  190. A4:
  191.     mov    BP,SP
  192.     .save    <SI,DI>
  193.     mov    AX,P[BP]    ;get nbytes
  194.     add    AX,3        ;need another word for length info
  195.     and    AX,0FFFEh    ;round up to nearest word
  196.     .if    AX b 4, allocerr    ;can't allocate 0 bytes
  197.  
  198.     mov    BP,2        ;save some bytes
  199. ;    mov    SI,_allocp    ;last item
  200.     mov    SI,_baslnk    ;last item
  201.     mov    CX,SI        ;CX to save bytes
  202.     jmps    A2
  203.  
  204. A1:    mov    SI,DI
  205.     .if    SI e CX, trysbrk    ;wrapped around, didn't find any
  206. A2:    mov    DI,[SI]            ;next item in list
  207.     .if    AX a [DI+BP], A1    ;not big enough
  208.  
  209.     je    A3        ;exactly big enough
  210.     add    AX,BP        ;we'll need another 2 bytes
  211.     .if    AX e [DI+BP],A3    ;have to allocate an entire block
  212.     sub    AX,BP
  213.  
  214. ;Allocate from bottom of free block. Desirable in order to delay
  215. ;stack overflow as long as possible.
  216. ; DI -> free block
  217. ; SI -> previous free block
  218. ; AX =  # of bytes in allocated block
  219.     add    [SI],AX        ;link to new free block
  220.     mov    SI,[SI]        ;pointer to new free block
  221.     mov    CX,[DI+BP]    ;number of bytes in block we're splitting
  222.     sub    CX,AX        ;CX = remaining bytes
  223.     mov    [SI+BP],CX    ;# of bytes in this block
  224.  
  225. A3:    xchg    AX,[DI]        ;[DI] = # of bytes, AX = next free block
  226.     mov    [SI],AX        ;skip the DI entry in list
  227.     mov    _allocp,SI
  228.     lea    AX,[DI+BP]    ;pointer to area allocated (DI + 2)
  229. A6:    .restore <DI,SI>
  230.     pop    BP
  231.     ret
  232.  
  233. trysbrk:            ;try sbrk() to grow our data segment
  234.     .if    AX ae 256, A5
  235.     mov    AX,256        ;256 byte chunk minimum size
  236. A5:    push    AX
  237.     callm    sbrk
  238.     pop    BX
  239.     .if    AX e -1, allocerr    ;failed
  240.     add    AX,2        ;point past # of bytes allocated
  241.     push    AX
  242.     callm    free        ;add allocated memory into free list
  243.     pop    BX
  244.     .restore <DI,SI>
  245.     jmp    A4        ;try again
  246.  
  247. allocerr:
  248.     clr    AX        ;NULL
  249.     jmp    A6
  250.  
  251.     else ;LPTR
  252. ;;;;;;;;;;;;;;;;;;;;;;;;
  253. ; malloc() for large data models
  254.  
  255.     push    BP
  256.     push    DS
  257.     .if    _allocp ne -1, A4    ;if already initialized
  258.     mov32    AX,BX _baslnk+2,_baslnk
  259.     normptr    AX,BX, CX        ;normalize _baslnk
  260.     mov32    _baslnk+2,_baslnk AX,BX
  261.     mov32    _allocp+2,_allocp AX,BX
  262.  
  263. A4:    mov    BP,SP
  264.     .save    <SI,DI>
  265. ;A4:    nbytes = (nbytes + 3) / 4 * 4
  266.     mov    BP,P+2[BP]
  267.     add    BP,3
  268.     and    BP,0FFFEh
  269. ;    if (nbytes < 4)
  270. ;        return 0
  271.     .if    BP ae 4, A12
  272. A13:    jmp    mallocerr
  273. A12:
  274. ;    if (nbytes < 6)
  275.     .if    BP ae 6, A5
  276. ;        nbytes = 6
  277.         mov    BP,6
  278. A5:
  279. ;    pstart = _baslnk
  280.     mov32    DX,DI _baslnk+2,_baslnk
  281. ;    p = pstart
  282.     mov32    CX,SI DX,DI
  283. ;    loop
  284. A7:        mov    ES,CX
  285. ;        pnext = p->next
  286.         mov32    AX,BX ES:2[SI],ES:[SI]
  287. ;        if (nbytes <= pnext->size)
  288. ;            break
  289.         mov    ES,AX
  290.         .if    BP be ES:4[BX], A6
  291. ;        p = pnext
  292.         mov32    CX,SI AX,BX
  293. ;        if (p == pstart)
  294.         .if32    CX,SI ne DX,DI, A7
  295. ;            p = wsbrk(nbytes)
  296.             .if    BP ae 512, A14
  297.             mov    BP,512        ;512 minimum growth size
  298.         A14:    push    BP
  299.             callm    sbrk        ;extend program segment
  300.             pop    BP        ;fix stack
  301. ;            if (p == -1)
  302. ;                return 0
  303.             ifdef MSC
  304.             mov    BX,AX
  305.             mov    AX,DX
  306.             endif
  307.             .if    BX e -1, A13    ;error
  308. ;            wfree(p + 2)
  309.             add    BX,2
  310.             push    AX
  311.             push    BX
  312.             callm    free        ;free new block
  313.             add    SP,4
  314.             .if    AX e -1, mallocerr
  315. ;            goto A4
  316.             .restore <DI,SI>
  317.             jmp    A4
  318. A6:                        ; We have:
  319.                         ;    pnext -> block to alloc
  320.                         ;    pnext = AX,BX
  321. ;
  322. ;    _allocp = p
  323.     mov32    _allocp+2,_allocp CX,SI
  324. ;    if (nbytes + sizeof(*pnext) > pnext->size)
  325.     mov    DX,BP
  326.     add    DX,6
  327.     jc    A10
  328.     .if    DX be ES:4[BX], A9
  329. ;        Allocate entire block that pnext points to.
  330. ;        p->next = pnext->next
  331. A10:        mov32    DX,DI ES:2[BX],ES:[BX]
  332.         mov    ES,CX
  333.         mov32    ES:2[SI],ES:[SI] DX,DI
  334. ;        *pnext = pnext->size
  335.         mov    ES,AX
  336.         mov    DX,ES:4[BX]
  337.         mov    ES:[BX],DX
  338. ;        goto A8
  339.         jmp    A8
  340.  
  341. A9:    
  342. ; Create new block pnew that consists of the remainder of pnext.
  343. ; At this point, we have:
  344. ;    BP = nbytes
  345. ;    CX:SI = p
  346. ;    AX:BX = pnext
  347. ;    ES = AX
  348.  
  349. ;    pnew = pnext + nbytes
  350.  
  351.     mov32    DX,DI AX,BX
  352.     add    DI,BP            ;no overflow possible here
  353.     normptr    DX,DI, AX
  354.     mov    AX,ES            ;restore AX
  355.  
  356. ;    pnew->size = pnext->size - nbytes
  357.     push    BP
  358.     neg    BP
  359.     add    BP,ES:4[BX]
  360.     mov    ES,DX
  361.     mov    ES:4[DI],BP
  362. ;    pnew->next = pnext->next
  363.     mov    DS,AX
  364.     mov    DX,[BX]
  365.     mov    ES:[DI],DX
  366.     mov    DX,2[BX]
  367.     mov    ES:2[DI],DX
  368.     mov    DX,ES
  369. ;    p->next = pnew
  370.     mov    ES,CX
  371.     mov32    ES:2[SI],ES:[SI] DX,DI
  372. ;    *pnext = nbytes
  373.     pop    BP
  374.     mov    [BX],BP                ;DS == AX
  375. ;A8:    return pnext + 2
  376. A8:    add    BX,2
  377.     ifdef MSC
  378.     xchg    DX,AX
  379.     xchg    AX,BX
  380.     endif
  381. A11:    .restore <DI,SI>
  382.     pop    DS
  383.     pop    BP
  384.     ret
  385.  
  386. mallocerr:
  387.     clr    AX
  388.       ifdef MSC
  389.     cwd
  390.       else
  391.     mov    BX,AX
  392.       endif
  393.     jmp    A11
  394.     endif
  395. c_endp    malloc
  396.  
  397. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  398. ; Reallocate memory that was allocated by malloc() or calloc().
  399. ; Use:
  400. ;    char *realloc(char *p, unsigned nbytes)
  401. ; Returns:
  402. ;    0 error
  403. ;    else pointer to reallocated memory
  404.  
  405. func    realloc
  406.     push    BP
  407.     mov    BP,SP
  408.  
  409.     mov    AX,P+SIZEPTR[BP]    ;AX = nbytes
  410.     tst    AX            ;trying to realloc() to 0 size?
  411.     jnz    R6            ;no
  412.     pop    BP
  413.     jmp    near ptr free        ;free(p)
  414.  
  415. R6:
  416.     ;if realloced size is smaller, attempt to just shrink current block
  417.     if SPTR
  418.     mov    BX,P[BP]    ;BX = p
  419.     tst    BX        ;is p NULL?
  420.     jnz    R5        ;no
  421.     ;function just like malloc(nbytes)
  422.     push    AX
  423.     callm    malloc
  424.     mov    SP,BP
  425.     pop    BP
  426.     ret
  427.  
  428. R5:    sub    BX,2
  429.     mov    CX,[BX]        ;CX = # of bytes in this block
  430.     else
  431.     les    BX,P[BP]    ;ES:BX = p
  432.     mov    CX,ES
  433.     or    CX,BX        ;is p NULL?
  434.     jnz    R5        ;no
  435.     ;function just like malloc(nbytes)
  436.     push    AX
  437.     callm    malloc
  438.     mov    SP,BP
  439.     pop    BP
  440.     ret
  441.  
  442. R5:    sub    BX,2
  443.     mov    CX,ES:[BX]
  444.     endif
  445.     add    AX,3
  446.     and    AL,0FEh        ;AX = real new size
  447.     sub    CX,AX
  448.     jb    R3            ;if allocating more bytes
  449.     .if    CX b <SIZEPTR+2>, R4    ;size of free list entry
  450.     .save    <DI>
  451.      mov    DI,BX
  452.     add    DI,AX
  453.     if SPTR
  454.     mov    [DI],CX        ;size of new fragment
  455.     add    DI,2
  456.     mov    [BX],AX        ;realloced size of p
  457.     push    DI
  458.     callm    free
  459.     pop    DI
  460.     else
  461.     mov    ES:[DI],CX    ;size of new fragment
  462.     mov    ES:[BX],AX    ;realloced size of p
  463.     mov    BX,DI
  464.     mov    AX,ES        ;AX:BX is pointer to new fragment
  465.     normptr    AX,BX, CX    ;normalize it
  466.     add    BX,2        ;point past size of fragment
  467.     push    AX
  468.     push    BX
  469.     callm    free
  470.     add    SP,SIZEPTR
  471.     endif
  472.     .restore <DI>
  473. R4:
  474.     if SPTR
  475.     mov    AX,P[BP]
  476.     else
  477.       ifdef MSC
  478.     mov32    DX,AX P+2[BP],P[BP]    ;reload original pointer p
  479.       else
  480.     mov32    AX,BX P+2[BP],P[BP]    ;reload original pointer p
  481.       endif
  482.     endif
  483.     jmps    R1        ;no change, return p
  484.  
  485.     ;we'll have to allocate a new block, and free the old one
  486. R3:
  487.     push    P+SIZEPTR[BP]
  488.     callm    malloc        ;malloc(nbytes)
  489.     mov    SP,BP
  490.     if LPTR
  491.       ifdef MSC
  492.     tst    DX
  493.       else
  494.     tst    AX
  495.       endif
  496.     else
  497.     tst    AX
  498.     endif
  499.     jz    rallocerr    ;error
  500.     push    AX        ;save pointer to new memory
  501.     .save    <SI,DI>
  502.     if SPTR
  503.     mov    SI,P[BP]    ;DS:SI -> original
  504.       ife ESeqDS
  505.     mov    CX,DS
  506.     mov    ES,CX
  507.       endif
  508.     mov    DI,AX        ;ES:DI -> new item
  509.     mov    CX,-2[SI]
  510.     .if    CX be -2[DI], R2
  511.     mov    CX,-2[DI]    ;CX = smaller of two size
  512. R2:    shr    CX,1        ;# of words
  513.     dec    CX        ;compensate for extra word in beginning
  514.     cld
  515.     rep    movsw        ;transfer the words
  516.     push    P[BP]
  517.     callm    free        ;free the old one
  518.     add    SP,SIZEPTR
  519.     else
  520.       ifdef MSC
  521.     push    DX
  522.       else
  523.     push    BX
  524.       endif
  525.     push    DS
  526.     lds    SI,P[BP]    ;DS:SI -> original
  527.       ifdef MSC
  528.     mov    ES,DX
  529.     mov    DI,AX        ;ES:DI -> new item
  530.       else
  531.     mov    ES,AX
  532.     mov    DI,BX        ;ES:DI -> new item
  533.       endif
  534.     mov    CX,-2[SI]
  535.     .if    CX be ES:-2[DI], R2
  536.     mov    CX,ES:-2[DI]    ;CX = smaller of two sizes
  537. R2:    shr    CX,1        ;# of words
  538.     dec    CX        ;compensate for extra word in beginning
  539.     cld
  540.     rep    movsw        ;transfer the words
  541.     pop    DS
  542.     push    P+2[BP]
  543.     push    P[BP]
  544.     callm    free        ;free the old one
  545.     add    SP,SIZEPTR
  546.       ifdef MSC
  547.     pop    DX
  548.       else
  549.     pop    BX
  550.       endif
  551.     endif
  552.     .restore <DI,SI>
  553.     tst    AX
  554.     pop    AX        ;restore pointer to new memory
  555.     jz    R1
  556. rallocerr:
  557.     clr    AX
  558.     if LPTR
  559.       ifdef MSC
  560.     cwd
  561.       else
  562.     mov    BX,AX
  563.       endif
  564.     endif
  565. R1:    pop    BP
  566.     ret
  567. c_endp    realloc
  568.  
  569. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  570. ; Free memory that was allocated by malloc() or calloc().
  571. ; Use:
  572. ;    free(p);
  573. ; Returns:
  574. ;    0    success
  575. ;    -1    error
  576.  
  577. func    free
  578.     if SPTR
  579.     push    BP
  580.     mov    BP,SP
  581.     .save    <SI,DI>
  582.     mov    BX,P[BP]        ;get p
  583.     tst    BX            ;pass a NULL pointer?
  584.     jz    F5            ;yes, return 0
  585.     mov    BP,2            ;to save some bytes
  586.                     ;check if below bottom of pool
  587.     .if    BX be _heapbottom, freeerr    ;if below bottom of pool
  588.     .if    BX ae _pastdata, freeerr    ;if above top of pool
  589.     test    BX,1            ;odd?
  590.     jne    freeerr
  591.     sub    BX,BP            ;point to start of block
  592.     mov    AX,[BX]            ;# of bytes in block to be freed
  593.  
  594. ; Try to find SI and DI such that SI < BX < DI
  595.  
  596.     mov    SI,_allocp        ;try our roving pointer
  597.     .if    SI b BX, F1        ;a good starting point
  598.     mov    SI, offset DGROUP:_baslnk
  599.     jmps    F1
  600.  
  601. F6:    mov    SI,DI
  602. F1:    mov    DI,[SI]            ;the next in the list
  603.     .if    SI ae BX, freeerr
  604.     .if    DI a BX, F2        ;got it
  605.     .if    DI a SI, F6        ;no wrap around (SI < DI < BX)
  606.  
  607. ; We have SI < BX < DI (relative position in list)
  608.  
  609. F2:    mov    CX,[SI+BP]        ;# of bytes in previous block
  610.     add    CX,SI            ;+ link
  611.     .if    CX ne BX, F3        ;if can't collapse with prev block
  612.     add    [SI+BP],AX
  613.     jmps    F4
  614.  
  615. F3:    mov    2[BX],AX        ;store # of bytes in freed block
  616.     mov    [BX],DI            ;link to block after BX
  617.     mov    [SI],BX            ;link to BX
  618.     mov    SI,BX
  619.  
  620. ; See if we can collapse SI with DI
  621. ; SI -> block just before DI
  622. ; DI -> block just after SI
  623. ; BP = 2
  624.  
  625. F4:    mov    _allocp,SI        ;for next time
  626.     mov    AX,[SI+BP]
  627.     add    AX,SI
  628.     .if    AX ne DI, F5        ;nope
  629.     mov    AX,[DI]            ;link after DI
  630.     mov    [SI],AX            ;becomes link after SI
  631.     mov    AX,[DI+BP]        ;# of bytes in DI
  632.     add    [SI+BP],AX        ;add to # of bytes in SI
  633.  
  634. F5:    clr    AX            ;success
  635. F7:    .restore <DI,SI>
  636.     pop    BP
  637.     ret
  638.  
  639. freeerr:
  640.     mov    AX,-1            ;error
  641.     jmp    F7
  642.  
  643.     else ;LPTR
  644. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  645. ; free() for large data models
  646.  
  647.     push    BP
  648.     mov    BP,SP
  649.     .save    <SI,DI>
  650.     push    DS
  651.     mov32    DX,DI P+2[BP],P[BP]        ;DX:DI = pfree
  652. ;    if (pfree == NULL)
  653. ;        return 0;
  654.     mov    AX,DX
  655.     or    AX,DI
  656.     jnz    F9
  657.     jmp    F4
  658.  
  659. ;    if (pfree <= _heapbottom || pfree >= _pastdata || pfree & 1)
  660. ;        goto freeerr
  661. F9:    test    DI,1            ;odd pointers are errors
  662.     je    F7
  663. F8:    jmp    freeerr
  664. F7:
  665. ;    pfree -= 2
  666.     sub    DI,2
  667. ;    p = (_allocp < pfree) ? _allocp : &_baslnk
  668.     mov32    CX,SI _allocp+2,_allocp        ;CX:SI = _allocp
  669.     .if32    CX,SI b DX,DI, F1
  670.     mov32    CX,SI <seg DGROUP:_baslnk>,<offset DGROUP:_baslnk>
  671. F1:    mov    ES,CX            ;ES:SI = p
  672. ;    loop
  673. ;        pnext = p->next
  674.         mov32    AX,BX ES:2[SI],ES:[SI]        ;AX:BX = pnext
  675. ;        if (p >= pfree)
  676. ;            goto freeerr
  677.         .if32 CX,SI ae DX,DI, F8
  678. ;        if (pnext > pfree || pnext <= p)
  679. ;            break
  680.         .if32 AX,BX a  DX,DI, F2
  681.         .if32 AX,BX be CX,SI, F2
  682. ;        p = pnext
  683.         mov32    CX,SI AX,BX
  684.         jmp    F1
  685. F2:
  686. ;    _allocp = p
  687.     mov32    _allocp+2,_allocp CX,SI
  688. ;    pfree->size = *pfree
  689.     mov    DS,DX
  690.     mov    BP,[DI]
  691.     mov    4[DI],BP
  692. ;    pfree->next = pnext
  693.     mov32    2[DI],[DI] AX,BX
  694. ;    p->next = pfree
  695.     mov    DS,CX
  696.     mov32    2[SI],[SI] DX,DI
  697. ;    if (p + p->size != pfree)
  698.     mov32    AX,BX CX,SI
  699.     add    BX,4[SI]
  700.     normptr    AX,BX, CX        ;normalize AX,BX
  701.     mov    CX,DS            ;restore CX
  702.     .if32    AX,BX e DX,DI, F3
  703. ;        p = pfree
  704.         mov32    CX,SI DX,DI
  705. F3:
  706. ;    while (p + p->size == p->next)
  707.     mov    DS,CX
  708.     mov32    AX,BX CX,SI
  709.     add    BX,4[SI]
  710.     normptr    AX,BX, DX        ;normalize AX,BX
  711.     mov32    DX,DI 2[SI],[SI]    ;DX:DI = p->pnext
  712.     mov    ES,DX
  713.     .if32    AX,BX ne DX,DI, F4
  714.  
  715. ;        if (p->size + p->next->size < 64k)
  716.         mov    BP,4[SI]
  717.         add    BP,ES:4[DI]
  718.         jc    F5
  719. ;            p->size += p->next->size
  720.             mov    4[SI],BP
  721. ;            p->next = p->next->next
  722.             mov    AX,ES:[DI]
  723.             mov    [SI],AX
  724.             mov    AX,ES:2[DI]
  725.             mov    2[SI],AX
  726.             jmp    F3
  727. ;        else
  728. F5:
  729. ;            pnew = p + 64k - 16        ;CX:SI = p
  730.             mov    AX,CX
  731.             add    AX,0FFFh        ;AX:SI = pnew
  732.             mov    DS,AX            ;DS:SI = pnew
  733.  
  734. ;            pnew->next = p->next->next    ;ES:DI = p->next
  735.             mov32    AX,BX ES:2[DI],ES:[DI]
  736.             mov32    2[SI],[SI] AX,BX
  737.  
  738. ;            pnew->size = p->size + p->next->size - (64k - 16)
  739.             sub    BP,0FFF0h
  740.             mov    4[SI],BP
  741. ;            p->next = pnew
  742.             mov    AX,DS
  743.             mov    DS,CX
  744.             mov32    2[SI],[SI] AX,SI
  745. ;            p->size = (64k - 16)
  746.             mov    4[SI],0FFF0h
  747. ;            p = pnew
  748.             mov    CX,AX    ;only the segments are different
  749.             jmp    F3
  750. ;    return 0
  751. F4:    clr    AX
  752.     ifdef MSC
  753.     cwd            ;return NULL (for realloc())
  754.     else
  755.     mov    BX,AX
  756.     endif
  757. F6:    pop    DS
  758.     .restore <DI,SI>
  759.     pop    BP
  760.     ret
  761. ;
  762. freeerr:
  763. ;    return -1
  764.     mov    AX,-1
  765.     jmp    F6
  766.     endif
  767. c_endp    free
  768.  
  769.     endcode    alloc
  770.     end
  771.