📄 stub.asm
字号:
; 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 casestubinfo:stubinfo_magic: ; char [16] .db "go32stub, v 2.04" ; version may change, [0..7] won'tstubinfo_size: ; unsigned long .dd stubinfo_end ; bytes in structurestubinfo_minstack: ; unsigned long .dd 0x80000 ; minimum amount of DPMI stack space (512K)stubinfo_memory_handle: ; unsigned long .dd 0 ; DPMI memory handlestubinfo_initial_size: ; unsigned long .dd 0 ; size of initial segmentstubinfo_minkeep: ; unsigned short .dw 16384 ; amount of automatic real-mode bufferstubinfo_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 selectorstubinfo_cs_selector: ; unsigned short .dw 0 ; to be freedstubinfo_env_size: ; unsigned short .dw 0 ; number of bytes of environmentstubinfo_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 4stubinfo_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 errordos3ok: mov [dos_major], al mov si, stubinfo_minkeep;-----------------------------------------------------------------------------; Resize memory in case we need to exec a DPMI serverresize_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 bytesscan_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 emptynot_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -