diff --git a/src/stub/stub.asm b/src/stub/stub.asm index a56727d8..3557f1d9 100644 --- a/src/stub/stub.asm +++ b/src/stub/stub.asm @@ -45,7 +45,7 @@ ; ; Revision history: ; -; 93/12/05 DJ Delorie Initial version v2.00, requires DPMI 0.9 +; 93/12/05 DJ Delorie Initial version v2.00, requires DPMI 0.9 ; 94/10/13 CW Sandmann v2.01, accumlated changes: 60K load bug, limits, cwsdpmi, optimization ; 94/10/29 CW Sandmann v2.03, M Welinder changes; cwsdpmi load anywhere, size decrease ; @@ -58,130 +58,130 @@ ;----------------------------------------------------------------------------- ; Interface to 32-bit executable: ; -; cs:eip according to COFF header -; ds 32-bit data segment for COFF program -; fs selector for our data segment (fs:0 is stubinfo) -; ss:sp our stack (ss to be freed) -; All unspecified registers have unspecified values in them. +; cs:eip according to COFF header +; ds 32-bit data segment for COFF program +; fs selector for our data segment (fs:0 is stubinfo) +; ss:sp our stack (ss to be freed) +; All unspecified registers have unspecified values in them. ;----------------------------------------------------------------------------- ; This is the stubinfo structure. The presence of this structure ; indicates that the executable is a djgpp v2.00 executable. ; Fields will never be deleted from this structure, only obsoleted. ; - .org 0 ; just in case + .org 0 ; just in case stubinfo: -stubinfo_magic: ; char [16] - .db "go32stub, v 2.04" ; version may change, [0..7] won't -stubinfo_size: ; unsigned long - .dd stubinfo_end ; bytes in structure -stubinfo_minstack: ; unsigned long - .dd 0x80000 ; minimum amount of DPMI stack space (512K) -stubinfo_memory_handle: ; unsigned long - .dd 0 ; DPMI memory handle -stubinfo_initial_size: ; unsigned long - .dd 0 ; size of initial segment -stubinfo_minkeep: ; unsigned short - .dw 16384 ; amount of automatic real-mode buffer -stubinfo_ds_selector: ; unsigned short - .dw 0 ; our DS selector (used for transfer buffer) -stubinfo_ds_segment: ; unsigned short - .dw 0 ; our DS segment (used for simulated calls) -stubinfo_psp_selector: ; unsigned short - .dw 0 ; PSP selector -stubinfo_cs_selector: ; unsigned short - .dw 0 ; to be freed -stubinfo_env_size: ; unsigned short - .dw 0 ; number of bytes of environment -stubinfo_basename: ; char [8] - .db 8 .dup 0 ; base name of executable to load (asciiz if < 8) -stubinfo_argv0: ; char [16] - .db 16 .dup 0 ; used ONLY by the application (asciiz if < 16) -stubinfo_dpmi_server: ; char [16] - .db "CWSDPMI.EXE\0\0\0\0\0" ; used by stub to load DPMI server if no DPMI already present +stubinfo_magic: ; char [16] + .db "go32stub, v 2.04" ; version may change, [0..7] won't +stubinfo_size: ; unsigned long + .dd stubinfo_end ; bytes in structure +stubinfo_minstack: ; unsigned long + .dd 0x80000 ; minimum amount of DPMI stack space (512K) +stubinfo_memory_handle: ; unsigned long + .dd 0 ; DPMI memory handle +stubinfo_initial_size: ; unsigned long + .dd 0 ; size of initial segment +stubinfo_minkeep: ; unsigned short + .dw 16384 ; amount of automatic real-mode buffer +stubinfo_ds_selector: ; unsigned short + .dw 0 ; our DS selector (used for transfer buffer) +stubinfo_ds_segment: ; unsigned short + .dw 0 ; our DS segment (used for simulated calls) +stubinfo_psp_selector: ; unsigned short + .dw 0 ; PSP selector +stubinfo_cs_selector: ; unsigned short + .dw 0 ; to be freed +stubinfo_env_size: ; unsigned short + .dw 0 ; number of bytes of environment +stubinfo_basename: ; char [8] + .db 8 .dup 0 ; base name of executable to load (asciiz if < 8) +stubinfo_argv0: ; char [16] + .db 16 .dup 0 ; used ONLY by the application (asciiz if < 16) +stubinfo_dpmi_server: ; char [16] + .db "CWSDPMI.EXE\0\0\0\0\0" ; used by stub to load DPMI server if no DPMI already present - .align 4 + .align 4 stubinfo_end: ;----------------------------------------------------------------------------- ; First, set up our memory and stack environment - .start ; execution begins here - push cs - pop ds - mov [stubinfo_ds_segment], ds + .start ; execution begins here + push cs + pop ds + mov [stubinfo_ds_segment], ds - mov [psp_segment], es ; save the PSP segment - cld + mov [psp_segment], es ; save the PSP segment + cld ;----------------------------------------------------------------------------- ; Check that we have DOS 3.00 or later. (We need this because earlier ; versions don't supply argv[0] to us and will scrog registers on dpmi exec). - mov ah, 0x30 - int 0x21 - cmp al, 3 - jae dos3ok - mov al, 109 - mov dx, msg_bad_dos - jmpl error + mov ah, 0x30 + int 0x21 + cmp al, 3 + jae dos3ok + mov al, 109 + mov dx, msg_bad_dos + jmpl error dos3ok: - mov [dos_major], al - mov si, stubinfo_minkeep + mov [dos_major], al + mov si, stubinfo_minkeep ;----------------------------------------------------------------------------- ; Resize memory in case we need to exec a DPMI server resize_again: - mov ax, [si] ; si=&stubinfo_minkeep - or ax, ax - jnz @f1 -; mov ax,0xfe00 ; 0 was probably 64k, so max it! (mod 512) - mov ah,0xfe ; al already 0 + mov ax, [si] ; si=&stubinfo_minkeep + or ax, ax + jnz @f1 +; mov ax,0xfe00 ; 0 was probably 64k, so max it! (mod 512) + mov ah,0xfe ; al already 0 @f1: - mov bx, end_of_memory ; does not include PSP - cmp bx, ax ; is our program big enough to hold it? - jae @f1 - mov bx, ax + mov bx, end_of_memory ; does not include PSP + cmp bx, ax ; is our program big enough to hold it? + jae @f1 + mov bx, ax @f1: - mov [si], bx ; si=&stubinfo_minkeep store for reference - inc bh ; add 256 bytes for PSP - mov cx, 0xff04 ; 0xff is for below - shr bx, cl ; bytes to paragraphs + mov [si], bx ; si=&stubinfo_minkeep store for reference + inc bh ; add 256 bytes for PSP + mov cx, 0xff04 ; 0xff is for below + shr bx, cl ; bytes to paragraphs - mov ah, 0x4a ; ES = PSP segment from above - int 0x21 ; resize our memory block - jnc @f1 ; did it work? - shl bx,cl ; calculate smaller [keep] value - dec bh - mov [si], bx ; si=&stubinfo_minkeep - jmp resize_again ; and try again + mov ah, 0x4a ; ES = PSP segment from above + int 0x21 ; resize our memory block + jnc @f1 ; did it work? + shl bx,cl ; calculate smaller [keep] value + dec bh + mov [si], bx ; si=&stubinfo_minkeep + jmp resize_again ; and try again @f1: ;----------------------------------------------------------------------------- ; Scan environment for "PATH=" and the stub's full name after environment - mov es, es:[0x2c] ; get environment segment - xor di, di ; begin search for NUL/NUL (di = 0) -; mov cx, 0xff04 ; effectively `infinite' loop - xor al, al - .db 0xa9 ; "test ax,...." -- skip 2 bytes + mov es, es:[0x2c] ; get environment segment + xor di, di ; begin search for NUL/NUL (di = 0) +; mov cx, 0xff04 ; effectively `infinite' loop + xor al, al + .db 0xa9 ; "test ax,...." -- skip 2 bytes scan_environment: - repne - scasb ; search for NUL - cmpw es:[di], 0x4150 ; "PA" - jne not_path - scasw - cmpw es:[di], 0x4854 ; "TH" - jne not_path - scasw - cmpb es:[di], '=' - jne not_path - inc di ; Point to PATH contents - mov [path_off], di ; save for later - dec di ; in case the PATH is empty + repne + scasb ; search for NUL + cmpw es:[di], 0x4150 ; "PA" + jne not_path + scasw + cmpw es:[di], 0x4854 ; "TH" + jne not_path + scasw + cmpb es:[di], '=' + jne not_path + inc di ; Point to PATH contents + mov [path_off], di ; save for later + dec di ; in case the PATH is empty not_path: - scasb - jne scan_environment ; no, still environment - scasw ; adjust pointer to point to prog name + scasb + jne scan_environment ; no, still environment + scasw ; adjust pointer to point to prog name ;; When we are spawned from a program which has more than 20 handles in use, ;; all the handles passed to us by DOS are taken (since only the first 20 @@ -189,383 +189,383 @@ not_path: ;; Therefore, we forcefully close handles 18 and 19, to make sure at least two ;; handles are available. - mov ah, 0x3e - mov bx, 19 - int 0x21 ; don't care about errors - mov ah, 0x3e - mov bx, 18 - int 0x21 ; don't care about errors + mov ah, 0x3e + mov bx, 19 + int 0x21 ; don't care about errors + mov ah, 0x3e + mov bx, 18 + int 0x21 ; don't care about errors ;----------------------------------------------------------------------------- ; Get DPMI information before doing anything 386-specific - push es - push di - xor cx, cx ; flag for load attempt set cx = 0 - jz @f2 ; We always jump, shorter than jmp + push es + push di + xor cx, cx ; flag for load attempt set cx = 0 + jz @f2 ; We always jump, shorter than jmp @b1: - mov al, 110 - mov dx, msg_no_dpmi - jmpl error + mov al, 110 + mov dx, msg_no_dpmi + jmpl error @b2: - or cx, cx - jnz @b1 ; we already tried load once before - inc cx - call load_dpmi - jc @b1 + or cx, cx + jnz @b1 ; we already tried load once before + inc cx + call load_dpmi + jc @b1 @f2: - mov ax, 0x1687 ; get DPMI entry point - int 0x2f - or ax, ax - jnz @b2 ; if 0 then it's there - and bl, 1 ; 32 bit capable? - jz @b2 + mov ax, 0x1687 ; get DPMI entry point + int 0x2f + or ax, ax + jnz @b2 ; if 0 then it's there + and bl, 1 ; 32 bit capable? + jz @b2 @f3: - mov [modesw], di ; store the DPMI entry point - mov [modesw+2], es - mov [modesw_mem], si - pop di - pop es + mov [modesw], di ; store the DPMI entry point + mov [modesw+2], es + mov [modesw_mem], si + pop di + pop es ;----------------------------------------------------------------------------- ; Now, find the name of the program file we are supposed to load. -; xor ah, ah ; termination character (set above!) - call store_env_string ; copy it to loadname, set bx +; xor ah, ah ; termination character (set above!) + call store_env_string ; copy it to loadname, set bx - mov [stubinfo_env_size], di - mov [loadname_nul], si ; remember nul so we can change it to $ - cmpb stubinfo_basename[0], 0 - je no_symlink + mov [stubinfo_env_size], di + mov [loadname_nul], si ; remember nul so we can change it to $ + cmpb stubinfo_basename[0], 0 + je no_symlink ;----------------------------------------------------------------------------- ; Replace the stub's file name with the link's name after the directory - mov cx, 8 ; max length of basename - mov di, stubinfo_basename ; pointer to new basename + mov cx, 8 ; max length of basename + mov di, stubinfo_basename ; pointer to new basename @b1: - mov al, [di] ; get next character - inc di - or al, al ; end of basename? - je @f1 - mov [bx], al ; store character - inc bx - loop @b1 ; eight characters? + mov al, [di] ; get next character + inc di + or al, al ; end of basename? + je @f1 + mov [bx], al ; store character + inc bx + loop @b1 ; eight characters? @f1: - movd [bx], 0x4558452e ; append ".EXE" - add bx, 4 - movb [bx], 0 ; null terminate - mov [loadname_nul], bx ; remember nul so we can change it to $ + movd [bx], 0x4558452e ; append ".EXE" + add bx, 4 + movb [bx], 0 ; null terminate + mov [loadname_nul], bx ; remember nul so we can change it to $ no_symlink: ;----------------------------------------------------------------------------- ; Load the COFF information from the file - mov ax, 0x3d00 ; open file for reading - mov dx, loadname - int 0x21 - jcl error_no_progfile ; do rest of error message + mov ax, 0x3d00 ; open file for reading + mov dx, loadname + int 0x21 + jcl error_no_progfile ; do rest of error message @f1: - mov [program_file], ax ; store for future reference + mov [program_file], ax ; store for future reference - mov bx, ax - mov cx, exe_header_length - mov dx, exe_header - mov ah, 0x3f ; read EXE header - int 0x21 + mov bx, ax + mov cx, exe_header_length + mov dx, exe_header + mov ah, 0x3f ; read EXE header + int 0x21 - xor dx, dx ; dx = 0 - xor cx, cx ; offset of COFF header + xor dx, dx ; dx = 0 + xor cx, cx ; offset of COFF header - mov ax, [exe_magic] - cmp ax, 0x014c ; COFF? - je file_is_just_coff - cmp ax, 0x5a4d ; EXE magic value - jnel error_not_exe + mov ax, [exe_magic] + cmp ax, 0x014c ; COFF? + je file_is_just_coff + cmp ax, 0x5a4d ; EXE magic value + jnel error_not_exe - mov dx, [exe_sectors] - shl dx, 9 ; 512 bytes per sector - mov bx, [exe_bytes_last_page] - or bx, bx ; is bx = 0 ? - je @f1 - sub dh, 2 ; dx -= 512 - add dx, bx + mov dx, [exe_sectors] + shl dx, 9 ; 512 bytes per sector + mov bx, [exe_bytes_last_page] + or bx, bx ; is bx = 0 ? + je @f1 + sub dh, 2 ; dx -= 512 + add dx, bx @f1: -file_is_just_coff: ; cx:dx is offset - mov coff_offset[0], dx - mov coff_offset[2], cx - mov ax, 0x4200 ; seek from beginning - mov bx, [program_file] - int 0x21 +file_is_just_coff: ; cx:dx is offset + mov coff_offset[0], dx + mov coff_offset[2], cx + mov ax, 0x4200 ; seek from beginning + mov bx, [program_file] + int 0x21 - mov cx, coff_header_length - mov dx, coff_header - mov ah, 0x3f ; read file (bx = handle) - int 0x21 + mov cx, coff_header_length + mov dx, coff_header + mov ah, 0x3f ; read file (bx = handle) + int 0x21 - cmp ax, coff_header_length - jne @f2 - cmpw coff_header[coff_magic], 0x014c + cmp ax, coff_header_length + jne @f2 + cmpw coff_header[coff_magic], 0x014c @f2: - jnel error_not_coff + jnel error_not_coff - mov eax, aout_header[aout_entry] - mov [start_eip], eax + mov eax, aout_header[aout_entry] + mov [start_eip], eax - mov ecx, [coff_offset] + mov ecx, [coff_offset] - mov eax, text_section[s_scnptr] - add eax, ecx - mov [text_foffset], eax + mov eax, text_section[s_scnptr] + add eax, ecx + mov [text_foffset], eax - add ecx, data_section[s_scnptr] ; Ok to destroy ecx now: last use. - mov [data_foffset], ecx + add ecx, data_section[s_scnptr] ; Ok to destroy ecx now: last use. + mov [data_foffset], ecx - mov ebx, bss_section[s_vaddr] - add ebx, bss_section[s_size] - mov eax, 0x00010001 - cmp ebx, eax - jae @f1 - mov ebx, eax ; ensure 32-bit segment + mov ebx, bss_section[s_vaddr] + add ebx, bss_section[s_size] + mov eax, 0x00010001 + cmp ebx, eax + jae @f1 + mov ebx, eax ; ensure 32-bit segment @f1: - add ebx, 0x0000ffff ; ensure 64K rounded - xor bx, bx ; clear rounded bits - mov [stubinfo_initial_size], ebx + add ebx, 0x0000ffff ; ensure 64K rounded + xor bx, bx ; clear rounded bits + mov [stubinfo_initial_size], ebx ;----------------------------------------------------------------------------- ; Set up for the DPMI environment - call include_umb - mov bx, [modesw_mem] - or bx, bx - jz no_dos_alloc + call include_umb + mov bx, [modesw_mem] + or bx, bx + jz no_dos_alloc - mov ah, 0x48 ; allocate memory for the DPMI host - int 0x21 - jcl error_no_dos_memory_umb - mov es, ax + mov ah, 0x48 ; allocate memory for the DPMI host + int 0x21 + jcl error_no_dos_memory_umb + mov es, ax no_dos_alloc: - call restore_umb - mov ax, 1 ; indicates a 32-bit client - callf [modesw] ; enter protected mode + call restore_umb + mov ax, 1 ; indicates a 32-bit client + callf [modesw] ; enter protected mode - jcl error_in_modesw + jcl error_in_modesw ;----------------------------------------------------------------------------- ; We're in protected mode at this point. - mov [stubinfo_psp_selector], es - mov [stubinfo_cs_selector], cs - mov ax, ds - mov [stubinfo_ds_selector], ax - mov es, ax + mov [stubinfo_psp_selector], es + mov [stubinfo_cs_selector], cs + mov ax, ds + mov [stubinfo_ds_selector], ax + mov es, ax - xor ax, ax ; AX = 0x0000 - mov cx, 1 - int 0x31 ; allocate LDT descriptor - jc @f2 - mov [client_cs], ax + xor ax, ax ; AX = 0x0000 + mov cx, 1 + int 0x31 ; allocate LDT descriptor + jc @f2 + mov [client_cs], ax - xor ax, ax ; AX = 0x0000 -; mov cx, 1 ; already set above - int 0x31 ; allocate LDT descriptor + xor ax, ax ; AX = 0x0000 +; mov cx, 1 ; already set above + int 0x31 ; allocate LDT descriptor @f2: - jcl perror_no_selectors - mov [client_ds], ax + jcl perror_no_selectors + mov [client_ds], ax ; Try getting a DPMI 1.0 memory block first, then try DPMI 0.9 ; Note: This causes the Borland Windows VxD to puke, commented for now with ;* -;* mov ax, 0x0504 -;* xor ebx, ebx ; don't specify linear address - mov ecx, stubinfo_initial_size[0] -;* mov edx, 1 ; allocate committed pages -;* int 0x31 ; allocate memory block -;* jc try_old_dpmi_alloc -;* mov client_memory[0], ebx -;* mov stubinfo_memory_handle[0], esi -;* jmp got_dpmi_memory +;* mov ax, 0x0504 +;* xor ebx, ebx ; don't specify linear address + mov ecx, stubinfo_initial_size[0] +;* mov edx, 1 ; allocate committed pages +;* int 0x31 ; allocate memory block +;* jc try_old_dpmi_alloc +;* mov client_memory[0], ebx +;* mov stubinfo_memory_handle[0], esi +;* jmp got_dpmi_memory try_old_dpmi_alloc: - mov ax, 0x0501 - mov bx, stubinfo_initial_size[2] -; mov cx, stubinfo_initial_size[0] ;Set above - int 0x31 ; allocate memory block - jcl perror_no_dpmi_memory - mov client_memory[2], bx - mov client_memory[0], cx - mov stubinfo_memory_handle[2], si - mov stubinfo_memory_handle[0], di + mov ax, 0x0501 + mov bx, stubinfo_initial_size[2] +; mov cx, stubinfo_initial_size[0] ;Set above + int 0x31 ; allocate memory block + jcl perror_no_dpmi_memory + mov client_memory[2], bx + mov client_memory[0], cx + mov stubinfo_memory_handle[2], si + mov stubinfo_memory_handle[0], di got_dpmi_memory: - mov ax, 0x0007 - mov bx, [client_cs] ; initialize client CS - mov cx, client_memory[2] - mov dx, client_memory[0] - int 0x31 ; set segment base address + mov ax, 0x0007 + mov bx, [client_cs] ; initialize client CS + mov cx, client_memory[2] + mov dx, client_memory[0] + int 0x31 ; set segment base address - mov ax, 0x0009 -; mov bx, [client_cs] ; already set above - mov cx, cs ; get CPL - and cx, 0x0003 - shl cx, 5 - push cx ; save shifted CPL for below - or cx, 0xc09b ; 32-bit, big, code, non-conforming, readable - int 0x31 ; set descriptor access rights + mov ax, 0x0009 +; mov bx, [client_cs] ; already set above + mov cx, cs ; get CPL + and cx, 0x0003 + shl cx, 5 + push cx ; save shifted CPL for below + or cx, 0xc09b ; 32-bit, big, code, non-conforming, readable + int 0x31 ; set descriptor access rights - mov ax, 0x0008 -; mov bx, [client_cs] ; already set above - mov cx, stubinfo_initial_size[2] - dec cx - mov dx, 0xffff - int 0x31 ; set segment limit + mov ax, 0x0008 +; mov bx, [client_cs] ; already set above + mov cx, stubinfo_initial_size[2] + dec cx + mov dx, 0xffff + int 0x31 ; set segment limit - mov ax, 0x0007 - mov bx, [client_ds] ; initialize client DS - mov cx, client_memory[2] - mov dx, client_memory[0] - int 0x31 ; set segment base address + mov ax, 0x0007 + mov bx, [client_ds] ; initialize client DS + mov cx, client_memory[2] + mov dx, client_memory[0] + int 0x31 ; set segment base address - mov ax, 0x0009 -; mov bx, [client_ds] ; already set above - pop cx ; shifted CPL from above - or cx, 0xc093 ; 32-bit, big, data, r/w, expand-up - int 0x31 ; set descriptor access rights + mov ax, 0x0009 +; mov bx, [client_ds] ; already set above + pop cx ; shifted CPL from above + or cx, 0xc093 ; 32-bit, big, data, r/w, expand-up + int 0x31 ; set descriptor access rights - mov ax, 0x0008 -; mov bx, [client_ds] ; already set above - mov cx, stubinfo_initial_size[2] - dec cx - mov dx, 0xffff - int 0x31 ; set segment limit + mov ax, 0x0008 +; mov bx, [client_ds] ; already set above + mov cx, stubinfo_initial_size[2] + dec cx + mov dx, 0xffff + int 0x31 ; set segment limit ;----------------------------------------------------------------------------- ; Load the program data - mov ax, 0x0100 - mov bx, 0x0f00 ; 60K DOS block size - int 0x31 ; allocate DOS memory - jnc @f1 - cmp ax, 0x0008 - jnel perror_no_dos_memory - mov ax, 0x0100 ; try again with new value in bx - int 0x31 ; allocate DOS memory - jcl perror_no_dos_memory + mov ax, 0x0100 + mov bx, 0x0f00 ; 60K DOS block size + int 0x31 ; allocate DOS memory + jnc @f1 + cmp ax, 0x0008 + jnel perror_no_dos_memory + mov ax, 0x0100 ; try again with new value in bx + int 0x31 ; allocate DOS memory + jcl perror_no_dos_memory @f1: - mov [dos_block_seg], ax - mov [dos_block_sel], dx - shl bx, 4 ; paragraphs to bytes - mov [dos_block_size], bx + mov [dos_block_seg], ax + mov [dos_block_sel], dx + shl bx, 4 ; paragraphs to bytes + mov [dos_block_size], bx - mov esi, [text_foffset] ; load text section - mov edi, text_section[s_vaddr] - mov ecx, text_section[s_size] - call read_section + mov esi, [text_foffset] ; load text section + mov edi, text_section[s_vaddr] + mov ecx, text_section[s_size] + call read_section - mov esi, [data_foffset] ; load data section - mov edi, data_section[s_vaddr] - mov ecx, data_section[s_size] - call read_section + mov esi, [data_foffset] ; load data section + mov edi, data_section[s_vaddr] + mov ecx, data_section[s_size] + call read_section - mov es, [client_ds] ; clear the BSS section - mov edi, bss_section[s_vaddr] - mov ecx, bss_section[s_size] - xor eax,eax - shr ecx,2 - .addrsize - rep - stosd + mov es, [client_ds] ; clear the BSS section + mov edi, bss_section[s_vaddr] + mov ecx, bss_section[s_size] + xor eax,eax + shr ecx,2 + .addrsize + rep + stosd - mov ah,0x3e - mov bx, [program_file] - int 0x21 ; close the file + mov ah,0x3e + mov bx, [program_file] + int 0x21 ; close the file - mov ax, 0x0101 - mov dx, [dos_block_sel] - int 0x31 ; free up the DOS memory + mov ax, 0x0101 + mov dx, [dos_block_sel] + int 0x31 ; free up the DOS memory - push ds - pop fs - mov ds, [client_ds] - .opsize - jmpf fs:[start_eip] ; start program + push ds + pop fs + mov ds, [client_ds] + .opsize + jmpf fs:[start_eip] ; start program ;----------------------------------------------------------------------------- ; Read a section from the program file read_section: - mov eax, esi ; sector alignment by default - and eax, 0x1ff - add ecx, eax - sub si, ax ; sector align disk offset (can't carry) - sub edi, eax ; memory maybe not aligned! + mov eax, esi ; sector alignment by default + and eax, 0x1ff + add ecx, eax + sub si, ax ; sector align disk offset (can't carry) + sub edi, eax ; memory maybe not aligned! - mov [read_size], ecx ; store for later reference - mov [read_soffset], edi + mov [read_size], ecx ; store for later reference + mov [read_soffset], edi - call zero_regs - mov dpmi_regs[dr_dx], si ; store file offset - shr esi, 16 - mov dpmi_regs[dr_cx], si - mov bx, [program_file] - mov dpmi_regs[dr_bx], bx - movw dpmi_regs[dr_ax], 0x4200 - call pm_dos ; seek to start of data + call zero_regs + mov dpmi_regs[dr_dx], si ; store file offset + shr esi, 16 + mov dpmi_regs[dr_cx], si + mov bx, [program_file] + mov dpmi_regs[dr_bx], bx + movw dpmi_regs[dr_ax], 0x4200 + call pm_dos ; seek to start of data ; Note, handle set above - mov ax, [dos_block_seg] - mov dpmi_regs[dr_ds], ax - movw dpmi_regs[dr_dx], 0 ; store file offset + mov ax, [dos_block_seg] + mov dpmi_regs[dr_ds], ax + movw dpmi_regs[dr_dx], 0 ; store file offset read_loop: - movb dpmi_regs[dr_ah], 0x3f - mov ax, read_size[2] ; see how many bytes to read - or ax, ax - jnz read_too_big - mov ax, read_size[0] - cmp ax, [dos_block_size] - jna read_size_in_ax ; jna shorter than jmp + movb dpmi_regs[dr_ah], 0x3f + mov ax, read_size[2] ; see how many bytes to read + or ax, ax + jnz read_too_big + mov ax, read_size[0] + cmp ax, [dos_block_size] + jna read_size_in_ax ; jna shorter than jmp read_too_big: - mov ax, [dos_block_size] + mov ax, [dos_block_size] read_size_in_ax: - mov dpmi_regs[dr_cx], ax - call pm_dos ; read the next chunk of file data + mov dpmi_regs[dr_cx], ax + call pm_dos ; read the next chunk of file data - xor ecx, ecx - mov cx, dpmi_regs[dr_ax] ; get byte count - mov edi, [read_soffset] ; adjust pointers - add [read_soffset], ecx - sub [read_size], ecx + xor ecx, ecx + mov cx, dpmi_regs[dr_ax] ; get byte count + mov edi, [read_soffset] ; adjust pointers + add [read_soffset], ecx + sub [read_size], ecx - xor esi, esi ; esi=0 offset for copy data - shr cx, 2 ; ecx < 64K - push ds - push es - mov es, [client_ds] - mov ds, [dos_block_sel] - .addrsize - rep - movsd - pop es - pop ds + xor esi, esi ; esi=0 offset for copy data + shr cx, 2 ; ecx < 64K + push ds + push es + mov es, [client_ds] + mov ds, [dos_block_sel] + .addrsize + rep + movsd + pop es + pop ds - add ecx, [read_size] ; ecx zero from the rep movsd - jnz read_loop + add ecx, [read_size] ; ecx zero from the rep movsd + jnz read_loop - ret + ret ;----------------------------------------------------------------------------- ; Routine to check al for delimiter test_delim: - cmp al, ':' ; watch for file name part - je @f3 - cmp al, '/' - je @f3 - cmp al, '\\' + cmp al, ':' ; watch for file name part + je @f3 + cmp al, '/' + je @f3 + cmp al, '\\' @f3: - ret + ret ;----------------------------------------------------------------------------- ; Copy string from environment to loadname. @@ -577,127 +577,127 @@ test_delim: ; al = terminating character store_env_string: - mov si, loadname ; pointer to buffer - mov bx, si ; in case no delimiters + mov si, loadname ; pointer to buffer + mov bx, si ; in case no delimiters @b1: - mov al, es:[di] ; copy a character to buffer - inc di - mov [si], al - cmp al, ah ; end of file name? - je @f1 - or al, al ; end of file name? - je @f1 - inc si - call test_delim - jne @b1 - mov bx, si ; remember pointer to first char of - je @b1 ; next name component (shorter than jmp) + mov al, es:[di] ; copy a character to buffer + inc di + mov [si], al + cmp al, ah ; end of file name? + je @f1 + or al, al ; end of file name? + je @f1 + inc si + call test_delim + jne @b1 + mov bx, si ; remember pointer to first char of + je @b1 ; next name component (shorter than jmp) @f1: - ret + ret ;----------------------------------------------------------------------------- ; Most errors come here, early ones jump direct (8088 instructions) error_no_progfile: - mov al, 102 - mov dx, msg_no_progfile - jmp error_fn + mov al, 102 + mov dx, msg_no_progfile + jmp error_fn error_not_exe: - mov al, 103 - mov dx, msg_not_exe - jmp error_fn + mov al, 103 + mov dx, msg_not_exe + jmp error_fn error_not_coff: - mov al, 104 - mov dx, msg_not_coff -; jmp error_fn + mov al, 104 + mov dx, msg_not_coff +; jmp error_fn error_fn: - push dx - mov bx, [loadname_nul] ; error, print file name - movb [bx], '$' - mov bx, loadname - jmp @f1 + push dx + mov bx, [loadname_nul] ; error, print file name + movb [bx], '$' + mov bx, loadname + jmp @f1 error_no_dos_memory_umb: - call restore_umb + call restore_umb error_no_dos_memory: - mov al, 105 - mov dx, msg_no_dos_memory - jmp error + mov al, 105 + mov dx, msg_no_dos_memory + jmp error error_in_modesw: - mov al, 106 - mov dx, msg_error_in_modesw - jmp error + mov al, 106 + mov dx, msg_error_in_modesw + jmp error perror_no_selectors: - mov al, 107 - mov dx, msg_no_selectors - jmp error + mov al, 107 + mov dx, msg_no_selectors + jmp error perror_no_dpmi_memory: - mov al, 108 - mov dx, msg_no_dpmi_memory - jmp error + mov al, 108 + mov dx, msg_no_dpmi_memory + jmp error perror_no_dos_memory: - mov al, 105 - mov dx, msg_no_dos_memory -; jmp error + mov al, 105 + mov dx, msg_no_dos_memory +; jmp error error: - push dx - mov bx, err_string + push dx + mov bx, err_string @f1: - call printstr - pop bx - call printstr + call printstr + pop bx + call printstr exit: - mov bx, crlfdollar - call printstr - mov ah, 0x4c ; error exit - exit code is in al - int 0x21 + mov bx, crlfdollar + call printstr + mov ah, 0x4c ; error exit - exit code is in al + int 0x21 printstr1: - inc bx - push ax ; have to preserve al set by error call - mov ah, 2 - int 0x21 - pop ax ; restore ax (John A.) + inc bx + push ax ; have to preserve al set by error call + mov ah, 2 + int 0x21 + pop ax ; restore ax (John A.) printstr: - mov dl, [bx] - cmp dl, '$' - jne printstr1 - ret + mov dl, [bx] + cmp dl, '$' + jne printstr1 + ret crlfdollar: - .db 13,10,'$' + .db 13,10,'$' ;----------------------------------------------------------------------------- ; DPMI utility functions zero_regs: - push ax - push cx - push di - xor ax, ax - mov di, dpmi_regs - mov cx, 0x19 - rep - stosw - pop di - pop cx - pop ax - ret + push ax + push cx + push di + xor ax, ax + mov di, dpmi_regs + mov cx, 0x19 + rep + stosw + pop di + pop cx + pop ax + ret pm_dos: - mov ax, 0x0300 ; simulate interrupt - mov bx, 0x0021 ; int 21, no flags - xor cx, cx ; cx = 0x0000 (copy no args) - mov edi, dpmi_regs - int 0x31 - ret + mov ax, 0x0300 ; simulate interrupt + mov bx, 0x0021 ; int 21, no flags + xor cx, cx ; cx = 0x0000 (copy no args) + mov edi, dpmi_regs + int 0x31 + ret ;----------------------------------------------------------------------------- ; load DPMI server if not present @@ -705,189 +705,189 @@ pm_dos: ; On entry di points to image name path_off: - .dw 0 ; If stays zero, no path + .dw 0 ; If stays zero, no path load_dpmi: - xor ah, ah ; Copy until this character (=0) - call store_env_string ; copy stub image to "loadname" - mov si, bx ; remove name so we can add DPMI name - mov di, [path_off] ; Pointer to path contents (next try) - jmp @f2 + xor ah, ah ; Copy until this character (=0) + call store_env_string ; copy stub image to "loadname" + mov si, bx ; remove name so we can add DPMI name + mov di, [path_off] ; Pointer to path contents (next try) + jmp @f2 loadloop: - mov ah, ';' ; Copy until this character - call store_env_string ; to "loadname" - or al,al ; Check terminating character - jne @f1 ; If ';', continue - dec di ; else point at null for next pass. + mov ah, ';' ; Copy until this character + call store_env_string ; to "loadname" + or al,al ; Check terminating character + jne @f1 ; If ';', continue + dec di ; else point at null for next pass. @f1: - cmp si, loadname ; anything there? - je do_exec ; final try (no path) let it return - mov al, [si-1] - call test_delim ; is final character a path delimiter - je @f2 - movb [si], '\\' ; no, add separator between path & name - inc si + cmp si, loadname ; anything there? + je do_exec ; final try (no path) let it return + mov al, [si-1] + call test_delim ; is final character a path delimiter + je @f2 + movb [si], '\\' ; no, add separator between path & name + inc si @f2: - call do_exec ; copy our name to string and try load - jc loadloop - ret + call do_exec ; copy our name to string and try load + jc loadloop + ret ;----------------------------------------------------------------------------- ; add the string CWSDPMI to path ending do_exec: - call include_umb - mov bx, stubinfo_dpmi_server + call include_umb + mov bx, stubinfo_dpmi_server @b1: - mov al, [bx] - mov [si], al - inc bx - inc si - or al, al - jne @b1 -; movw [si], 0x0a0d ;debug -; movb [si+2], '$' ;debug + mov al, [bx] + mov [si], al + inc bx + inc si + or al, al + jne @b1 +; movw [si], 0x0a0d ;debug +; movb [si+2], '$' ;debug - push es ; Save in case of failure - push di + push es ; Save in case of failure + push di ;memory saving - use dpmi_regs as a temporary parameter block - push ds - pop es ;zero_regs needs es set - call zero_regs - mov bx, dpmi_regs - mov [bx+4], ds ;segment of command tail - mov [bx+2], bx ;offset (point to zero) + push ds + pop es ;zero_regs needs es set + call zero_regs + mov bx, dpmi_regs + mov [bx+4], ds ;segment of command tail + mov [bx+2], bx ;offset (point to zero) - mov dx, loadname -; mov ah, 9 ;debug -; int 0x21 ;debug - mov ax, 0x4b00 ;Do program exec - int 0x21 - pop di - pop es - jc @f1 ;carry set if exec failed + mov dx, loadname +; mov ah, 9 ;debug +; int 0x21 ;debug + mov ax, 0x4b00 ;Do program exec + int 0x21 + pop di + pop es + jc @f1 ;carry set if exec failed - mov ah, 0x4d ;get return code - int 0x21 - sub ax, 0x300 ;ah=3 TSR, al=code (success) - neg ax ;CY, if not originally 0x300 + mov ah, 0x4d ;get return code + int 0x21 + sub ax, 0x300 ;ah=3 TSR, al=code (success) + neg ax ;CY, if not originally 0x300 @f1: - jmp restore_umb ;called func. return for us. + jmp restore_umb ;called func. return for us. ;----------------------------------------------------------------------------- ; Make upper memory allocatable. Clobbers Ax and Bx. include_umb: - cmpb [dos_major], 5 ; Won't work before dos 5 - jb @f1 - mov ax, 0x5800 ; get allocation strategy - int 0x21 - mov [old_strategy],al - mov ax, 0x5802 ; Get UMB status. - int 0x21 - mov [old_umb],al - mov ax, 0x5801 - mov bx, 0x0080 ; first fit, first high then low - int 0x21 - mov ax, 0x5803 - mov bx, 0x0001 ; include UMB in memory chain - int 0x21 + cmpb [dos_major], 5 ; Won't work before dos 5 + jb @f1 + mov ax, 0x5800 ; get allocation strategy + int 0x21 + mov [old_strategy],al + mov ax, 0x5802 ; Get UMB status. + int 0x21 + mov [old_umb],al + mov ax, 0x5801 + mov bx, 0x0080 ; first fit, first high then low + int 0x21 + mov ax, 0x5803 + mov bx, 0x0001 ; include UMB in memory chain + int 0x21 @f1: - ret + ret ; Restore upper memory status. All registers and flags preserved. restore_umb: - pushf - cmpb [dos_major], 5 ; Won't work before dos 5 - jb @f1 - push ax - push bx - mov ax, 0x5803 ; restore UMB status. - mov bl,[old_umb] - xor bh, bh - int 0x21 - mov ax, 0x5801 ; restore allocation strategy - mov bl,[old_strategy] - xor bh, bh - int 0x21 - pop bx - pop ax + pushf + cmpb [dos_major], 5 ; Won't work before dos 5 + jb @f1 + push ax + push bx + mov ax, 0x5803 ; restore UMB status. + mov bl,[old_umb] + xor bh, bh + int 0x21 + mov ax, 0x5801 ; restore allocation strategy + mov bl,[old_strategy] + xor bh, bh + int 0x21 + pop bx + pop ax @f1: - popf - ret + popf + ret ;----------------------------------------------------------------------------- ; Stored Data err_string: - .db "Load error: $" + .db "Load error: $" msg_no_progfile: - .db ": can't open$" + .db ": can't open$" msg_not_exe: - .db ": not EXE$" + .db ": not EXE$" msg_not_coff: - .db ": not COFF (Check for viruses)$" + .db ": not COFF (Check for viruses)$" msg_no_dpmi: - .db "no DPMI - Get csdpmi*b.zip$" + .db "no DPMI - Get csdpmi*b.zip$" msg_no_dos_memory: - .db "no DOS memory$" + .db "no DOS memory$" msg_bad_dos: - .db "need DOS 3$" + .db "need DOS 3$" msg_error_in_modesw: - .db "can't switch mode$" + .db "can't switch mode$" msg_no_selectors: - .db "no DPMI selectors$" + .db "no DPMI selectors$" msg_no_dpmi_memory: - .db "no DPMI memory$" + .db "no DPMI memory$" ;----------------------------------------------------------------------------- ; Unstored Data, available during and after mode switch last_generated_byte: - .align 512 ; Align ourselves to a sector - ; boundary for startup speed. - .bss ; data after this isn't in file. + .align 512 ; Align ourselves to a sector + ; boundary for startup speed. + .bss ; data after this isn't in file. -modesw: ; address of DPMI mode switch - .dd 0 -modesw_mem: ; amount of memory DPMI needs - .dw 0 +modesw: ; address of DPMI mode switch + .dd 0 +modesw_mem: ; amount of memory DPMI needs + .dw 0 -program_file: ; file ID of program data - .dw 0 +program_file: ; file ID of program data + .dw 0 -text_foffset: ; offset in file - .dd 0 +text_foffset: ; offset in file + .dd 0 -data_foffset: ; offset in file - .dd 0 +data_foffset: ; offset in file + .dd 0 -start_eip: ; EIP value to start at - .dd 0 -client_cs: ; must follow start_eip - .dw 0 +start_eip: ; EIP value to start at + .dd 0 +client_cs: ; must follow start_eip + .dw 0 client_ds: - .dw 0 + .dw 0 client_memory: - .dd 0 + .dd 0 dos_block_seg: - .dw 0 + .dw 0 dos_block_sel: - .dw 0 + .dw 0 dos_block_size: - .dw 0 + .dw 0 read_soffset: - .dd 0 + .dd 0 read_size: - .dd 0 + .dd 0 dpmi_regs: - .db 0x32 .dup 0 + .db 0x32 .dup 0 dr_edi = 0x00 dr_di = 0x00 dr_esi = 0x04 @@ -922,67 +922,67 @@ dr_ss = 0x30 ;----------------------------------------------------------------------------- - .align 16 ; so that stack ends on para boundary - .dw 128 .dup 0 - .stack + .align 16 ; so that stack ends on para boundary + .dw 128 .dup 0 + .stack ;----------------------------------------------------------------------------- ; At one time real mode only data. Header stuff now used during image load. psp_segment: - .dw 0 + .dw 0 -loadname_nul: ; offset of NUL so it can become '$' - .dw 0 -loadname: ; name of program file to load, if it - .db 81 .dup 0 ; gets really long ok to overwrite next +loadname_nul: ; offset of NUL so it can become '$' + .dw 0 +loadname: ; name of program file to load, if it + .db 81 .dup 0 ; gets really long ok to overwrite next -exe_header: ; loaded from front of loadfile +exe_header: ; loaded from front of loadfile exe_magic: - .dw 0 + .dw 0 exe_bytes_last_page: - .dw 0 + .dw 0 exe_sectors: - .dw 0 + .dw 0 exe_header_length = . - exe_header coff_offset: - .dd 0 ; from start of file + .dd 0 ; from start of file -coff_header: ; loaded from after stub - .db 20 .dup 0 +coff_header: ; loaded from after stub + .db 20 .dup 0 aout_header: - .db 28 .dup 0 + .db 28 .dup 0 text_section: - .db 40 .dup 0 + .db 40 .dup 0 data_section: - .db 40 .dup 0 + .db 40 .dup 0 bss_section: - .db 40 .dup 0 + .db 40 .dup 0 coff_header_length = . - coff_header old_strategy: - .db 0 + .db 0 old_umb: - .db 0 + .db 0 dos_major: - .db 0 + .db 0 - .align 16 ; Align ourselves to a paragraph -end_of_memory: ; resize is done early so must keep all + .align 16 ; Align ourselves to a paragraph +end_of_memory: ; resize is done early so must keep all ;----------------------------------------------------------------------------- ; structure definitions ; -coff_magic = 0 ; from coff header +coff_magic = 0 ; from coff header -aout_entry = 16 ; from aout header +aout_entry = 16 ; from aout header -s_paddr = 8 ; from section headers -s_vaddr = 12 -s_size = 16 -s_scnptr = 20 +s_paddr = 8 ; from section headers +s_vaddr = 12 +s_size = 16 +s_scnptr = 20