1

I am writing my own interrupt, to transfer 100 bytes from one file to another file. (My interrupt code is 0x88).

What the interrupt does: the interrupt gets two addresses DS:DX - input file; ES:CX - output file, (in .com programs, DS always == to ES, so address will be in DX and CX) with file names in them (ASCIIZ format). The interrupt has to copy the first 100 bytes from the first file to the second file. If there are less than 100 bytes, then fill up the needed amount to be 100 bytes with whitespace (ASCII code 0x20).

Problem: I don't know how to transfer data from the first file to another, because there is no "section .data" (as I know, I might be wrong, but I couldn't find any information on that).

How I am thinking of doing that: I was thinking to read one byte to register and compare that one byte with 0x00 (if it is not the end of the file). And then write one byte to the output file. If the byte is 0x00, that means the end of the file was reached, so I have to fill (100 minus bytes transferred) with whitespace.

Question: How to read one byte in the register (not in the buffer)?

EDIT: I have tried to add section .data into interrupt file. This is what I have got so far. I have a problem adding whitespace (If the input file has less than 100 bytes) in the end.

Input File:

CCCCC

Output file:

CCCCC   mov di, .buffer
call procFPBCD2ASCIIZ
mov dx, di
call procPutStr

pop dx

Output file has 100 bytes (as needed), but it fills with something else.


%include 'yasmmac.inc'
;------------------------------------------------------------------------
org 100h  

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
section .text                   ; Code starts here
      jmp     Settings                           ;First launch
    Old_I88:
      dw      0, 0

    procWrite:         
      jmp .next

    .next:
      mov [writingFile], cx
      call procFOpenForReading
      jnc .readingFileIsOpened
      macPutString 'Error while opening reading file', '$'
      exit

    .readingFileIsOpened:
      mov dx, buffer
      mov cx, 100
      call procFRead
      jc .errorReading
      call procFClose
      cmp ax, 100
      jb .lessThanHundred
      jmp .write

    .lessThanHundred:
      mov dx, [writingFile]
      call procFCreateOrTruncate
      jc .errorOpenFile
      mov dx, buffer
      mov cx, ax
      call procFWrite
      jc .errorWriting
      mov cx, 100
      sub cx, ax
      push cx
      xor cx, cx
      mov dx, ax
      call procFSeekFromBeginning
      pop cx
      mov dx, whitespace
      call procFWrite
      jc . errorWriting
      call procFClose
      jmp .end

    .write:
      mov dx, [writingFile]
      call procFCreateOrTruncate
      mov cx, 100
      mov dx, buffer
      call procFWrite
      jc .klaidaRasant
      call procFClose
      jmp .end
      
      

    . errorWriting:
      macPutString 'Error while writing file', '$'
      exit

    .errorOpenFile:
      macPutString 'Error while opening file', '$'
      exit

    .errorReading:
      macPutString 'Error while reading file.', '$'
      exit

    .end:
      exit

      .writingError:
        exit


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
New_I88:                                           
    
      macPushAll                                       ; Saving registers
      call  procWrite                                  ; 
      mov ax, 0xb800
      mov es, ax
      mov ax, 0x6F41
      mov di, 0000 
      mov cx, 0xa0
      rep stosw
      macPopAll                                       ; 
    

      iret                                         ; Return from interrupt

    ;

;
;
; 
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;  Settings (after first launch) block. Does not remain in the memory
;

 
Settings:
        ; Getting old 88h vector
        push    cs
        pop     ds
        mov     ax, 3588h                 ; Getting old interrupt vector
        int     21h
        
        ; Saving old vector 
        mov     [cs:Old_I88], bx             
        mov     [cs:Old_I88 + 2], es         
        
        ; Setting new 1Ch vector
        ;lea     dx, [New_I88]
        mov     dx,  New_I88
        mov     ax, 2588h                 ; Setting interrupt vector
        int     21h
        
        macPutString "OK ...", crlf, '$'
        
        ;lea     dx, [Settings  + 1]       ; dx - how many bytes
        mov dx, Settings + 1
        int     27h                      
%include 'yasmlib.asm'  


