2244 |
mateusz.vi |
1 |
; WMINICRT - minimal runtime for (Open) Watcom C to generate DOS .COM files
|
|
|
2 |
;
|
|
|
3 |
; The default behaviour of the runtime is:
|
|
|
4 |
; - sets up a stack of 400H bytes
|
|
|
5 |
; - releases additional memory beyond stack to DOS
|
|
|
6 |
; - panics on initialization, if not enough memory for stack size
|
|
|
7 |
; - panics if running out of stack during execution
|
|
|
8 |
;
|
|
|
9 |
; WASM definitions:
|
|
|
10 |
; STACKSIZE=<value> define stack size other than 400h
|
|
|
11 |
; NOSTACKCHECK do not assemble __STK function
|
|
|
12 |
; STACKSTAT remember the minimum SP, maintained by __STK__
|
|
|
13 |
; and exported via _stack_low_.
|
|
|
14 |
;
|
|
|
15 |
; To build an executable without build- and linker scripts run:
|
|
|
16 |
; wasm startup.asm
|
|
|
17 |
; wcc -0 -bt=dos -ms -os -zl your_c_file.c
|
|
|
18 |
; wlink system dos com file startup,your_c_file
|
|
|
19 |
; To change the stack size, add -DSTACKSIZE=<value> to the wasm call
|
|
|
20 |
;
|
|
|
21 |
; To compile without stack checking:
|
|
|
22 |
; a) compile this startup file with wasm -DNOSTACKCHECK startup.asm
|
|
|
23 |
; b) call the C compiler with -s flag
|
|
|
24 |
;
|
|
|
25 |
; To build a debug version of your program:
|
|
|
26 |
; wasm -d1 startup.asm
|
|
|
27 |
; wcc -bt=dos -ms -d2 -zl your_c_file.c
|
|
|
28 |
; wlink system dos com debug all option map file startup,your_c_file
|
|
|
29 |
;
|
|
|
30 |
; TODO:
|
|
|
31 |
; - display stack statistics on program termination if STACKSTAT is enabled
|
|
|
32 |
; - proper Makefiles
|
|
|
33 |
; - many more (optional) things while keeping it small :-)
|
|
|
34 |
|
|
|
35 |
.8086
|
|
|
36 |
|
|
|
37 |
IFNDEF STACKSIZE
|
|
|
38 |
STACKSIZE = 400h
|
|
|
39 |
ENDIF
|
|
|
40 |
|
|
|
41 |
DGROUP group _TEXT,_DATA,CONST,CONST2,_BSS,_STACK
|
|
|
42 |
|
|
|
43 |
extrn "C",main : near
|
|
|
44 |
|
|
|
45 |
public _cstart_, _small_code_
|
|
|
46 |
|
|
|
47 |
_TEXT segment word public 'CODE'
|
|
|
48 |
org 100h
|
|
|
49 |
|
|
|
50 |
_small_code_ label near
|
|
|
51 |
|
|
|
52 |
_cstart_ proc
|
|
|
53 |
; DOS puts the COM program in the largest memory block it can find
|
|
|
54 |
; and sets SP to the end of this block. On top of that, it reserves
|
|
|
55 |
; the entire memory (not only the process' block) to the program, which
|
|
|
56 |
; makes it impossible to allocate memory or run child processes.
|
|
|
57 |
; for this reasons it is beneficial to resize the memory block we occupy
|
|
|
58 |
; into a more reasonable value
|
|
|
59 |
|
|
|
60 |
@verify_stack_size:
|
|
|
61 |
cmp sp,offset DGROUP:_stack_end_
|
|
|
62 |
ja @resize_mem
|
|
|
63 |
mov dx,offset @memerr
|
|
|
64 |
jmp _panic_
|
|
|
65 |
@memerr db 'MEMERR$'
|
|
|
66 |
|
|
|
67 |
; step 2: resize our memory block to sp bytes (ie. sp/16 paragraphs)
|
|
|
68 |
@resize_mem:
|
|
|
69 |
mov sp,offset DGROUP:_stack_end_
|
|
|
70 |
IFDEF STACKSTAT
|
|
|
71 |
mov [_stack_low_],sp
|
|
|
72 |
ENDIF STACKSTAT
|
|
|
73 |
mov ah,4ah
|
|
|
74 |
mov bx,sp
|
|
|
75 |
add bx,0fh
|
|
|
76 |
shr bx,1
|
|
|
77 |
shr bx,1
|
|
|
78 |
shr bx,1
|
|
|
79 |
shr bx,1
|
|
|
80 |
int 21h
|
|
|
81 |
|
|
|
82 |
; clear _BSS to be ANSI C conformant
|
|
|
83 |
mov di,offset DGROUP:_BSS
|
|
|
84 |
mov cx,offset DGROUP:_STACK
|
|
|
85 |
sub cx,di
|
|
|
86 |
shr cx,1
|
|
|
87 |
xor ax,ax
|
|
|
88 |
cld
|
|
|
89 |
rep stosw
|
|
|
90 |
|
|
|
91 |
call main
|
|
|
92 |
mov ah,4ch
|
|
|
93 |
int 21h
|
|
|
94 |
_cstart_ endp
|
|
|
95 |
|
|
|
96 |
_panic_ proc
|
|
|
97 |
; output error message in DX, then terminate with FF
|
|
|
98 |
mov ah,9
|
|
|
99 |
int 21h
|
|
|
100 |
mov ax,4cffh ; terminate if not enough stack space
|
|
|
101 |
int 21h
|
|
|
102 |
_panic_ endp
|
|
|
103 |
|
|
|
104 |
IFNDEF NOSTACKCHECK
|
|
|
105 |
|
|
|
106 |
public __STK
|
|
|
107 |
__STK proc
|
|
|
108 |
; ensures that we have enough stack space left. the needed bytes are
|
|
|
109 |
; given in AX. panics if stack low.
|
|
|
110 |
sub ax,sp ; subtract needed bytes from SP
|
|
|
111 |
neg ax ; SP-AX = -(AX-SP)
|
|
|
112 |
cmp ax,offset DGROUP:_STACK - 2 ; -2 is to compensate for __STK ret addr
|
|
|
113 |
jae @l1 ; enough stack => return, else panic
|
|
|
114 |
int 3 ; trap into debugger
|
|
|
115 |
mov dx,offset @stkerr
|
|
|
116 |
add sp,200h ; make sure we have enough stack to call DOS
|
|
|
117 |
jmp _panic_
|
|
|
118 |
@stkerr db 'STKERR$'
|
|
|
119 |
@l1:
|
|
|
120 |
IFDEF STACKSTAT ; update lowest stack pointer if statistics enabled
|
|
|
121 |
cmp [_stack_low_],ax
|
|
|
122 |
jbe @r
|
|
|
123 |
mov [_stack_low_],ax
|
|
|
124 |
ENDIF STACKSTAT
|
|
|
125 |
@r:
|
|
|
126 |
ret
|
|
|
127 |
__STK endp
|
|
|
128 |
|
|
|
129 |
ENDIF
|
|
|
130 |
|
|
|
131 |
_DATA segment word public 'DATA'
|
|
|
132 |
_DATA ends
|
|
|
133 |
|
|
|
134 |
CONST segment word public 'DATA'
|
|
|
135 |
CONST ends
|
|
|
136 |
|
|
|
137 |
CONST2 segment word public 'DATA'
|
|
|
138 |
CONST2 ends
|
|
|
139 |
|
|
|
140 |
_BSS segment word public 'BSS'
|
|
|
141 |
IFDEF STACKSTAT
|
|
|
142 |
public _stack_low_
|
|
|
143 |
_stack_low_: dw 1 dup(?)
|
|
|
144 |
ENDIF STACKSTAT
|
|
|
145 |
_BSS ends
|
|
|
146 |
|
|
|
147 |
; stack definition, available memory is checked at runtime
|
|
|
148 |
; defined as segment so that linker may detect .COM size overflow
|
|
|
149 |
_STACK segment para public 'TINY_STACK'
|
|
|
150 |
public _stack_end_
|
|
|
151 |
db STACKSIZE dup(?)
|
|
|
152 |
_stack_end_:
|
|
|
153 |
_STACK ends
|
|
|
154 |
|
|
|
155 |
_TEXT ends
|
|
|
156 |
|
|
|
157 |
end _cstart_
|