home *** CD-ROM | disk | FTP | other *** search
- ; 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 neccessarily 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.00" ; version may change, [0..7] won't
- stubinfo_size: ; unsigned long
- .dd stubinfo_end ; bytes in structure
- stubinfo_minstack: ; unsigned long
- .dd 0x40000 ; minimum amount of DPMI stack space (256K)
- 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 dx, msg_bad_dos
- jmpl error
- dos3ok:
- mov [dos_major], al
-
- ;-----------------------------------------------------------------------------
- ; Resize memory in case we need to exec a DPMI server
-
- resize_again:
- mov bx, end_of_memory ; does not include PSP
- mov ax, [stubinfo_minkeep]
- cmp bx, ax ; is our program big enough to hold it?
- jae @f1
- mov bx, ax
- @f1:
- mov [stubinfo_minkeep], bx ; 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 [stubinfo_minkeep], bx
- 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
-
- ;-----------------------------------------------------------------------------
- ; 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 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+0], 0x4558452e ; append ".EXE"
- add bx, 4
- mov [bx], al ; al = 0
- 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
-
- mov eax, data_section[s_scnptr]
- add eax, ecx
- mov [data_foffset], eax
-
- mov ebx, bss_section[s_vaddr]
- mov eax, bss_section[s_size]
- add ebx, eax
- 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 dx, msg_no_progfile
- jmp error_fn
-
- error_not_exe:
- mov dx, msg_not_exe
- jmp error_fn
-
- error_not_coff:
- 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 dx, msg_no_dos_memory
- jmp error
-
- error_in_modesw:
- mov dx, msg_error_in_modesw
- jmp error
-
- perror_no_selectors:
- mov dx, msg_no_selectors
- jmp error
-
- perror_no_dpmi_memory:
- mov dx, msg_no_dpmi_memory
- jmp error
-
- perror_no_dos_memory:
- 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 ax, 0x4cff ; error exit
- int 0x21
-
- printstr1:
- inc bx
- mov ah, 2
- int 0x21
- 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"
- 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 ": cannot 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
-
-
-