section .data

  buffer:
    times 128 db 00

  writingFile:
    dw 0000
  
  inputFile:
    times 128 db 00
  
  outputFile:
    times 128 db 00

  whitespace:
    db '                                                                                                            ', 00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
section .bss                  
Sep Roland
  • 33,889
  • 7
  • 43
  • 76
KazlLaur
  • 63
  • 6
  • 1
    I don't think the `.data` section needs to be in your interrupt code necessarily. Does YASM have a `seg` operator? e.g. `mov ax, seg inputFile`/`mov ds,ax`? The assembler turns `seg inputFile` into whatever segment the label `inputFile` happens to be in, in this case `section .data`. At least that's how it works in UASM (the assembler I use for 8086) – puppydrum64 Dec 08 '22 at 14:39

1 Answers1

1
mov  dx, Settings + 1
int  27h                      

It's because of the error in these 2 lines that your program worked a little bit and not crash right away! The number that you put in DX so that DOS can make your program a (passive) TSR needs to be the number of paragraphs that you want the program to keep for itself. Your instruction loads DX with a number of bytes and in doing so hogs much more memory than is needed. It would seem your 'missing' .data section was present after all. But not in the way it should have been.

push cx
xor cx, cx
mov dx, ax
call procFSeekFromBeginning
pop cx

This seeking operation prior to writing the padding spaces is totally redundant. The preceding procFWrite will have left the filepointer exactly where you need it.


On entry to your New_I88 interrupt handler, the DS and ES segment registers (whether equal to each other or not) are not pointing to your code. It will be best to open and create the concerned files and then have DS point to your code (Does macPushAll also preserve DS and ES?).

; IN (ds:dx,es:cx)
procWrite:         
  push es cx
  call procFOpenForReading    ; -> BX CF
  pop  dx ds
  jc   .errorOpenFile
  mov  [cs:Handle1], bx
  call procFCreateOrTruncate  ; -> BX CF
  jc   .errorOpenFile
  mov  [cs:Handle2], bx
  push cs
  pop  ds

Now you're ready to read from the opened source file 100 or less bytes. If it's less then simply pad the incomplete buffer with the necessary space characters. Don't be tempted to cut corners and preload space characters in the (static) buffer. In practice, this int 88h service needs to function correctly time and time again.

  mov  dx, buffer
  mov  cx, 100
  mov  bx, [Handle1]
  call procFRead              ; -> AX=[0,100] CF
  jc   .errorReading
  call procFClose             ; -> CF
  jc   .errorReading
  mov  bx, ax
padBuffer:
  cmp  bx, 100
  jnb  .write
  mov  [buffer + bx], byte 32
  inc  bx
  jmp  padBuffer

Once complete, you always write just 100 bytes.

.write:
  mov  dx, buffer
  mov  cx, 100
  mov  bx, [Handle2]
  call procFWrite             ; -> AX CF
  jc   .errorWriting
  call procFClose             ; -> CF
  jc   .errorWriting
  ret

You are writing a .COM program, so don't use sections of any kind.

  %include 'yasmmac.inc'

  org 100h  

  jmp  Settings               ; Execution starts here
  nop

Old_I88:  dw 0, 0
Handle1:  dw 0
Handle2:  dw 0
buffer:   times 100 db 0
; ----------------------------
proWrite:
  ...
  ret
; ----------------------------
New_I88:                                           
  ...
  iret
; ----------------------------
  %include 'yasmlib.asm' 
; ----------------------------
Settings:
  mov  ax, 3588h
  int  21h
  mov  [Old_I88], bx             
  mov  [Old_I88 + 2], es         
  mov  dx, New_I88
  mov  ax, 2588h
  int  21h   
  ...
  mov  dx, (Settings + 15) / 16      ; Number of paragraphs to keep
  int  27h                      

Question: How to read one byte in the register (not in the buffer)?

The 'yasmlib' has the function procFGetChar for this (returning in the CL register).

If the byte is 0x00, that means the end of the file was reached

No, the value from CL doesn't tell you that. When procFGetChar returns with the carry flag clear and AX=0, then the End-Of-File was reached and so nothing valuable is in CL.

Sep Roland
  • 33,889
  • 7
  • 43
  • 76