forked from wine-mirror/wine
-
Notifications
You must be signed in to change notification settings - Fork 1
/
if1632.S
294 lines (263 loc) · 5.5 KB
/
if1632.S
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
/*
* Copyright Robert J. Amstadt, 1993
*/
.data
jump_target:
return_value:
.long 0
/**********************************************************************
* Places to keep info about the current 32-bit stack frame.
*/
saved_esp:
.long 0
saved_ebp:
.long 0
saved_ss:
.word 0
/**********************************************************************
* Places to keep info about the current 16-bit stack frame.
*/
saved_16esp:
.long 0
saved_16ebp:
.long 0
saved_16ss:
.word 0
nbytes:
.word 0
selector:
.word 0
offset:
.word 0
.text
/**********************************************************************
* int CallTo16(unsigned long csip, unsigned long sssp,
* unsigned short ds)
*
* Stack: 0 ebp
* 4 eip
* 8 target ip
* 10 target cs
* 12 target sp
* 14 target ss
* 16 target ds
*/
.align 4
.globl _CallTo16
_CallTo16:
pushl %ebp
movl %esp,%ebp
/*
* Save our registers
*/
pushal
pushl saved_esp
pushl saved_ebp
pushw saved_ss
/*
* Get target address.
*/
movl 8(%ebp),%eax
movl %eax,jump_target
lea jump_target,%edx
/*
* Put stack registers where we can get them after stack switch.
*/
movw %ss,saved_ss
movl %esp,saved_esp
movl %ebp,saved_ebp
/*
* Load ds, es, sp, ss & bp
*/
movl $0,%eax
movw _PSPSelector,%ax
movw %ax,%es
movw 16(%ebp),%ax
movw %ax,%ds
xorl %eax,%eax
movw 12(%ebp),%ax
movl %eax,%esp
movw 14(%ebp),%ax
movw %ax,%ss
movl %eax,%ebp
/*
* Call entry point
*/
.byte 0x66
lcall %fs:(%edx)
/*
* Restore old stack and segment registers.
*
* Two choices here:
* 1. Trust that fs or gs hasn't changed.
* 2. Rely on knowledge of Linux use of segments.
*
* I'll opt for choice 2 because who knows what programs we
* going to run. Linux should be fairly stable in terms of
* GDT usage.
*/
pushl %eax
movw $0x2b,%ax
movw %ax,%ds
movw %ax,%es
movw %ax,%fs
movw %ax,%gs
popl %eax
movw saved_ss,%ss
movl saved_esp,%esp
movl saved_ebp,%ebp
/*
* Restore registers, but do not destroy return value.
*/
popw saved_ss
popl saved_ebp
popl saved_esp
movl %eax,return_value
popal
movl return_value,%eax
.align 2,0x90
leave
ret
/**********************************************************************
* CallTo32()
*
* This function is called as a relay point to the built function
* handler. KERNEL, USER and GDI calls are dealt with by this
* handler. Calls to these DLLs will be mapped to a call handler
* which will set EAX to a number indicating which DLL and which
* function within that DLL.
*
* This function will pass to the function handler two arguments.
* The first argument will be the contents of EAX, the second
* argument will be a segment:offset pair that points to the
* 16-bit stack.
*/
.align 4
.globl _CallTo32
_CallTo32:
pushl %ebp
movl %esp,%ebp
/*
* Save registers. 286 mode does not have fs or gs.
*/
pushw %ds
pushw %es
/*
* Restore segment registers.
*/
pushl %eax
movw $0x2b,%ax
movw %ax,%ds
movw %ax,%es
popl %eax
/*
* Save old stack save variables, save stack registers, reload
* stack registers.
*/
pushl saved_16esp
pushl saved_16ebp
pushw saved_16ss
movw %ss,saved_16ss
movl %esp,saved_16esp
movl %ebp,saved_16ebp
movw saved_ss,%ss
movl saved_esp,%esp
movl saved_ebp,%ebp
/*
* Call entry point
*/
pushw saved_16ss
pushw saved_16esp
pushl %eax
call _DLLRelay
/*
* Restore registers, but do not destroy return value.
*/
movw saved_16ss,%ss
movl saved_16esp,%esp
movl saved_16ebp,%ebp
popw saved_16ss
popl saved_16ebp
popl saved_16esp
popw %es
popw %ds
.align 2,0x90
leave
/*
* Now we need to ditch the parameter bytes that were left on the
* stack. We do this by effectively popping the number of bytes,
* and the return address, removing the parameters and then putting
* the return address back on the stack.
* Normally this field is filled in by the relevant function in
* the emulation library, since it should know how many bytes to
* expect.
*/
popw %gs:nbytes
cmpw $0,%gs:nbytes
je noargs
popw %gs:offset
popw %gs:selector
addw %gs:nbytes,%esp
pushw %gs:selector
pushw %gs:offset
noargs:
/*
* Last, but not least we need to move the high word from eax to dx
*/
pushl %eax
popw %dx
popw %dx
.byte 0x66
lret
/**********************************************************************
* KERNEL_InitTask()
*
* This interface functions is special because it returns all
* of its values in registers. Thus we can't just fall back through
* the C functions that called us. Instead we simply abandon
* the 32-bit stack, set up the registers and return.
*/
.globl _KERNEL_InitTask
_KERNEL_InitTask:
/*
* Restore stack
*/
movw saved_16ss,%ss
movl saved_16esp,%esp
movl saved_16ebp,%ebp
popw saved_16ss
popl saved_16ebp
popl saved_16esp
popw %es
popw %ds
.align 2,0x90
leave
/*
* Now we need to ditch the parameter bytes that were left on the
* stack. We do this by effectively popping the number of bytes,
* and the return address, removing the parameters and then putting
* the return address back on the stack.
* Normally this field is filled in by the relevant function in
* the emulation library, since it should know how many bytes to
* expect.
*/
popw %gs:nbytes
cmpw $0,%gs:nbytes
je noargs_2
popw %gs:offset
popw %gs:selector
addw %gs:nbytes,%esp
pushw %gs:selector
pushw %gs:offset
noargs_2:
/*
* Last, we need to load the return values.
*/
movw $1,%ax
movw %gs:_WIN_StackSize,%cx
movw $1,%dx
movw 0x80,%bx
movl $0,%esi
movl $1,%edi
.byte 0x66
lret