home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / asmutil / x2b11.zip / X2B11.ASM < prev   
Assembly Source File  |  1989-10-14  |  18KB  |  568 lines

  1. Comment    ~
  2.     X2B.ASM
  3.     A replacement for the Exe2Bin program, which is NOT included with
  4.     PC-DOS 3.3.
  5.     written by Henry T. Nettles, Dec. 21, 1987 -- Feb. 20, 1988
  6.     compiled with MicroSoft Macro Assembler, version 5.0
  7.     The inspiration (and model) for this program was EXE2COM.C, written
  8.     by Chris Dunford.
  9.     The include module, DOS.INC, comes with MASM 5.0
  10.     The subroutine BinToStr is borrowed from the SHOW.ASM program which
  11.     also comes with MASM 5.0
  12.     Some of this code (the command line parser) is borrowed from a program
  13.     by Vernon Buerg (TABS.ASM)
  14.     This program is hereby released to the public domain.
  15.  
  16.     Usage:  >X2B  [d:][\path\]PROG[.EXE]  [d:][\path\][PROG][.COM]
  17.  
  18.     The only necessary parameter is the file name of the input file.  A
  19.     drive and/or path may be given if needed.
  20.     If no extension is given, .EXE is assumed.  If no ouput file is
  21.     given, then the same file name with an extension of .COM is used.
  22.     WARNING: If a drive and/or path is given for the input file, and
  23.     no ouput file is given, then the input drive and/or path will be
  24.     used for the ouput (not the default directory).
  25.  
  26.     This program works on my computer, on the files I have tried it on.
  27.     However, extensive testing has not been performed, and I assume no
  28.     responsibility whatever for the program.  I would be interested in
  29.     bug reports, and if anyone improves the code it would be nice to
  30.     receive a copy.  I can be reached at:
  31.  
  32.             22547 Braken Carter
  33.             Katy, Texas 77449-3619
  34.  
  35. Toad Hall Tweak, 15 Oct 89
  36. - Converted to .COM format
  37. - General tightening
  38. - Moved EXE header buffer, filename buffers to dynamic space at code end
  39.   (to reduce program size)
  40. - Changed BinToStr procedure so it carries parms directly in AX/DI
  41.   instead of the slow pushes.
  42. - Removed some unnecessary local variables
  43.  
  44. Comment    ends    ~
  45.  
  46. RECSIZE        equ    512
  47. CMDTAIL        equ    80h
  48. CR        equ    0dh
  49. LF        equ    0ah
  50. EOM        equ    '$'
  51. SIZE_OF_HEADER    equ    28
  52.  
  53. exe_header    STRUC        ; what an exe header looks like
  54. exe_sig1    db    0    ; EXE file signature: "MZ"
  55. exe_sig2    db    0
  56. excess        dw    0    ; image size mod 512 (valid bytes in last page)
  57. pages        dw    0    ; # of 512 byte pages in image
  58. relo_ct        dw    0    ; count of relocation table entries
  59. hdr_size    dw    0    ; size of header in paragraphs
  60. min_mem        dw    0    ; min required memory
  61. max_mem        dw    0    ; max required memory
  62. xss        dw    0    ; stack seg offset in load module
  63. xsp        dw    0    ; initial value of sp
  64. cksum        dw    0    ; file checksum
  65. xip        dw    0    ; initial value of IP
  66. xcs        dw    0    ; cs offset in load module
  67. relo_start    dw    0    ; offset of first relocatable item
  68. ovl_num        dw    0    ; overlay number
  69. exe_header ENDS            ; end of structure
  70.  
  71. CSEG    SEGMENT PARA PUBLIC 'CODE'
  72.     ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  73.  
  74.     org    100H
  75.  
  76. X2B    proc    near
  77.     jmp    Start        ;skip over runtime data            v1.1
  78.  
  79. errflag        db    0    ;error flag                v1.1
  80. save_ip        dw    0
  81. handle1        dw    0
  82. handle2        dw    0
  83.  
  84. msg1    db    'Input File ==>',eom
  85. msg2    db    '  Output File ==>',eom
  86. msg3    db    CR,LF,EOM
  87.  
  88. author        db    'X2B 1.1  Public Domain Software by Henry T. Nettles'
  89.         db    CR,LF,EOM
  90. code_size_msg    db    'Code Size = '
  91. code_size_str    db    '      ',eom
  92. code_start_msg    db    '  Code Start = '
  93. code_start_str    db    '      ',eom
  94. ip_msg        db    '  Initial IP = '
  95. ip_str        db    '      ',CR,LF,EOM
  96. actual_code_size_msg db    'Size of .Com file = '
  97. actual_code_size_str db    '      ',CR,LF,EOM
  98.  
  99. code_size dw    0        ; amount of code to move to .com file
  100. code_start dw    0
  101.  
  102. no_file_msg1 db    'USAGE:  >X2B  [d:][\path\]file[.exe] [d:][\path\][file][.com]'
  103.          db    CR,LF,EOM
  104. open_fail_msg  db 'ERROR: Open of input file failed!',CR,LF,EOM
  105. create_fail_msg    db 'ERROR: Create of output file failed!',CR,LF,EOM
  106. disk_full_msg  db 'ERROR: The disk is full!',CR,LF,EOM
  107. Bad_Read_msg   db 'I/O Error on Read!',CR,LF,EOM
  108. bad_write_msg  db 'I/O Error on Write!',CR,LF,EOM
  109. seek_error_msg db 'I/O Error on Seek!',CR,LF,EOM
  110.  
  111. badsig_msg     db 'Invalid EXE File Signature',CR,LF,EOM
  112. hasrelo_msg    db 'EXE has relocatable items',CR,LF,EOM
  113. has_ss_msg     db 'EXE has stack segment',CR,LF,EOM
  114. bad_ip_msg     db 'IP not 0 or 100h',CR,LF,EOM
  115. too_big_msg    db 'Exe file is too big to convert to COM file',CR,LF,EOM
  116. mul_err_msg    db 'Overflow on multiply',CR,LF,EOM
  117.  
  118.  
  119. Start:                    ;v1.1
  120.  
  121. ;****************************************************************************
  122. ;*    Get two file names from command line
  123. ;*    This portion of code was borrowed from TABS.ASM by Vernon Buerg
  124. ;****************************************************************************
  125.  
  126.     xor    al,al            ;handy 0            v1.1
  127.     mov    FNAME1,al        ;insure both dynamic filename    v1.1
  128.     mov    FNAME2,al        ; buffers are 0            v1.1
  129.  
  130.     mov    si,CMDTAIL        ; DS:SI points to command line
  131.     sub    bp,bp            ;Indicates first or second name
  132.     sub    ch,ch            ;The PSP may contain one or two
  133.     or    cl,[si]            ; filenames separated by blanks v1.1
  134.     jz    GetF5            ; First byte of cmdline should not be 0
  135.  
  136.     mov    di,offset FNAME1    ;ES:DI points to fname1        v1.1
  137.     Inc    si            ; point to next char from command line
  138.                     ; (assume that 1st char is a blank)
  139.  
  140. GetF1:    Lodsb                ;Copy command line to file names
  141.                     ; AL will contain character pointed
  142.                     ; to by DS:SI
  143.     cmp    AL,' '            ; skip leading blanks
  144.     jne    GetF2            ; not a blank -- jump
  145.  
  146.     or    bp,bp            ; or until the length is zero
  147.     jz    GetF4            ;If a second blank is found,
  148.      mov    ax,2400h        ; append zero and dollar sign
  149.      stosw                ; mov AX to ES:DI
  150.      mov    di,offset FNAME2    ;ES:DI now points to 2d filename v1.1
  151.      jmp    short GetF4
  152.  
  153. GetF2:    cmp    AL,Cr            ;Is it CR, end of line?
  154.     je    GetF5            ; yes, end of command
  155.  
  156.     stosb                ; no, save in name
  157.     mov    bp,di            ; and indicate data copied
  158. GetF4:    loop    GetF1
  159.  
  160. GetF5:    mov    ax,2400h        ;Append zero and dollar    sign
  161.     stosw
  162.  
  163.     mov    dx,offset author    ;tell them who we are        v1.1
  164.     mov    ah,9            ;display string
  165.     int    21H
  166.  
  167. ;***************************************************************************
  168. ;*    DISPLAY THE TWO FILE NAMES FROM COMMAND LINE
  169. ;***************************************************************************
  170.     mov    si,offset FNAME1    ;point to fname1         v1.1
  171.     xor    al,al            ;handy 0            v1.1
  172.     cmp    al,[si]            ;did user enter at least 1 file name? v1.1
  173.     jnz    L1            ; is ok, we have a file name
  174.      jmp    No_File1
  175.  
  176. L1:
  177.     mov    di,si    ;offset fname1    ; check fname1 for extension    v1.1
  178.     mov    cx,-1
  179.     cld                ; direction of search = forward
  180.     repnz    scasb            ; search through file name for '\0'
  181.     not    cx            ; CX = length including '\0'
  182.     mov    dx,cx            ;save length in DX a sec    v1.1
  183.     mov    di,si    ;offset fname1    ;point back to fname1 start    v1.1
  184.     mov    al,'.'
  185.     repnz    scasb            ; search for period in file name
  186.     jz    L1a            ; found the period, must have ext
  187.  
  188.     mov    ax,si    ;offset fname1    ; no period, must add .EXE for user v1.1
  189.     add    ax,dx    ;fname1_len    ;                v1.1
  190.     dec    ax            ;
  191.     mov    di,ax            ; di points to '\0' at end of file name
  192.     mov    ax,'E.'    ;452eh        ; ".E" backwards        v1.1
  193.     stosw
  194.     mov    ax,'EX'    ;4558h        ; "XE" backwards        v1.1
  195.     stosw
  196.     mov    ax,2400h        ; append zero and dollar sign
  197.     stosw
  198.  
  199. L1a:
  200.     mov    cx,-1            ;common code            v1.1
  201.     cmp    byte ptr FNAME2,0    ;did user enter 2d file name?    v1.1
  202.                     ; (should not be 0)        v1.1
  203.     jnz    L2            ; fname2 is non-blank, go check    for ext
  204.  
  205.     mov    si,offset FNAME1    ;source is FNAME1        v1.1
  206.     mov    di,si    ;offset FNAME1    ;into DI for a scasb        v1.1
  207.     mov    al,'.'
  208.     cld
  209.     repnz    scasb            ; search fname1 for '.'
  210.     not    cx            ; cx has length of fname1 including '.'
  211.     dec    cx            ; don't copy the period
  212.     mov    di,offset FNAME2    ; let Dest.  Index point to fname2 v1.1
  213.                     ;SI (source) is already FNAME1    v1.1
  214.     cld                ; direction of movement = forward
  215.     rep    movsb            ; move chars from [SI] to [DI]
  216.                     ;   CX has count (# chars to move)
  217.     jmp    short L2a        ; go add the ".COM"
  218. ;
  219. L2:    mov    di,offset fname2    ; check fname2 for extension
  220.     xor    al,al            ; zero al
  221.     cld                ; direction of search = forward
  222.     repnz    scasb            ; search through file name for '\0'
  223.     not    cx            ; CX = length including '\0'
  224.     mov    dx,cx            ; save the length in DX a sec    v1.1
  225.     mov    di,offset FNAME2        ;v1.1
  226.     mov    al,'.'
  227.     repnz    scasb            ; search for period in file name
  228.     jz    L2b            ; found the period, must have ext
  229.  
  230.     mov    ax,offset FNAME2        ;v1.1
  231.     add    ax,dx    ;fname2_len    ;add in FNAME2's length        v1.1
  232.     dec    ax            ;adjust
  233.     mov    di,ax            ; di points to '\0' at end of file name
  234. L2a:    mov    ax,'C.'    ;432eh        ; ".C" backwards        v1.1
  235.     stosw
  236.     mov    ax,'MO'    ;4d4fh        ;"OM" backwards            v1.1
  237.     stosw
  238.     mov    ax,2400h        ; append zero and dollar sign
  239.     stosw
  240. L2b:
  241.     mov    dx,offset msg1
  242.     mov    ah,9
  243.     int    21H
  244.     mov    dx,offset FNAME1
  245.     mov    ah,9
  246.     int    21H
  247.     mov    dx,offset msg2
  248.     mov    ah,9
  249.     int    21H
  250.     mov    dx,offset FNAME2
  251.     mov    ah,9
  252.     int    21H
  253.     mov    dx,offset msg3
  254.     mov    ah,9
  255.     int    21H
  256.  
  257. ;****************************************************************************
  258. ;*    OPEN THE INPUT FILE
  259. ;****************************************************************************
  260.  
  261.     mov    dx,offset FNAME1    ;open input file
  262.     mov    ax,3D00H        ;open, read only
  263.     int    21H
  264.     jnc    L3            ; opened ok
  265.      jmp    Open_Fail        ; no file
  266.  
  267. L3:    mov    handle1,ax        ; save token for file
  268.  
  269. ;****************************************************************************
  270. ;*    OPEN THE OUTPUT FILE
  271. ;****************************************************************************
  272.     mov    dx,offset FNAME2    ;output file name
  273.     xor    cx,cx            ;normal attributes
  274.     mov    ah,3CH            ;create file
  275.     int    21H
  276.     jnc    L4            ; created ok
  277.      jmp    Create_Fail        ; create failed
  278.  
  279. L4:    mov    handle2,ax        ; save token for file
  280.  
  281. ;****************************************************************************
  282. ;*    PROCESS THE EXE HEADER
  283. ;****************************************************************************
  284. ; first we read in the exe header, don't you think?
  285.  
  286.     mov    dx,offset BUFFER    ;read buffer
  287.     mov    cx,SIZE_OF_HEADER
  288.     mov    bx,handle1
  289.     mov    ah,3FH            ;read from file/device
  290.     int    21H
  291.     jnc    L5            ;read ok
  292.      jmp    Bad_Read        ;read error
  293.  
  294. L5:    mov    bx,offset buffer    ; use DS:BX to address buffer
  295.     cmp    word ptr [bx].exe_sig1,'ZM'    ;'MZ' backwards? v1.1
  296.     je    L7            ;YEP, OK
  297.      jmp    BadSig            ;no, print error msg, exit    v1.1
  298.  
  299. L7:
  300.     xor    ax,ax            ;handy 0            v1.1
  301.  
  302.     cmp    [bx].relo_ct,ax            ;is relocatable count 0? v1.1
  303.     je    L8                ; is ok, no relocatable items
  304.      jmp    HasRelo                ; oops, can't convert
  305.  
  306. L8:
  307.     cmp    [bx].xss,ax            ;is stack segment 0?    v1.1
  308.     je    L9                ; is ok, no stack segment
  309.      jmp    Has_SS
  310.  
  311. L9:
  312.     cmp    [bx].xsp,ax            ;is stack segment offset 0? v1.1
  313.     je    L10                ; is okay
  314.      jmp    Has_SS
  315.  
  316. L10:
  317.     mov    ax,[bx].xip            ; initial value for IP
  318.     or    ax,ax                ; should either be 0 or 100h v1.1
  319.     je    L11
  320.     cmp    ax,100h
  321.     je    L11
  322.      jmp    Bad_IP
  323.  
  324. L11:    mov    save_ip,ax        ; save the IP for later use
  325. ;***************************************************************************
  326. ;* Compute offset of program image in module, and program size
  327. ;*
  328. ;* The program size is computed as follows;  it cannot exceed 64k bytes
  329. ;*     512 * (# of EXE pages -1 )
  330. ;*   + valid bytes in last EXE page
  331. ;*   - offset of program image in EXE file
  332. ;*
  333. ;* Note that if the IP is nonzero, we will skip the first
  334. ;* IP bytes of the program image, and copy IP bytes fewer
  335. ;* than the actual size
  336. ;*
  337. ;***************************************************************************
  338.  
  339.     mov    ax,[bx].hdr_size    ; size of the program header
  340.                     ; expressed in 16 byte paragraphs
  341.     mov    cl,4            ; no of times to shift
  342.     shl    ax,cl            ; fast multiply by 16
  343.     mov    code_start,ax        ; save it
  344.  
  345.     mov    ax,[bx].pages        ;nr of 512-byte pages        v1.1
  346.     dec    ax            ; subtract 1
  347.     cmp    ax,128            ; is it too big? (128*512 is 64k)
  348.     jle    L12            ; no, is ok
  349.      jmp    Too_Big            ; exe file is too big, print error
  350.  
  351. L12:    mov    cl,9            ; number of times to shift left
  352.     shl    ax,cl            ; fast multiply by 512
  353.     jno    L13            ; jump on no overflow
  354.      jmp    Mul_Err            ; else multiply error
  355.  
  356. L13:
  357.     mov    cx,[bx].excess        ; no. of bytes in last non-full page
  358.     add    ax,cx            ; add to result from above
  359.     sub    ax,code_start        ; subtract the code start address
  360.     mov    code_size,ax        ; save it for later
  361.     mov    di,offset code_size_str    ;where to write the Ascii chars    v1.1
  362.     call    BinToStr        ;convert code size        v1.1
  363.     mov    dx,offset code_size_msg    ;'Code size = xxxx'        v1.1
  364.     mov    ah,9            ;display msg
  365.     int    21H
  366.  
  367.     mov    ax,code_start        ;convert code start address    v1.1
  368.     mov    di,offset code_start_str ;where to write the Ascii chars v1.1
  369.     call    BinToStr
  370.     mov    dx,offset code_start_msg    ;'Code start = xxxx'    v1.1
  371.     mov    ah,9
  372.     int    21H
  373.  
  374.     mov    ax,save_ip        ;program's IP
  375.     mov    di,offset ip_str    ;where to write the Ascii chars    v1.1
  376.     call    BinToStr
  377.     mov    dx,offset ip_msg    ;'Initial IP = xxxx'        v1.1
  378.     mov    ah,9
  379.     int    21H
  380.  
  381. ;****************************************************************************
  382. ;*    MOVE FILE POINTER TO START OF CODE
  383. ;****************************************************************************
  384. ;* Add the initial IP to the code start address.  This will give
  385. ;* us the file offset, which is the location in the EXE file that we
  386. ;* will start copying from
  387. ;*
  388.     mov    ax,code_start
  389.     add    ax,save_ip        ;add in program's IP        v1.1
  390.     mov    dx,ax            ;DX needs it as lower part    v1.1
  391.                     ;of file offset            v1.1
  392.  
  393.     mov    bx,handle1        ; handle of input file
  394.     xor    cx,cx            ; upper    part of    offset        v1.1
  395.     mov    ax,4200h        ; move file pointer        v1.1
  396.                     ;(from start)
  397.     int    21h
  398.     jnc    L14
  399.      jmp    Seek_Error
  400.  
  401. L14:
  402. ;****************************************************************************
  403. ;*    COPY THE CODE TO THE OUTPUT (.COM) FILE
  404. ;****************************************************************************
  405. ; reduce the code_size by the size of the IP
  406.     mov    ax,code_size        ; reduce the code_size
  407.     sub    ax,save_ip        ; by the IP size        v1.1
  408.     mov    code_size,ax        ; store it away
  409.  
  410.     mov    di,offset actual_code_size_str    ;v1.1
  411.     call    BinToStr        ;convert code size
  412.  
  413.     mov    dx,offset actual_code_size_msg    ;'Size of .COM file = xxxx' v1.1
  414.     mov    ah,9
  415.     int    21H
  416. Next:                    ; process next record
  417.     mov    ax,RECSIZE
  418.     cmp    ax,code_size        ; compare code_size to RECSIZE
  419.     jle    L15            ; if ax < code_size, use ax as is
  420.      mov    ax,code_size        ;  else use size of remaining code
  421. L15:    mov    cx,ax            ; # of bytes to read
  422.     mov    bx,handle1        ;  input file
  423.     mov    dx,offset buffer    ; where to put it
  424.     mov    ax,3f00h        ; read from file/device
  425.     int    21h
  426.     jnc    L16            ; read ok
  427.      jmp    Bad_Read        ; ERROR - get out of here
  428.  
  429. L16:    or    ax,ax            ; on return, AX has # of bytes read
  430.     jnz    L17            ; if not zero, keep on
  431.      jmp    Done            ; read zero bytes, must be done
  432.  
  433. L17:
  434.     mov    cx,ax            ; nr bytes to write        v1.1
  435.     mov    bx,handle2        ;  output file
  436.     mov    dx,offset buffer    ; addr of what we are about to write
  437.     mov    ah,40h            ; write to file/dev
  438.     int    21h
  439.     jnc    L18            ; carry flag not set, no error on write
  440.      jmp    Bad_Write        ; jump if write error
  441.  
  442. L18:    cmp    ax,cx    ;wsize        ; AX has # of bytes actually written
  443.     je    L19            ; if we wrote all of the bytes
  444.                     ;    that we wanted to, then keep on
  445.      jmp    Disk_Full        ; did NOT write all of the bytes
  446.                     ; that I wanted to, disk must be full
  447. L19:    mov    bx,code_size
  448.     xchg    ax,bx            ; ax has code_size, bx has bytes written
  449.     sub    ax,bx            ; subtract bytes written from code_size
  450.                     ;   which gives us the number of
  451.     mov    code_size,ax        ;   bytes remaining to be copied
  452.     or    ax,ax            ; bytes remaining = zero?    v1.1
  453.     je    Done            ; yes, we're finished
  454.      jmp    Next            ; no, go read next block
  455.  
  456. ;****************************************************************************
  457. ;*    ERROR MESSAGES
  458. ;****************************************************************************
  459.  
  460. No_File1:    mov    dx,offset no_file_msg1
  461.         jmp    short Print_Error
  462. Open_Fail:    mov    dx,offset open_fail_msg
  463.         jmp    short Print_Error
  464. Create_Fail:    mov    dx,offset create_fail_msg
  465.         jmp    short Print_Error
  466. Disk_Full:    mov    dx,offset disk_full_msg
  467.         jmp    short Print_Error
  468. Bad_Read:    mov    dx,offset bad_read_msg
  469.         jmp    short Print_Error
  470. Bad_Write:    mov    dx,offset bad_write_msg
  471.         jmp    short Print_Error
  472. Seek_Error:    mov    dx,offset seek_error_msg
  473.         jmp    short Print_Error
  474. BadSig:        mov    dx,offset badsig_msg
  475.         jmp    short Print_Error
  476. HasRelo:    mov    dx,offset hasrelo_msg
  477.         jmp    short Print_Error
  478. Has_SS:        mov    dx,offset has_ss_msg
  479.         jmp    short Print_Error
  480. Bad_IP:        mov    dx,offset bad_ip_msg
  481.         jmp    short Print_Error
  482. Too_Big:    mov    dx,offset too_big_msg
  483.         jmp    short Print_Error
  484. Mul_Err:    mov    dx,offset mul_err_msg
  485.  
  486. Print_Error:    mov    ah,9
  487.         int    21h
  488.         not    errflag        ;turn error flag on        v1.1
  489.                     ;(non-zero)
  490.  
  491. ;****************************************************************************
  492. ;*    CLOSE INPUT AND OUTPUT FILES
  493. ;****************************************************************************
  494.  
  495. Done:    mov    ax,handle1        ;input file handle
  496.     or    ax,ax            ; is the handle still zero,
  497.                     ; as was initially? v1.1
  498.     je    Get_Out            ; yes, no files to close
  499.     mov    ah,3eh            ; close input file
  500.     mov    bx,handle1
  501.     int    21h
  502.  
  503.     mov    ax,handle2        ;output file handle
  504.     or    ax,ax            ; is the handle still zero,
  505.                     ; as was initially? v1.1
  506.     je    Get_Out            ; yes, no output file to close
  507.     mov    ah,3eh            ; close output file
  508.     mov    bx,handle2
  509.     int    21h
  510.  
  511.     cmp    errflag,0        ;any errors?            v1.1
  512.     jz    Get_Out            ; no
  513.      mov    dx,offset FNAME2    ; yes, delete the output file    v1.1
  514.      mov    ah,41H            ;delete file
  515.      int    21H
  516.  
  517. ;****************************************************************************
  518. ;*    EXIT WITH STATUS CODE
  519. ;****************************************************************************
  520.  
  521. Get_Out:
  522.     mov    ax,4C00H        ;terminate, errorlevel 0    v1.1
  523.     int    21H
  524.  
  525. X2B    endp            ;v1.1
  526.  
  527. ; Procedure BinToStr (number,address)
  528. ; Purpose   Converts integer to string
  529. ; Input     ax = number to convert, di = near address for write    v1.1
  530. ; Output    AX has characters written
  531.  
  532. BinToStr  PROC    near
  533.  
  534.     sub      cx,cx            ; Clear    counter
  535.     mov      bx,10            ; Divide by 10
  536.  
  537. ; Convert and save on stack backwards
  538.  
  539. GetDigit:
  540.     sub      dx,dx            ; Clear top
  541.     div      bx            ; Divide to get last digit as remainder
  542.     add      dl,"0"        ; Convert to ASCII
  543.     push      dx            ; Save on stack
  544.     or      ax,ax            ; Quotient 0?
  545.     loopnz  GetDigit        ; No? Get another
  546.  
  547. ; Take off the stack and store forward
  548.  
  549.     neg      cx            ; Negate and save count
  550.     mov      dx,cx
  551. PutDigit:
  552.     pop      ax            ; Get character
  553.     stosb                ; Store it
  554.     loop      PutDigit
  555.     mov      ax,dx            ; Return digit count
  556.  
  557.     ret                ;                v1.1
  558. BinToStr  ENDP
  559.  
  560.     even
  561.  
  562. buffer    label    byte    ;recsize dup(?)
  563. FNAME1    equ    buffer + RECSIZE    ;64-byte input filename buffer
  564. FNAME2    equ    FNAME1 + 64        ;64-byte output filename buffer
  565.  
  566. CSEG    ENDS
  567.     END    X2B
  568.