654 lines
15 KiB
NASM
654 lines
15 KiB
NASM
;*****************************************************************
|
||
;
|
||
; Copyrigth (C) 1984 Logitech. All Rights Reserved.
|
||
;
|
||
; Permission is hereby granted to registered users to use or
|
||
; abstract the following program in the implementation of
|
||
; customized versions. This permission does not include the
|
||
; right to redistribute the source code of this program.
|
||
;
|
||
; LOGITECH SA. CH-1143 Apples, Switzerland
|
||
;
|
||
; Modula-2/86 Run Time Support package
|
||
;
|
||
; Module: DBUG.ASM
|
||
; Produces the Post Mortem Dump on a disk file
|
||
; and provides the interface to the Run-Time Debugger.
|
||
;
|
||
; Version: 8086, RAM-based, MS-DOS 2.0 compatible
|
||
; Release: 1.10 - Dec 84
|
||
;
|
||
;*****************************************************************
|
||
|
||
CGROUP group code
|
||
DGROUP group data
|
||
|
||
assume CS: CGROUP
|
||
assume DS: DGROUP
|
||
assume ES: NOTHING
|
||
assume SS: DGROUP
|
||
|
||
include RTS.INC
|
||
|
||
;*****************************************************************
|
||
;
|
||
; EXPORT QUALIFIED
|
||
public INSTALL_DEBUG
|
||
public RTD_AFTER_LOAD
|
||
public DEBUGGER
|
||
|
||
;
|
||
;*****************************************************************
|
||
data segment public 'data'
|
||
|
||
; FROM RTS IMPORT
|
||
extrn START_MEM:word, MEM_SIZE:word
|
||
extrn SAVED_DISK:byte
|
||
extrn RTS_DISK:byte
|
||
extrn RTS_PROCESS:byte ;:ProcessDescriptor
|
||
extrn CUR_proc_addr:dword
|
||
extrn cur_process:byte ;:ProcessDescriptor
|
||
|
||
data ends
|
||
;*****************************************************************
|
||
|
||
|
||
;*****************************************************************
|
||
code segment public 'code'
|
||
|
||
; FROM RTS IMPORT
|
||
extrn RTS_DS:word ; really belongs here!
|
||
extrn DUMMY_ISR: near
|
||
extrn NORM_ADDR:near
|
||
extrn WRITE_LN:near
|
||
extrn WRITE_MSG:near
|
||
extrn GET_CURR_DISK:near
|
||
extrn SELECT_DISK:near
|
||
|
||
code ends
|
||
;*****************************************************************
|
||
|
||
|
||
;*****************************************************************
|
||
data segment public 'data'
|
||
|
||
; string constants
|
||
|
||
DUMP_NAME DB 'MEMORY.PMD',0
|
||
DUMP_MSG DB ' writing post mortem dump ... $'
|
||
BAD_DUMP_MSG DB 'failed', 0DH,0AH, '$'
|
||
OK_DUMP_MSG DB 'done', 0DH,0AH, '$'
|
||
|
||
; Variables for Post Mortem Dump:
|
||
|
||
even
|
||
DUMP_LOW_START dw ? ; first paragraph of 'low' dump area
|
||
DUMP_LOW_END dw ? ; last paragraph of same
|
||
DUMP_HIGH_START dw ?
|
||
DUMP_HIGH_END dw ?
|
||
DUMP_FILE_SPEC db 64H dup(?)
|
||
DUMP_FILE_HANDLE dw ?
|
||
|
||
SAVE_SP dw ?
|
||
SAVE_SS dw ?
|
||
|
||
s_rts_CS dw ? ; registers of main P.D.
|
||
s_rts_IP dw ?
|
||
s_rts_SS dw ?
|
||
s_rts_SP dw ?
|
||
s_rts_DS dw ?
|
||
s_rts_BP dw ?
|
||
|
||
s_cur_CS dw ? ; registers of current P.D.
|
||
s_cur_IP dw ?
|
||
s_cur_SS dw ?
|
||
s_cur_SP dw ?
|
||
s_cur_DS dw ?
|
||
s_cur_BP dw ?
|
||
|
||
old_break dd ? ; to save old break_vector around dumping
|
||
|
||
pmd_stack dw 160 dup (?) ; should be enough
|
||
pmd_stack_end label word
|
||
|
||
; Variables for the Run-Time Debugger:
|
||
RTD_PRESENT DB FALSE ; set through fct DEBUG_MODE_FCT
|
||
|
||
data ends
|
||
;*****************************************************************************
|
||
|
||
|
||
;
|
||
; The file containing the Post Mortem Dump has the following format:
|
||
;
|
||
; First 80H bytes are the header with
|
||
; 0 : addr process-descr of main process
|
||
; 4 : addr process-descr of terminating process
|
||
; 9..0D : not used
|
||
; 0E : number of dumped areas
|
||
; 0F : version number of dump file format
|
||
; 00 = first version (V1.0)
|
||
; 10H = new header (V1.03)
|
||
; 10 : first paragraph of first dumped area
|
||
; 12 : last " " " " "
|
||
; 14 : first paragraph of second dumped area
|
||
; 16 : last " " " " "
|
||
; 18 : first paragraph of third dumped area
|
||
; 1A : last " " " " "
|
||
;
|
||
; Every dumped area is a multiple of paragraphs (16 bytes).
|
||
; The first area starts with offset 80H in the file, subsequent
|
||
; areas follow immediately the previous area.
|
||
;
|
||
;************************************************************
|
||
|
||
code segment public 'code'
|
||
|
||
; public INSTALL_DEBUG
|
||
|
||
INSTALL_DEBUG proc NEAR
|
||
;============
|
||
; Allows to install and remove a Run-Time Debugger.
|
||
; Parameter: CL defines mode (0= remove, 1=install).
|
||
MOV ES: RTD_PRESENT, FALSE
|
||
TEST CL, CL
|
||
JZ DEBUG_SET
|
||
MOV ES: RTD_PRESENT, TRUE
|
||
DEBUG_SET:
|
||
IRET
|
||
INSTALL_DEBUG endp
|
||
|
||
;************************************************************
|
||
|
||
; public RTD_AFTER_LOAD
|
||
|
||
RTD_AFTER_LOAD proc NEAR
|
||
;=============
|
||
; Calls the Run-Time Debugger, if present.
|
||
; Upon entry: ES is assumed to be set to RTS.
|
||
; DS:0 points to current process
|
||
; called from RUN_PROGRAM
|
||
|
||
CMP ES:RTD_PRESENT, TRUE
|
||
JNE NO_RTD
|
||
MOV CUR_PROCESS.PD_dbug_status,1 ; 'loaded' state.
|
||
MOV ES:RTD_PRESENT, FALSE ; to avoid recursivity
|
||
INT 3
|
||
MOV ES:RTD_PRESENT, TRUE
|
||
MOV CUR_PROCESS.PD_dbug_status,0
|
||
NO_RTD: RET
|
||
|
||
RTD_AFTER_LOAD endp
|
||
|
||
;************************************************************
|
||
|
||
; public DEBUGGER
|
||
|
||
DEBUGGER proc NEAR
|
||
;=======
|
||
; Upon entry, DS is assumed to be set to RTS.
|
||
; We arrive here when an overlay has terminated, or any program,
|
||
; including level 0 has fallen into a run-time error.
|
||
; If the run-time debugger is present, we call it in any case, if
|
||
; it is not present, we produce a memory dump, if the status is
|
||
; not NORMAL nor WARNED.
|
||
mov ax,word ptr cur_proc_addr + 2
|
||
mov es,ax
|
||
|
||
; Test if status legal:
|
||
MOV AX,ES:CUR_PROCESS.PD_STATUS
|
||
CMP AX,HIGHEST_ERR_CODE
|
||
JBE ERR_CODE_OK
|
||
MOV ES:CUR_PROCESS.PD_STATUS, ILL_FCT_CODE
|
||
MOV AX,ILL_FCT_CODE
|
||
|
||
ERR_CODE_OK:
|
||
CMP AX,stop_code ; no dump if normal or warned
|
||
JB NORMAL_TERMINATION
|
||
|
||
; check, if the Run-Time Debugger is present:
|
||
CMP RTD_PRESENT, TRUE
|
||
JNE TAKE_A_DUMP
|
||
MOV ES:CUR_PROCESS.PD_dbug_status,0 ; indicates 'running'
|
||
MOV RTD_PRESENT, FALSE ; to avoid recursivity
|
||
INT 3
|
||
MOV RTD_PRESENT, TRUE
|
||
RET
|
||
|
||
|
||
TAKE_A_DUMP: ; no RTD, take a dump
|
||
|
||
; a bad function call will not produce a dump (probably bad code):
|
||
cmp ax,ILL_FCT_CODE
|
||
je NO_DUMP
|
||
|
||
; We use an auxiliary stack
|
||
; (we may have a stack overflow):
|
||
MOV SAVE_SS, SS
|
||
MOV SAVE_SP, SP
|
||
MOV AX, DS
|
||
MOV SS, AX
|
||
lea SP, pmd_stack_end
|
||
CALL P_M_DUMP
|
||
; Restore stack of user process:
|
||
MOV SS, SAVE_SS
|
||
MOV SP, SAVE_SP
|
||
|
||
NORMAL_TERMINATION:
|
||
|
||
NO_DUMP:
|
||
|
||
; aw 16 oct
|
||
|
||
; check, if the Run-Time Debugger is present:
|
||
CMP RTD_PRESENT, TRUE
|
||
JNE RETURN
|
||
MOV ES:CUR_PROCESS.PD_dbug_status,2 ; indicates 'terminated'
|
||
MOV RTD_PRESENT, FALSE ; to avoid recursivity
|
||
INT 3
|
||
MOV RTD_PRESENT, TRUE
|
||
MOV ES:CUR_PROCESS.PD_dbug_status,0 ; indicates 'running'
|
||
|
||
RETURN:
|
||
RET
|
||
|
||
DEBUGGER endp
|
||
|
||
;************************************************************
|
||
|
||
|
||
P_M_DUMP proc NEAR
|
||
;========
|
||
CLD ; just to make sure
|
||
|
||
; Entry point for Post Mortem Dump
|
||
; When arriving here, we assume the relevant
|
||
; registers to be saved in the process descriptor.
|
||
; They are saved into local vars because interrupts
|
||
; cannot be disabled during DOSCALLs
|
||
|
||
mov ds,rts_ds ; set DS to own data
|
||
|
||
; set breakvector to a dummy ISR during writing the dump
|
||
; save old vector into old_break
|
||
xor ax, ax
|
||
mov es, ax
|
||
mov bx, 4 * 1BH
|
||
mov ax, es: [bx]
|
||
mov word ptr old_break, ax
|
||
mov ax, es: 2[bx]
|
||
mov word ptr old_break+2, ax
|
||
mov es: word ptr [bx], offset DUMMY_ISR
|
||
mov es: word ptr 2[bx], cs
|
||
|
||
|
||
CALL WRITE_LN
|
||
LEA DX, DUMP_MSG
|
||
CALL WRITE_MSG
|
||
mov ax,rts_process.PD_SS
|
||
mov s_rts_SS,ax
|
||
mov ax,rts_process.PD_SP
|
||
mov s_rts_SP,ax
|
||
mov ax,rts_process.PD_CS
|
||
mov s_rts_CS,ax
|
||
mov ax,rts_process.PD_IP
|
||
mov s_rts_IP,ax
|
||
mov ax,rts_process.PD_DS
|
||
mov s_rts_DS,ax
|
||
mov ax,rts_process.PD_BP
|
||
mov s_rts_BP,ax
|
||
|
||
mov es,word ptr cur_proc_addr + 2 ; base of cur P.D.
|
||
mov ax,ES:cur_process.PD_SS
|
||
mov s_cur_SS,ax
|
||
mov ax,ES:cur_process.PD_SP
|
||
mov s_cur_SP,ax
|
||
mov ax,ES:cur_process.PD_CS
|
||
mov s_cur_CS,ax
|
||
mov ax,ES:cur_process.PD_IP
|
||
mov s_cur_IP,ax
|
||
mov ax,ES:cur_process.PD_DS
|
||
mov s_cur_DS,ax
|
||
mov ax,ES:cur_process.PD_BP
|
||
mov s_cur_BP,ax
|
||
|
||
; paragraph address of :
|
||
mov ax, RTS_DS
|
||
mov DUMP_LOW_START, ax
|
||
; end of lower memory area:
|
||
MOV BX,word ptr RTS_PROCESS.PD_HEAP_TOP + 2
|
||
MOV AX,word ptr RTS_PROCESS.PD_HEAP_TOP
|
||
CALL NORM_ADDR
|
||
INC BX ; next paragraph
|
||
MOV DUMP_LOW_END, BX ; just save it
|
||
; start of higher memory area:
|
||
MOV BX, RTS_PROCESS.PD_SS
|
||
MOV AX, RTS_PROCESS.PD_SP
|
||
CALL NORM_ADDR
|
||
MOV DUMP_HIGH_START, BX ; just save it
|
||
; last paragraph of memory:
|
||
mov bx, START_MEM
|
||
dec bx
|
||
add bx, MEM_SIZE
|
||
MOV DUMP_HIGH_END, BX ; just save it
|
||
|
||
; Now, we create the file on the same disk
|
||
; where the resident part was found. Therefore,
|
||
; we have first to save the currrent disk:
|
||
call GET_CURR_DISK
|
||
|
||
; set up the filespec:
|
||
MOV AL, RTS_DISK
|
||
add al,'A'
|
||
PUSH DS
|
||
POP ES
|
||
MOV SI, OFFSET DUMP_NAME
|
||
MOV DI, offset DUMP_FILE_SPEC
|
||
mov byte ptr[di],al
|
||
inc di
|
||
mov byte ptr[di],':'
|
||
inc di
|
||
MOV CX, 11 ; Drive, Name, Typ and Extent
|
||
REP MOVSB
|
||
|
||
CALL DELETE_FILE ; Delete the old DUMP-file
|
||
CALL MAKE_FILE ; and create the new-one
|
||
JNB D_FILE_MADE ; yes
|
||
MOV AL, 0FFH ; no, dump fails
|
||
JMP AFTER_DUMP
|
||
D_FILE_MADE:
|
||
mov DUMP_FILE_HANDLE,ax
|
||
CALL SET_DEFAULT_DMA
|
||
; Fill the header record:
|
||
MOV AX, 0 ; First fill with zeroes
|
||
MOV DI, DEFAULT_DMA
|
||
PUSH DS
|
||
POP ES
|
||
MOV CX, 64
|
||
REP STOSW
|
||
; Now put the info required by the debugger:
|
||
MOV DI, DEFAULT_DMA
|
||
; addr of MAIN process descr:
|
||
MOV word ptr [DI], OFFSET RTS_PROCESS
|
||
MOV word ptr 2[DI], DS
|
||
; addr of descriptor of terminating process:
|
||
LES SI,cur_proc_addr
|
||
MOV [DI]+4, SI
|
||
MOV [DI]+6, ES
|
||
; put number of dumped areas:
|
||
MOV BYTE PTR [DI]+14, 3
|
||
; and version number of dump-file format:
|
||
MOV BYTE PTR [DI]+15, 10H
|
||
; start and end of interrupt vector table:
|
||
MOV WORD PTR [DI]+16, 0
|
||
MOV WORD PTR [DI]+18, 3FH
|
||
; paragraph address of :
|
||
mov ax,DUMP_LOW_START
|
||
mov [di]+20, ax
|
||
; end of lower memory area:
|
||
MOV bx,DUMP_LOW_END
|
||
MOV [DI]+22, BX ; top of main heap (parag)
|
||
; start of higher memory area:
|
||
MOV bx,DUMP_HIGH_START
|
||
MOV [DI]+24, BX ; top of main stack (parag)
|
||
; last paragraph of memory:
|
||
MOV bx,DUMP_HIGH_END
|
||
MOV [DI]+26, BX
|
||
|
||
mov ax,PD_SS
|
||
mov [DI]+20H,ax
|
||
mov ax,s_rts_SS
|
||
mov [DI]+22H,ax
|
||
mov ax,PD_SP
|
||
mov [DI]+24H,ax
|
||
mov ax,s_rts_SP
|
||
mov [DI]+26H,ax
|
||
mov ax,PD_CS
|
||
mov [DI]+28H,ax
|
||
mov ax,s_rts_CS
|
||
mov [DI]+2AH,ax
|
||
mov ax,PD_IP
|
||
mov [DI]+2CH,ax
|
||
mov ax,s_rts_IP
|
||
mov [DI]+2EH,ax
|
||
mov ax,PD_DS
|
||
mov [DI]+30H,ax
|
||
mov ax,s_rts_DS
|
||
mov [DI]+32H,ax
|
||
mov ax,PD_BP
|
||
mov [DI]+34H,ax
|
||
mov ax,s_rts_BP
|
||
mov [DI]+36H,ax
|
||
mov ax,0FFFFH
|
||
mov [DI]+38H,ax ; mark end of main P.D. values
|
||
|
||
mov ax,PD_SS
|
||
mov [DI]+3AH,ax
|
||
mov ax,s_cur_SS
|
||
mov [DI]+3CH,ax
|
||
mov ax,PD_SP
|
||
mov [DI]+3EH,ax
|
||
mov ax,s_cur_SP
|
||
mov [DI]+40H,ax
|
||
mov ax,PD_CS
|
||
mov [DI]+42H,ax
|
||
mov ax,s_cur_CS
|
||
mov [DI]+44H,ax
|
||
mov ax,PD_IP
|
||
mov [DI]+46H,ax
|
||
mov ax,s_cur_IP
|
||
mov [DI]+48H,ax
|
||
mov ax,PD_DS
|
||
mov [DI]+4AH,ax
|
||
mov ax,s_cur_DS
|
||
mov [DI]+4CH,ax
|
||
mov ax,PD_BP
|
||
mov [DI]+4EH,ax
|
||
mov ax,s_cur_BP
|
||
mov [DI]+50H,ax
|
||
mov ax,0FFFFH
|
||
mov [DI]+52H,ax ; mark end of current P.D. values
|
||
|
||
; Send the first record to the file:
|
||
CALL SEQ_WRITE
|
||
CMP AL, 80H
|
||
MOV AX, 0FFH ; to indicate error, necessary if AL = 0
|
||
JNE DUMP_BAD
|
||
|
||
; Now dump the memory:
|
||
; We dump 3 memory areas: the interrupt vectors (0..3FFH), the 'low'
|
||
; memory from start of RESIDENT to heaptop of main and the 'high'
|
||
; memory starting at stacktop of main to end of memory.
|
||
; These 3 areas are dumped paragraph-wise.
|
||
MOV CX, 0 ; start of first area
|
||
MOV BX, 03FH ; end of first area
|
||
CALL DUMP_PART
|
||
CMP AL, 0
|
||
JNE DUMP_BAD ; there was an error
|
||
MOV CX, DUMP_LOW_START ; start of second area
|
||
MOV BX, DUMP_LOW_END ; end of second area
|
||
CALL DUMP_PART
|
||
CMP AL, 0
|
||
JNE DUMP_BAD ; there was an error
|
||
MOV CX, DUMP_HIGH_START ; start of third area
|
||
MOV BX, DUMP_HIGH_END ; end of third area
|
||
CALL DUMP_PART
|
||
CMP AL, 0
|
||
JNE DUMP_BAD ; there was an error
|
||
MOV AX, 0 ; to indicate 'no error'
|
||
DUMP_BAD:
|
||
PUSH AX
|
||
; Close the file:
|
||
CALL CLOSE_FILE
|
||
POP AX
|
||
|
||
AFTER_DUMP:
|
||
; Dump is made. AX contains 0 for successfull
|
||
; dump and > 0 if an error occured:
|
||
CMP AX, 0
|
||
JE DUMP_OK
|
||
LEA DX, BAD_DUMP_MSG
|
||
CALL WRITE_MSG
|
||
CALL DELETE_FILE
|
||
JMP DUMP_EXIT
|
||
DUMP_OK:
|
||
LEA DX, OK_DUMP_MSG
|
||
CALL WRITE_MSG
|
||
DUMP_EXIT:
|
||
; Restore the disk of before the dump:
|
||
MOV DL, SAVED_DISK
|
||
CALL SELECT_DISK
|
||
|
||
; set breakvector to previous ISR
|
||
mov ds, rts_ds
|
||
xor ax, ax
|
||
mov es, ax
|
||
mov bx, 4 * 1BH
|
||
mov ax, word ptr old_break
|
||
mov es: [bx], ax
|
||
mov ax, word ptr old_break+2
|
||
mov es: 2[bx], ax
|
||
|
||
RET
|
||
|
||
P_M_DUMP endp
|
||
;------------
|
||
|
||
|
||
data segment public 'data' ; data for the following procedure
|
||
|
||
TEMP_W DW ? ; auxiliary word-variable
|
||
|
||
DUMP_AT_ONCE EQU 0FFFH ; number of pargraphs that will be
|
||
; dumped with one write.
|
||
data ends
|
||
|
||
|
||
DUMP_PART proc NEAR
|
||
;------------------
|
||
; Dumps a part of the memory to the open dump file
|
||
; at the current position.
|
||
; Upon entry:
|
||
; CX holds addr of first paragraph to
|
||
; dump; BX is addr of last paragraph
|
||
; to dump (BX=CX means 1 par. to dump);
|
||
; file handle in external variable DUMP_FILE_HANDLE.
|
||
; Upon exit:
|
||
; AL=0 if no error occurred while writing,
|
||
; AL=0FFH otherwise.
|
||
|
||
; compute number of paragraphs to dump:
|
||
MOV AX, BX
|
||
INC AX ; can't be last paragraph (boot!)
|
||
SUB AX, CX ; startaddr < endaddr ?
|
||
JBE DP_BAD ; no
|
||
DP_NEXT: ; yes
|
||
; save the parameters:
|
||
PUSH CX ; first paragraph to dump
|
||
PUSH AX ; # of paragraphs to dump
|
||
MOV DX, CX
|
||
; compute number of paragraphs to dump at once:
|
||
CMP AX, DUMP_AT_ONCE
|
||
JBE DP_NBR_PARA_SET ; dump remaining paragraphs
|
||
MOV AX, DUMP_AT_ONCE ; dump maximum possible
|
||
DP_NBR_PARA_SET:
|
||
; transform number of paragraphs in bytes:
|
||
MOV CL, 4
|
||
SHL AX, CL
|
||
MOV CX, AX
|
||
MOV TEMP_W, AX ; save it for the compare
|
||
; get file handle:
|
||
MOV BX, DUMP_FILE_HANDLE
|
||
; set transfer address:
|
||
PUSH DS
|
||
MOV DS, DX
|
||
MOV DX, 0
|
||
; and write the bytes:
|
||
MOV AH, 40H
|
||
INT OS
|
||
POP DS
|
||
CMP AX, TEMP_W ; write ok ?
|
||
POP AX ; # of pargraphs to dump
|
||
POP CX ; first paragraph to dump
|
||
JNE DP_BAD ; no
|
||
; update pointer and counter:
|
||
CMP AX, DUMP_AT_ONCE
|
||
JBE DP_GOOD ; we're finished
|
||
SUB AX, DUMP_AT_ONCE
|
||
ADD CX, DUMP_AT_ONCE
|
||
JMP SHORT DP_NEXT
|
||
DP_BAD:
|
||
MOV AL, 0FFH
|
||
RET
|
||
DP_GOOD:
|
||
MOV AL, 0
|
||
RET
|
||
DUMP_PART endp
|
||
;------------------------------------------------------------------
|
||
|
||
|
||
OPEN_FILE:
|
||
; open file in FILE_SPEC: returns carry flag set if not found
|
||
mov ax,3D01H ; open for write only
|
||
mov dx,offset DUMP_FILE_SPEC
|
||
int OS
|
||
ret
|
||
|
||
|
||
CLOSE_FILE:
|
||
; closes the file given in the DUMP_FILE_HANDLE
|
||
mov ah,3EH
|
||
mov bx,DUMP_FILE_HANDLE
|
||
int OS
|
||
ret
|
||
|
||
|
||
DELETE_FILE:
|
||
; deletes the file given in the DUMP_FILE_SPEC
|
||
mov ah,41H
|
||
mov dx,offset DUMP_FILE_SPEC
|
||
int OS
|
||
ret
|
||
|
||
|
||
SET_DEFAULT_DMA:
|
||
; DS is assumed to be the one of RTS
|
||
mov dx, DEFAULT_DMA
|
||
mov ah, 01Ah
|
||
int OS
|
||
ret
|
||
|
||
|
||
SEQ_WRITE:
|
||
; writes the next byte in the file given
|
||
; in the DUMP_FILE_HANDLE.
|
||
push ds
|
||
mov ah,2FH ; get current dma (buffer address)
|
||
int os
|
||
push es
|
||
push bx
|
||
mov bx,DUMP_FILE_HANDLE
|
||
pop dx
|
||
mov cx,80H
|
||
mov ah,40H
|
||
pop ds
|
||
int OS
|
||
pop ds
|
||
ret
|
||
|
||
|
||
MAKE_FILE:
|
||
; creates the file given in the DUMP_FILE_SPEC
|
||
mov ah, 3CH
|
||
mov cx,0 ; attribute of zero
|
||
mov dx,offset DUMP_FILE_SPEC
|
||
int OS
|
||
ret
|
||
|
||
|
||
code ends
|
||
;*****************************************************************************
|
||
|
||
|
||
end
|
||
|