subttl Macro definitions ; In segment 'segzero' set $ to the next multiple of 'n'. align macro n,segzero org $ - (($-segzero) MOD n) + n endm ; Issue a DOS function request (int 21h) after ; setting up registers ax,bx,cx,dx,ds,es. ; Registers not specified are not affected by the macro, ; code to move a reg to itself is skipped, and ; moves between DS and ES are handled. dos_fr macro rax,rbx,rcx,rdx,rds,res ifnb ;;ax ifidn , else mov ax,rax endif endif ifnb ;;bx ifidn , else mov bx,rbx endif endif ifnb ;;cx ifidn , else mov cx,rcx endif endif ifnb ;;dx ifidn , else mov dx,rdx endif endif ifnb ;;es ifidn , push ds pop es else ifidn , else mov es,res endif endif endif ifnb ;;ds ifidn , push es pop ds else ifidn , else mov ds,rds endif endif endif int 21h endm ; Given the value of "active_exe", put into BX the corresponding byte offset ; into various tables. If table="itself", just load BX. ; ; Note: The calculated byte offset must fit into BL because we use BH for ; scratch. We don't affect any other register this way. If the ; number of entries allowed in the tables is enlarged so that we ; could overflow into BH, this macro will need changing. Changing ; a table's format will obviously affect this macro too. load_index macro table mov bx,active_exe ifdif , xor bh,bh endif ifidn ,
shl bx,1 ;; 2 bytes/entry endif ifidn ,
shl bx,1 ;; 4 shl bx,1 endif ifidn ,
shl bx,1 ;; 4 shl bx,1 endif ifidn ,
mov bh,bl shl bx,1 ;;shift BH and BL simultaneously shl bl,1 shl bl,1 add bl,bh ;; 10 xor bh,bh endif ifidn ,
shl bx,1 ;; 2 endif endm ; *** All registers on entry except CS,IP belong to the child. *** ; *** On exit, all registers except CS,IP,DS still belong to the child. *** ; This routine captures all the child's registers' values (except CS:IP, ; which is located on the stack at the saved SS:SP). ; DS is changed to PCS's data segment. save_state macro push ds ;pushes are in child's data segment push ax mov ax,data mov ds,ax ;DS points to PCS's data segment pop ax ;get back ax mov save_ax,ax mov save_bx,bx mov save_cx,cx mov save_dx,dx mov save_si,si mov save_di,di pop ax ;get back ds (stack now same as on entry) mov save_ds,ax mov save_es,es mov save_ss,ss mov save_sp,sp mov save_bp,bp endm ; Save the parent's (i.e. PCS's) segment and pointer registers. save_parent macro mov pcs_state.st_es,es ;save our state mov pcs_state.st_ss,ss mov pcs_state.st_sp,sp mov pcs_state.st_bp,bp mov pcs_state.st_ds,ds endm ; Restore the parent's segment and pointer registers. restore_parent macro mov bx,offset pcs_state ;restore parent's state cli mov es,[bx].st_es mov ss,[bx].st_ss mov sp,[bx].st_sp mov bp,[bx].st_bp ;; mov ds,[bx].st_ds ;save_state made DS active already sti endm ; Save off our registers and restore child's, then resume child. call_child macro x save_parent load_index state_table lea bx,state_table[bx] cli ; restore child's state mov es,[bx].st_es mov ss,[bx].st_ss mov sp,[bx].st_sp mov bp,[bx].st_bp mov ds,[bx].st_ds sti xlidbg&x label byte nop ;;this gets replaced with INT 3 for debug nop db 0CBh ;resume child via far return endm ; Save off child's registers and restore ours, then continue. resume_parent macro save_state ;save child's registers in global area restore_parent load_index state_table lea bx,state_table[bx] mov ax,save_ds ;save child's regs in child-local area mov [bx].st_ds,ax mov ax,save_es mov [bx].st_es,ax mov ax,save_ss mov [bx].st_ss,ax mov ax,save_sp mov [bx].st_sp,ax mov ax,save_bp mov [bx].st_bp,ax endm