|
|
Microsoft OS/2 SDK 12-15-1987
OS/2 SDK MASM UPDATE
Installing the Assembler
The OS/2 SDK version of the assembler does not include a SETUP
program. You install files by copying them directly from the release
disks.
Assembly Language Under OS/2
This file describes some of the differences between assembly language
under OS/2 and assembly language under DOS. It discusses new
techniques you will have to learn for protected-mode programs, and
summarizes differences in tools used for program development.
A Sample Program
----------------
The following program is an OS/2 version of the sample programs in
Chapter 1 of the Microsoft Macro Assembler Programmer's Guide:
TITLE hellos2
INCLUDELIB doscalls.lib ; <1>
.286
.MODEL small
; <2>
pushc MACRO pushed, pushed2 ;; Define bind from command line
IFDEF bind ;; if you want to bind the program
mov ax, pushed pushed2 ;; Push constant for 8088/8086
push ax
ELSE
push pushed pushed2 ;; Push constant for 80186+
ENDIF
ENDM
.STACK 800h ; <3>
.DATA
message DB "Hello, world.",13,10
lmessage EQU $ - message
bytesout DD ?
.CODE
EXTRN DosWrite:FAR, DosExit:FAR ; Declare OS/2 calls <4>
start: ; <5>
; DosWrite function used to write to screen <6>
; <7>
pushc 1 ; Push 1 as handle for standard output
push ds ; Push far address of
pushc OFFSET message ; "message"
pushc lmessage ; Push length of "message"
push ds ; Push far address of
pushc OFFSET bytesout ; "bytesout"
call DosWrite ; Make API call <8>
; AX contains error code <9>
; Variable "bytesout" contains
; number of bytes written
; DosExit function used to return to DOS
pushc 1 ; Push action 1 to end all threads
pushc 0 ; Push return code 0
call DosExit ; Exit
END start
Note the following ways in which OS/2 programs differ from comparable
DOS programs:
1. OS/2 programs must always be linked with the DOSCALLS library.
You can specify this in the source file with the INCLUDELIB
directive.
2. OS/2 programs require an 80286 (or higher) processor. This means
you safely use instructions that are available on the 80826, but
not on earlier processors, since your programs can never run on
the earlier processors anyway. However, if you wish to bind the
program so that it will work either under OS/2 or DOS, you will
probably want to use instructions recognized by all processors.
For example, a constant can be pushed directly under the 80286,
but it must be loaded into a register first under the 8086. The
sample program uses a macro to conditionally handle either case.
3. Since OS/2 uses the stack to pass arguments to DOS calls, you
may need a larger stack for OS/2 programs than for comparable
DOS programs.
4. OS/2 system calls are far external routines and must be declared
as such in the source code.
5. In DOS a data segment must be loaded into DS, but in OS/2 a
default data segment (the one declared with .DATA) is
automatically loaded into DS.
6. For compatibility with the DOS examples in the Programmer's
Guide, the DosWrite function is used to write to the screen. The
VioWrtTTY function is a simpler alternative in many cases. See
the Microsoft Operating System/2 Programmer's Reference for a
complete list of OS/2 functions and their arguments.
7. Arguments are pushed onto the stack using the Pascal calling
convention. Passed addresses are always far. The called routine
cleans up the stack, so there is no need to pop the arguments
after the call.
8. For readability, the OS/2 API (Application Program Interface)
calls are given in mixed case (DosWrite rather than DOSWRITE).
Actually the routine names are all uppercase, but you can used
mixed case because MASM converts names to uppercase. If you are
writing routines for a case-sensitive language (such as C) you
should give the names in uppercase and use the /MX or /ML
assembler option.
9. All OS/2 calls return 0 in AX if the call was successful, or an
error code in AX if it was not. If additional information needs
to be passed back to the program, it will be placed in an
address passed as an argument to the call. For example, DosWrite
returns the number of bytes written in the variable ("bytesout"
in the example) whose address was passed as the last argument.
Assembling, Linking, and Binding
--------------------------------
Assembly under OS/2 is exactly the same as under DOS. The MASM.EXE
program is bound so that it runs in either environment. For example,
use the following command line to assemble the sample program for
OS/2:
MASM hellos2;
If you want to assemble program to be bound so that it will run under
either OS/2 or DOS, use this command line:
MASM /Dbind hellos2;
This passes a message to the "pushc" macro to push constants in a
format compatible with the 8088/8086.
The linker has an additional field for a definition file under OS/2,
as described in the CodeView and Utilities manual. This field is not
used for the sample file. You must also link with DOSCALLS.LIB (which
may be located in the directory specified by the LIB environment
variable).
If DOSCALLS.LIB is specified in the source file with the INCLUDELIB
directive (as in the sample), use the following command line:
LINK hellos2;
You can also specify DOSCALLS.LIB in the command line:
LINK hellos2,,,DOSCALLS;
OS/2 applications use dynamic linking: procedure calls are not
resolved until the program is loaded into memory. When the program is
loaded, the code required by a call is extracted from a dynamic link
library and loaded with the program. All OS/2 system calls are
contained in dynamic link libraries.
The DOSCALLS.LIB library does not contain any code for OS/2 system
calls. Instead, it contains dynamic link reference records. The linker
uses these records to make the connection between the OS/2 system call
in the application and the dynamic link library containing the system
procedure.
You can write OS/2 programs that run under either OS/2 or MS-DOS 3.0
or higher by restricting the OS/2 system calls your program uses. OS/2
function calls are known collectively as the applications program
interface (API). If you restrict your program to a subset of these
functions, known as the Family API, you can write programs that run
under both OS/2 and MS-DOS 3.0 or higher. See the Microsoft Operating
System/2 Programmer's Reference for a list of the Family API
functions.
Once you have written, assembled, and linked a program using only
Family API functions, you must bind the program using the BIND utility
to produce a version that runs under either operating system. Binding
resolves references to dynamic link routines so the application runs
without the dynamic link libraries under DOS.
Because the sample program uses only Family API calls, you can bind it
using the following command:
BIND hellos2 C:\LIB\DOSCALLS.LIB
Note that BIND automatically includes the file API.LIB, so you
do not need to specify API.LIB on the command line.
To debug OS/2 programs using CodeView, use the protected-mode version,
CVP.EXE. The options for specifying debug information are the same as
in DOS. For example:
MASM /ZI hellos2;
LINK /CO hellos2;
CVP hellos2
Note that you cannot debug bound programs. However, you can debug a
protected-mode version of the program. If the program is free of
logical errors in protected mode, it should work the same when bound
and run under DOS.
Register and Memory Consideration
---------------------------------
The startup conditions for an OS/2 program are significantly different
than conditions for a comparable DOS program. Two major differences
are that OS/2 programs do not have a PSP and memory is only allocated
for the data and code required by the program.
Note these specific differences:
o Under OS/2, AX contains the segment value of the start of the
program's environment. In other words, AX:0 points to the
environment.
Under DOS, the word at 2Ch of the Program Segment Prefix (PSP) is
the segment value of the start of the environment.
o Under OS/2 any program arguments are part of the program's
environment. BX contains the starting offset. Thus AX:BX points
to the name of the executable program name. It is followed by a
null byte and then any command line arguments exactly as typed on
the command line. A null terminates the command line.
Under DOS, the command line is unrelated to the environment. It
starts at byte 81h of the PSP. The length of the command line is
in the byte at 80h in the PSP and the first two arguments are
parsed into uppercase file-name format at bytes 5Ch and 6Ch
respectively of the PSP.
o Under OS/2, DS contains the segment of the automatic data
segment. This is the segment named DGROUP, and it contains both
the stack and data. If you use simplified segment directives,
this is the .DATA segment. If you do not use simplified segment
directives, you must place one data segment in a group called
DGROUP. For example:
_DATA SEGMENT WORD PUBLIC 'DATA'
.
.
.
_DATA ENDS
DGROUP GROUP _DATA
ASSUME ds:DGROUP
Under DOS (.EXE format), DS points to the PSP. Before using a
data segment, you must initialize DS to the segment. Use of a
group (such as DGROUP) is optional. For example:
_DATA SEGMENT WORD PUBLIC 'DATA'
.
.
.
_DATA ENDS
ASSUME ds:_DATA
.
.
.
mov ax,_DATA
mov ds,ax
o Under OS/2, only the memory required by the program is allocated.
Each segment has an allocated size. Data beyond the allocated
boundary cannot be accessed. On startup, DS and SS are the same--
the automatic data segment is used both for data and stack. SP
and CX point to the end of the allocated automatic data segment.
CS:IP points to the start of the code segment.
Under DOS, programs attempt to use all of memory on startup. If a
program needs to allocate dynamic memory, it must first use a DOS
call to adjust the program's memory allocation to match the
actual memory use. This is not necessary under OS/2, since the
operating system automatically allocates only what the program
needs.
o Under OS/2, segments are actually selectors managed by the
operating system. They are not tied to actual memory addresses
and any attempt to do segment arithmetic will fail. All memory
allocation must be done through operating system calls.
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.