home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
fwktl101.zip
/
HELOWRLD.ASM
< prev
next >
Wrap
Assembly Source File
|
1996-05-28
|
22KB
|
561 lines
TITLE HELOWRLD
NAME HELOWRLD
.386
.387
; HELOWRLD.ASM can be assembled using IBM's ALP 3.00.004 assembler,
; linked to make a pseudo .DLL using LINK386, and
; stripped to leave only the FWKTL_format program using FWKTRIM.
TEXT32 SEGMENT DWORD PUBLIC 'CODE'
ASSUME CS:FLAT, DS:FLAT
ALIGN 4
MAIN:
; This is a "Hello, world!" program for loading and execution in
; OS/2 Warp protected mode, using the FWKTL(TM) Text_program Loader,
; Version 1.01, to load it.
;
; (C)Copyright Frederick W. Kantor 1996. All rights reserved.
;
; programs loaded by FWKTL can modify themselves, and can modify
; their source (the file from which the program was loaded)
;
;
; To assemble in an OS/2 session using IBM's ALP 3.00.004, run
;
; MK_HWASM.CMD
;
; (enclosed in this package) and follow the instructions on the screen
; to make HELOWLD2.COM;
;
; the .COM extension can then be changed or removed, to help avoid
; error. FWKTL loads it independent of extension.
;
; if the resulting .COM program is executed directly in a DOS or OS/2
; environment, it returns to the command line: the first byte is RET.
;
; There are 3 examples in this "Hello, world." program. The only
; parameter you need to set to use them is EXAMPLE :
; EXAMPLE EQU 1
; EXAMPLE EQU 2
; EXAMPLE EQU 3
EXAMPLE EQU 1 ; current setting
;
; EXAMPLE EQU 1
; uses PSETUP = 0 in initialization; HELOWLD2.COM is 69 bytes long;
; this configuration shows how to get an API's address when you
; already have the module handle; it gets a specific address for a
; single procedure, DOS32WRITE (DOSCALLS.282) (see also P_ STRUC);
; the handle for the DOSCALLS module is provided by FWKTL as part
; of the initial data.
;
; EXAMPLE EQU 2
; sets PSETUP = 1; HELOWRLD.COM is 41 bytes long; this uses a simple
; SHOW procedure in FWKTL to send an ASCIIZ string up to, but not
; including, its terminal 00 to 'standard output' (defaults to
; screen), and append a terminal carriage_return line_feed. (to save
; space, the exit errorlevel is not set to zero: the errorlevel
; returned is the low 16 bits of the DWORD for the program's entry
; point.)
;
; EXAMPLE EQU 3
; sets PSETUP = 0; HELOWLD2.COM is 142 bytes long;
; this illustrates how functions can be easily added; it gets
; addresses for a list of 25 APIs and uses two of them, one to write
; "Hello, world!",0d,0a to "standard output" (the screen), and the
; other to sound a tone. The APIs loaded in example 3 include tools
; for loading and freeing other dynamic link library modules,
; allocating and freeing memory, some semaphore procedures, etc.
; To run the assembled HELOWLD2.COM in an OS/2 session:
;
; Format: FWKTL HELOWLD2.COM <enter>
; Initialization:
;
; FWKTL loads a program and sets
;
; EAX = entry point for execution
; EBX = 0 if no free memory requested
; ELSE EBX DWORD aligned, after code
; ECX = number of DWORDs in initialization requested (see P_ STRUC)
; ESI points to start of initialization_data source (matching start
; of P_)
; EDI = 0 if no free memory requested
; ELSE EDI = EBX = start of free memory, in case you wish to put
; initialization data there
; the "direction flag" (decrement flag) is cleared (CLD)
;
; FWKTL provides initial values, and several procedures;
; see P_ STRUC, below, for initial values and procedure addresses.
; These values are easily copied, with ESI, EDI, ECX, and CLD from
; FWKTL. If free memory was requested (done in HELOWRLD.1), use
; REP MOVSD
; If no free memory was requested, save values in STACK. For saving
; EBX in STACK, I suggest you modify J_ STRUC and put J_EBX at the
; beginning, and load EDI with the effective address of the beginning
; of the standard FWKTL initialization values: e.g.,
; SUB ESP,TYPE J_
; MOV EBP,ESP
; LEA EDI,[EBP].P_LOADEDAT ; where to put initialization data
; REP MOVSD ; using ESI, ECX, and CLD from FWKTL
; FWKTL calls the program as a routine in Thread 1:
;
; on entry, the stack will not return an exception until 0ABAh dwords
; are pushed (= 02AE8h bytes = 10984 (decimal) bytes)
;
; on return to FWKTL: CS, SS, and ESP must be correct when RET
; is executed
;
; EAX, EBX, ECX, EDX, ESI, EDI, EBP, DS, ES, FS, GS can be changed
;
; EAX is used to return an exit errorlevel, of which the low 16 bits
; (AX) is returned by OS/2 Warp at the command line.
; to display exit errorlevels, you can use PROMPT=[$p $r]
;-------------------------------------------------------
KEEP_EBX EQU 00 ; set to 1 to store EBX in stack, so that it can
; be recovered by MOV EBX,[EBP] (e.g., in case a
; procedure called changes it); EBP may be less
; likely to be changed than EBX during such calls.
; All calls used in these 3 examples preserve EBX,
; so this is not used.
;-------------------------------------------------------
; PSETUP is used to control P_ STRUC and to set
; bit00 in second DWORD in the program header
; = 0 to get the shorter initial setup data;
; = 1 to get the longer initial setup data which
; has the addresses for the SHOW and USWORDCAPS
; utilities
IF EXAMPLE EQ 1 OR EXAMPLE EQ 3
PSETUP EQU 0
ELSEIF EXAMPLE EQ 2
PSETUP EQU 1
ENDIF
;-------------------------------------------------------
; structure for initial data:
P_ STRUC ; these are provided by FWKTL for initialization,
; according to file header settings:
P_LOADEDAT DD ? ; start of this memory block
P_PWHENCE DD ? ; points to ASCIIZ string re where program was found
P_PCOMTAIL DD ? ; points to ASCIIZ command tail
P_GETFN DD ? ; address for indirect call to FWKTL GETFN function:
; Input:
; EAX = ProcedureOrdinal
; (maximum permitted OS/2 ordinal <= 65533)
; if EAX > 0, ESI is ignored
; OR
; EAX = 0
; ESI points to ASCIIZ procedure_name
;
; EDX = module handle
; EDI points to target DWORD to receive
; procedure address
;
; Output:
; if successful,
; zero_flag is set
; procedure address is in target DWORD
; EAX = 0
;
; if error
; zero_flag is cleared
; EAX contains error number:
; 6 ERROR_INVALID_HANDLE
; 123 ERROR_INVALID_NAME
; 65079 ERROR_ENTRY_IS_CALLGATE
;
; all other CPU registers and flags are preserved
P_GETFNLIST DD ? ; address for indirect call to FWKTL GETFNLIST
; function, to get the addresses for a list of
; procedures in the same module:
;
; EBX, EDX, EBP are preserved across this function
;
; Input:
; EAX = 0 if list is ASCIIZ procedure_names
; 2 if list is WORD ordinals
; 4 if list is DWORD ordinals
; (maximum permitted OS/2 ordinal = 65533)
; ECX = number of items in procedure list
; EDX = module handle
; ESI points to start of list of WORDs, DWORDs,
; or series of ASCIIZ procedure_names
; EDI points to start of target DWORDs to receive
; the corresponding procedure addresses
;
; Output:
; if no error:
; zero_flag is set
; each target DWORD contains its procedure address
; ESI:
; if EAX = 0
; ESI points to terminal 00h of last ASCIIZ
; string;
; ELSE if EAX > 0
; ESI points to first byte after source;
; EDI points to first byte after last target DWORD
;
; if error:
; zero_flag is cleared
; EAX contains error number:
; 6 ERROR_INVALID_HANDLE
; 123 ERROR_INVALID_NAME
; 65079 ERROR_ENTRY_IS_CALLGATE
; ECX is not decremented on failed step
; ESI points to list item identifying the procedure
; for which the failure occurred
P_HDOSCALLS DD ? ; handle for DOSCALLS module as loaded by FWKTL,
; can be used in EDX for P_GETFN or P_GETFNLIST.
;------------------------- end of setup for PSETUP EQ 0
IF PSETUP EQ 1
; two additional procedures are optionally available from FWKTL:
P_SHOW DD ? ; address for FWKTL SHOW function;
;
; usage:
;
; ESI points to ASCIIZ string to show on screen
; using 'standard error' handle=2;
; this procedure drops terminal 00 and adds 0D,0A;
; all CPU registers and flags are preserved.
P_USWORDCAPS DD ? ; address for FWKTL capitalization function;
;
; usage:
;
; ESI points to contiguous string > ' ' to
; capitalize, US English;
; all CPU registers and flags are preserved.
;
; (e.g., this procedure can be used when '/' or '-'
; is found in command tail, for case_insensitive
; options when you don't capitalize whole tail)
ENDIF ;------------------------- end of setup for PSETUP EQ 1
IF EXAMPLE EQ 1 OR EXAMPLE EQ 3 ; these are used with an API:
P_WROTE DD ? ; used with the DOS32WRITE API
P_WRITE DD ? ; to hold address for OS/2 DOS32WRITE API
; Note: P_WRITE is also the first entry in the
; address targets used in EXAMPLE EQ 3:
; P_WROTE must not be inserted directly
; below P_WRITE, because it would offset
; the rest of the address targets in
; EXAMPLE EQ 3
ENDIF
; other material can be inserted here:
IF EXAMPLE EQ 3 ; addresses for 24 more APIs
P_SCANENV DD ?
P_SEARCHPATH DD ?
P_SLEEP DD ?
P_EXIT DD ?
P_SETFILEPTR DD ?
P_CLOSE DD ?
P_OPEN DD ?
P_READ DD ?
P_BEEP DD ? ; see note on using BEEP for diagnostics, below
P_ALLOCMEM DD ?
P_FREEMEM DD ?
P_CREATETHREAD DD ?
P_GETINFOBLOCKS DD ?
P_LOADMODULE DD ?
P_QUERYPROCADDR DD ?
P_FREEMODULE DD ?
P_CREATEEVENTSEM DD ?
P_OPENEVENTSEM DD ?
P_CLOSEEVENTSEM DD ?
P_RESETEVENTSEM DD ?
P_POSTEVENTSEM DD ?
P_WAITEVENTSEM DD ?
P_QUERYEVENTSEM DD ?
P_QUERYSYSINFO DD ?
ENDIF ; EXAMPLE EQ 3
P_ ENDS ; end of P_ STRUC
;-------------------------------------------------------
; Note: BEEP is convenient for simple diagnostics;
; e.g., you can insert code blocks like this to make a tone
; when each such place is reached, and set different values
; for frequency and/or duration to distinguish the beeps;
; registers and flags are preserved across this function:
; put this before the first beep call you want turned on:
;
; rundb equ 01 ; 01 to insert them (and remove initial ";"),
; ; 00 to exclude them
; if rundb ;debug
; pushfd ;debug
; pushad ;debug
; pushd 0100h ; duration, milliseconds ;debug
; pushd 0100h ; frequency, cycles per second ;debug
; call [ebx].p_beep ;debug
; add esp,08 ;debug
; popad ;debug
; popfd ;debug
; endif ;debug
;-------------------------------------------------------
; Here is the code header:
; the first byte of the header is a RET, in case the program has
; a .COM extension and someone accidentally tries to run it directly
; in a DOS or OS/2 session.
CODESTART: ; used as a reference point
RET ; 4_byte header identification string
DB 'FWK' ;
DD PSETUP ; bit00 = 0 for PSETUP=0 (see P_ STRUC)
; bit00 = 1 for PSETUP=1 (see P_ STRUC)
; bits 31...01 are reserved, and must be zero for use with
; FWKTL version 1.00.
DD TYPE P_ ; amount of free memory requested after code;
; in these examples, just enough to hold a P_ STRUC;
; PSETUP affects the size of P_ STRUC used
; to hold standard FWKTL initialization data;
; storage of any other data there also affects the
; size of P_ STRUC; e.g., P_ can contain buffers.
; the free memory starts DWORD aligned, zeroed.
; more memory than used in P_ STRUC can be requested;
; note that memory requested in this way is committed
; when allocated.
; for efficiency and flexibility, programs which need a
; lot of memory can use API procedures to allocate and
; free memory, rather than asking for it as part of
; installation. EXAMPLE EQ 3 loads the addresses for
; calling some memory management procedures.
; Note that this kind of program can write new code into
; the memory and then run it, or can relocate or modify
; itself and continue to run.
; Here is where the executable code starts;
JMP SHORT LL0 ; this is the execution entry point.
; at this point, the STACK from FWKTL provides working space
; for 0400h (1024 decimal) dwords, not counting space
; allowed for system use;
; the STACK will not return an exception until more than
; 0ABAh dwords are on the stack (2746 decimal)
; EAX = entry point for execution
; EBX = start of free memory, DWORD aligned, after code
; ECX = number of initialization DWORDs requested (P_ STRUC)
; ESI points to start of initialization_data source (matching
; start of P_)
; EDI=EBX to put initialization data there (using REP MOVSD)
; decrement flag has been cleared (CLD) (for using REP MOVSD)
MSG:
OMSG EQU $-CODESTART ; used in calculating where this message is
DB 'Hello, world!'
IF EXAMPLE EQ 2 ; the FWKTL SHOW procedure is for use with ASCIIZ strings;
DB 00 ; terminal 00 to make ASCIIZ string (SHOW provides CRLF)
ELSE ;
DB 0DH,0AH ; carriage_return line_feed (for use with DOS32WRITE API)
ENDIF ;
LMSG EQU $-MSG
IF EXAMPLE EQ 3 ; this is a flexible method, using an expandable list
; of procedures; in this example the procedures are
; identified using ordinal numbers (this is required for
; DOSCALLS procedures), but this method can be used with
; procedures identified by name, in a list of ASCIIZ
; procedure_names.
FNLIST: ; list of procedures (DOSCALLS ordinals).
OFNLIST EQU $-CODESTART ; offset used for finding FNLIST in memory.
; these decimal number WORDs are in the same order
; as their corresponding DD targets in P_ STRUC
; these are the procedures (APIs) included in EXAMPLE=3:
; decimal ordinals
DW 282 ; DOS32WRITE (DOSCALLS.282)
DW 227 ; DOS32SCANENV (DOSCALLS.227)
DW 228 ; DOS32SEARCHPATH (DOSCALLS.228)
DW 229 ; DOS32SLEEP (DOSCALLS.229)
DW 234 ; DOS32EXIT (DOSCALLS.234)
DW 256 ; DOS32SETFILEPTR (DOSCALLS.256)
DW 257 ; DOS32CLOSE (DOSCALLS.257)
DW 273 ; DOS32OPEN (DOSCALLS.273)
DW 281 ; DOS32READ (DOSCALLS.281)
DW 286 ; DOS32BEEP (DOSCALLS.286)
DW 299 ; DOS32ALLOCMEM (DOSCALLS.299)
DW 304 ; DOS32FREEMEM (DOSCALLS.304)
DW 311 ; DOS32CREATETHREAD (DOSCALLS.311)
DW 312 ; DOS32GETINFOBLOCKS (DOSCALLS.312)
DW 318 ; DOS32LOADMODULE (DOSCALLS.318)
DW 321 ; DOS32QUERYPROCADDR (DOSCALLS.321)
DW 322 ; DOS32FREEMODULE (DOSCALLS.322)
DW 324 ; DOS32CREATEEVENTSEM (DOSCALLS.324)
DW 325 ; DOS32OPENEVENTSEM (DOSCALLS.325)
DW 326 ; DOS32CLOSEEVENTSEM (DOSCALLS.326)
DW 327 ; DOS32RESETEVENTSEM (DOSCALLS.327)
DW 328 ; DOS32POSTEVENTSEM (DOSCALLS.328)
DW 329 ; DOS32WAITEVENTSEM (DOSCALLS.329)
DW 330 ; DOS32QUERYEVENTSEM (DOSCALLS.330)
DW 348 ; DOS32QUERYSYSINFO (DOSCALLS.348)
NFNLIST EQU ($-FNLIST)/2 ; number of items in FNLIST
; = list_length_in_bytes / word_length
ENDIF ; EXAMPLE EQ 3
; Note that the APIs loaded in EXAMPLE EQ 3 include procedures for
; loading and freeing other modules besides DOSCALLS (which was loaded
; by FWKTL); the GETFN and GETFNLIST functions in FWKTL can be used
; with other modules than DOSCALLS, once they have been loaded and
; their handles made available.
LL0: ; target for JMP from entry point
IF KEEP_EBX ; in general use, this step is used to
PUSH EBX ; save EBX value; but every call used in this
ENDIF ; particular program preserves EBX, so this
; step is not needed.
MOV EBP,ESP ; save ESP value in EBP
REP MOVSD ; load EBX:P_ STRUC
; FWKTL preset ESI, EDI, and ECX,
; and did CLD
IF EXAMPLE EQ 1 ; get specific API: DOS32WRITE (DOSCALLS.282)
MOV EAX,282 ; 282 decimal ordinal
MOV EDX,[EBX].P_HDOSCALLS ; use handle for DOSCALLS module,
; already loaded by FWKTL
LEA EDI,[EBX].P_WRITE ; point EDI at DWORD for holding address
CALL [EBX].P_GETFN ; get procedure address
ENDIF
IF EXAMPLE EQ 3 ; this is a flexible method, using an
; expandable list of API procedure ordinals
MOV ESI,[EBX].P_LOADEDAT ; calculate position of start of FNLIST
ADD ESI,OFNLIST ; procedure list
LEA EDI,[EBX].P_WRITE ; point EDI at first location for storing
; procedure addresses
MOV EAX,02 ; FNLIST list contains 2_byte ordinals
MOV ECX,NFNLIST ; number of items in list
MOV EDX,[EBX].P_HDOSCALLS ; use handle for DOSCALLS module,
; already loaded by FWKTL
CALL [EBX].P_GETFNLIST ; get addresses for procedures in list
ENDIF
IF EXAMPLE EQ 2 ; this is a special_case, with a simple way
; to show a message on the screen
; (uses "standard error" handle=2):
MOV ESI,[EBX].P_LOADEDAT ; point ESI at start of loaded program
ADD ESI,OMSG ; add offset to point ESI at start of message
CALL [EBX].P_SHOW ; call FWKTL SHOW function
ENDIF
IF EXAMPLE EQ 1 OR EXAMPLE EQ 3 ; this illustrates a flexible method,
; using the DOS32WRITE API loaded above
; (see HELOWRLD.LST):
LEA EAX,[EBX].P_WROTE ; pDWORD for amount written
PUSHD EAX ;
PUSHD LMSG ; amount to write
MOV EAX,[EBX].P_LOADEDAT ; calculate position of message text
ADD EAX,OMSG ;
PUSHD EAX ; push address of beginning of text
PUSHD 1 ; handle = 'standard output'
CALL [EBX].P_WRITE ; indirect call to DOS32WRITE to write message
ENDIF
IF EXAMPLE EQ 3
;MOV ESP,EBP ; could clear the stack first, but there's enough room
IF KEEP_EBX
MOV EBX,[EBP] ; this is a way to restore EBX
ENDIF
PUSHD 0200H ; 512 milliseconds duration (nominal)
PUSHD 0100H ; 256 cycles per second (approx)
CALL [EBX].P_BEEP ; indirect call to DOS32BEEP API loaded above
ENDIF ; EXAMPLE EQ 3
IF EXAMPLE NE 2 ; cleanup omitted in EXAMPLE EQ 2 to save space
MOV ESP,EBP ; clean up STACK
;
IF KEEP_EBX ;
POP EBX ;
ENDIF ;
XOR EAX,EAX ; set exit errorlevel = 0 (low 16 bits are
; used in making exit errorlevel returned
; to command line in OS/2 Warp)
ENDIF ; EXAMPLE NE 2
RET ; return to FWKTL
DB 'FWKEOF',0,1 ; EOF signature for use with FWKTRIM
TEXT32 ENDS
END MAIN
; FWKTL and FWKTRIM are trademarks of Frederick W. Kantor.
;
; IBM, OS/2, Warp, and IBM Assembly Language Processor (ALP) are trademarks
; of International Business Machines Corporation.