1
0
mirror of https://github.com/upx/upx synced 2025-09-28 19:06:07 +08:00
upx/src/stub/stub.asm
Markus F.X.J. Oberhumer a19e6cd4f5 Detabified.
committer: mfx <mfx> 1084317075 +0000
2004-05-11 23:11:15 +00:00

989 lines
33 KiB
NASM

; Copyright (C) 2002 DJ Delorie, see COPYING.DJ for details
; Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details
; Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details
; Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details
; Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details
; Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details
; -*- asm -*-
;
; KLUDGE-WARNING!
;
; So you say you want to change this file, right? Are you really sure
; that's a good idea? Let me tell you a bit about the pitfalls here:
;
; * Some code runs in protected mode, some in real-mode, some in both.
; * Some code must run on a 8088 without crashing it.
; * Registers and flags may be expected to survive for a long time.
; * The code is optimized for size, not for speed or readability.
; * Some comments are parsed by other programs.
;
; You still want to change it? Oh well, go ahead, but don't come
; crying back saying you weren't warned.
;
;-----------------------------------------------------------------------------
; djgpp extender-less stub loader
;
; (C) Copyright 1993-1995 DJ Delorie
;
; Redistribution and use in source and binary forms are permitted
; provided that: (1) source distributions retain this entire copyright
; notice and comment, (2) distributions including binaries display
; the following acknowledgement: ``This product includes software
; developed by DJ Delorie and contributors to the djgpp project''
; in the documentation or other materials provided with the distribution
; and in all advertising materials mentioning features or use of this
; software, and (3) binary distributions include information sufficient
; for the binary user to obtain the sources for the binary and utilities
; required to built and use it. Neither the name of DJ Delorie nor the
; names of djgpp's contributors may be used to endorse or promote
; products derived from this software without specific prior written
; permission.
;
; THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
; IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
;
; Revision history:
;
; 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
;
.copyright "The STUB.EXE stub loader is Copyright (C) 1993-1995 DJ Delorie. "
.copyright "Permission granted to use for any purpose provided this copyright "
.copyright "remains present and unmodified. "
.copyright "This only applies to the stub, and not necessarily the whole program.\n"
.id
;
;-----------------------------------------------------------------------------
; 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)
; <others> 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
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
.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
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
dos3ok:
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
@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
@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 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
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
not_path:
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
;; handles are inherited), and opening the .exe file will fail.
;; 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
;-----------------------------------------------------------------------------
; 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
@b1:
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
@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
@f3:
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
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
@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?
@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 $
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
@f1:
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
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 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
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
@f2:
jnel error_not_coff
mov eax, aout_header[aout_entry]
mov [start_eip], eax
mov ecx, [coff_offset]
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
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
;-----------------------------------------------------------------------------
; Set up for the DPMI environment
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
no_dos_alloc:
call restore_umb
mov ax, 1 ; indicates a 32-bit client
callf [modesw] ; enter protected mode
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
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
@f2:
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
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
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, 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, 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, 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
@f1:
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, [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 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
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 [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
; Note, handle set above
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
read_too_big:
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
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
add ecx, [read_size] ; ecx zero from the rep movsd
jnz read_loop
ret
;-----------------------------------------------------------------------------
; Routine to check al for delimiter
test_delim:
cmp al, ':' ; watch for file name part
je @f3
cmp al, '/'
je @f3
cmp al, '\\'
@f3:
ret
;-----------------------------------------------------------------------------
; Copy string from environment to loadname.
; On entry: di = environment offset
; ah = termination character (null also does)
; On exit: bx = pointer to one character after last observed file delimiter
; di = pointer to one character after last copied
; si = pointer to the copied termination character
; al = terminating character
store_env_string:
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)
@f1:
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
error_not_exe:
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
error_fn:
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
error_no_dos_memory:
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
perror_no_selectors:
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
perror_no_dos_memory:
mov al, 105
mov dx, msg_no_dos_memory
; jmp error
error:
push dx
mov bx, err_string
@f1:
call printstr
pop bx
call printstr
exit:
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.)
printstr:
mov dl, [bx]
cmp dl, '$'
jne printstr1
ret
crlfdollar:
.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
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
;-----------------------------------------------------------------------------
; load DPMI server if not present
; First check directory from which stub is loaded, then path, then default
; On entry di points to image name
path_off:
.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
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.
@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
@f2:
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
@b1:
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
;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)
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
@f1:
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
@f1:
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
@f1:
popf
ret
;-----------------------------------------------------------------------------
; Stored Data
err_string:
.db "Load error: $"
msg_no_progfile:
.db ": can't open$"
msg_not_exe:
.db ": not EXE$"
msg_not_coff:
.db ": not COFF (Check for viruses)$"
msg_no_dpmi:
.db "no DPMI - Get csdpmi*b.zip$"
msg_no_dos_memory:
.db "no DOS memory$"
msg_bad_dos:
.db "need DOS 3$"
msg_error_in_modesw:
.db "can't switch mode$"
msg_no_selectors:
.db "no DPMI selectors$"
msg_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.
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
text_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
client_ds:
.dw 0
client_memory:
.dd 0
dos_block_seg:
.dw 0
dos_block_sel:
.dw 0
dos_block_size:
.dw 0
read_soffset:
.dd 0
read_size:
.dd 0
dpmi_regs:
.db 0x32 .dup 0
dr_edi = 0x00
dr_di = 0x00
dr_esi = 0x04
dr_si = 0x04
dr_ebp = 0x08
dr_bp = 0x08
dr_ebx = 0x10
dr_bx = 0x10
dr_bl = 0x10
dr_bh = 0x11
dr_edx = 0x14
dr_dx = 0x14
dr_dl = 0x14
dr_dh = 0x15
dr_ecx = 0x18
dr_cx = 0x18
dr_cl = 0x18
dr_ch = 0x19
dr_eax = 0x1c
dr_ax = 0x1c
dr_al = 0x1c
dr_ah = 0x1d
dr_efl = 0x20
dr_es = 0x22
dr_ds = 0x24
dr_fs = 0x26
dr_gs = 0x28
dr_ip = 0x2a
dr_cs = 0x2c
dr_sp = 0x2e
dr_ss = 0x30
;-----------------------------------------------------------------------------
.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
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_magic:
.dw 0
exe_bytes_last_page:
.dw 0
exe_sectors:
.dw 0
exe_header_length = . - exe_header
coff_offset:
.dd 0 ; from start of file
coff_header: ; loaded from after stub
.db 20 .dup 0
aout_header:
.db 28 .dup 0
text_section:
.db 40 .dup 0
data_section:
.db 40 .dup 0
bss_section:
.db 40 .dup 0
coff_header_length = . - coff_header
old_strategy:
.db 0
old_umb:
.db 0
dos_major:
.db 0
.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
aout_entry = 16 ; from aout header
s_paddr = 8 ; from section headers
s_vaddr = 12
s_size = 16
s_scnptr = 20