-
Notifications
You must be signed in to change notification settings - Fork 2
/
msvcrt_abs.asm
341 lines (288 loc) · 9.79 KB
/
msvcrt_abs.asm
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
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
;; absolute symbols
public __except_list
public __tls_array
;; symbols not exported by the shared runtime
public __alldiv
public __allrem
public __aulldiv
public __aullrem
__except_list EQU 0
__tls_array EQU 02ch
;;/**
;; * Support for 64-bit longs.
;; *
;; * Copyright: Copyright Digital Mars 2000 - 2012.
;; * License: Distributed under the
;; * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
;; * (See accompanying file LICENSE)
;; * Authors: Walter Bright, Sean Kelly
;; * Source: $(DRUNTIMESRC src/rt/_llmath.d)
;; */
;;
;;copied from druntime module rt.llmath;
_TEXT segment para use32 public 'CODE'
assume CS:_TEXT
;;/***************************************
;; * Unsigned long divide.
;; * Input:
;; * [EDX,EAX],[ECX,EBX]
;; * Output:
;; * [EDX,EAX] = [EDX,EAX] / [ECX,EBX]
;; * [ECX,EBX] = [EDX,EAX] % [ECX,EBX]
;; */
__ULDIV__ proc
test ECX,ECX ;
jz uldiv ;
; if ECX > EDX, then quotient is 0 and remainder is [EDX,EAX]
cmp ECX,EDX ;
ja quo0 ;
test ECX,ECX ;
js Lleft ;
;/* We have n>d, and know that n/d will fit in 32 bits.
; * d will be left justified if we shift it left s bits.
; * [d1,d0] <<= s
; * [n2,n1,n0] = [n1,n0] << s
; *
; * Use one divide, by this reasoning:
; * ([n2,n1]<<32 + n0)/(d1<<32 + d0)
; * becomes:
; * ([n2,n1]<<32)/(d1<<32 + d0) + n0/(d1<<32 + d0)
; * The second divide is always 0.
; * Ignore the d0 in the first divide, which will yield a quotient
; * that might be too high by 1 (because d1 is left justified).
; * We can tell if it's too big if:
; * q*[d1,d0] > [n2,n1,n0]
; * which is:
; * q*[d1,d0] > [[q*[d1,0]+q%[d1,0],n1,n0]
; * If we subtract q*[d1,0] from both sides, we get:
; * q*d0 > [[n2,n1]%d1,n0]
; * So if it is too big by one, reduce q by one to q'=q-one.
; * Compute remainder as:
; * r = ([n1,n0] - q'*[d1,d0]) >> s
; * Again, we can subtract q*[d1,0]:
; * r = ([n1,n0] - q*[d1,0] - (q'*[d1,d0] - q*[d1,0])) >> s
; * r = ([[n2,n1]%d1,n0] + (q*[d1,0] - (q - one)*[d1,d0])) >> s
; * r = ([[n2,n1]%d1,n0] + (q*[d1,0] - [d1 *(q-one),d0*(1-q)])) >> s
; * r = ([[n2,n1]%d1,n0] + [d1 *one,d0*(one-q)])) >> s
; */
push EBP ;
push ESI ;
push EDI ;
mov ESI,EDX ;
mov EDI,EAX ;
mov EBP,ECX ;
bsr EAX,ECX ; // EAX is now 30..0
xor EAX,01Fh ; // EAX is now 1..31
mov CH,AL ;
neg EAX ;
add EAX,32 ;
mov CL,AL ;
mov EAX,EBX ;
shr EAX,CL ;
xchg CH,CL ;
shl EBP,CL ;
or EBP,EAX ;
shl EBX,CL ;
mov EDX,ESI ;
xchg CH,CL ;
shr EDX,CL ;
mov EAX,EDI ;
shr EAX,CL ;
xchg CH,CL ;
shl EDI,CL ;
shl ESI,CL ;
or EAX,ESI ;
div EBP ;
push EBP ;
mov EBP,EAX ;
mov ESI,EDX ;
mul EBX ;
cmp EDX,ESI ;
ja L1 ;
jb L2 ;
cmp EAX,EDI ;
jbe L2 ;
L1: dec EBP ;
sub EAX,EBX ;
sbb EDX,0[ESP] ;
L2:
add ESP,4 ;
sub EDI,EAX ;
sbb ESI,EDX ;
mov EAX,ESI ;
xchg CH,CL ;
shl EAX,CL ;
xchg CH,CL ;
shr EDI,CL ;
or EDI,EAX ;
shr ESI,CL ;
mov EBX,EDI ;
mov ECX,ESI ;
mov EAX,EBP ;
xor EDX,EDX ;
pop EDI ;
pop ESI ;
pop EBP ;
ret ;
uldiv: test EDX,EDX ;
jnz D3 ;
; Both high words are 0, we can use the DIV instruction
div EBX ;
mov EBX,EDX ;
mov EDX,ECX ; // EDX = ECX = 0
ret ;
even ;
D3: ; Divide [EDX,EAX] by EBX
mov ECX,EAX ;
mov EAX,EDX ;
xor EDX,EDX ;
div EBX ;
xchg ECX,EAX ;
div EBX ;
; ECX,EAX = result
; EDX = remainder
mov EBX,EDX ;
mov EDX,ECX ;
xor ECX,ECX ;
ret ;
quo0: ; Quotient is 0
; Remainder is [EDX,EAX]
mov EBX,EAX ;
mov ECX,EDX ;
xor EAX,EAX ;
xor EDX,EDX ;
ret ;
Lleft: ; The quotient is 0 or 1 and EDX >= ECX
cmp EDX,ECX ;
ja quo1 ; // [EDX,EAX] > [ECX,EBX]
; EDX == ECX
cmp EAX,EBX ;
jb quo0 ;
quo1: ; Quotient is 1
; Remainder is [EDX,EAX] - [ECX,EBX]
sub EAX,EBX ;
sbb EDX,ECX ;
mov EBX,EAX ;
mov ECX,EDX ;
mov EAX,1 ;
xor EDX,EDX ;
ret ;
__ULDIV__ endp
;;/***************************************
;; * Signed long divide.
;; * Input:
;; * [EDX,EAX],[ECX,EBX]
;; * Output:
;; * [EDX,EAX] = [EDX,EAX] / [ECX,EBX]
;; * [ECX,EBX] = [EDX,EAX] % [ECX,EBX]
;; */
;;
__LDIV__ proc
test EDX,EDX ; // [EDX,EAX] negative?
jns L10 ; // no
; neg64 EDX,EAX ; // [EDX,EAX] = -[EDX,EAX]
neg EDX ;
neg EAX ;
sbb EDX,0 ;
test ECX,ECX ; // [ECX,EBX] negative?
jns L11 ; // no
; neg64 ECX,EBX ;
neg ECX ;
neg EBX ;
sbb ECX,0 ;
call __ULDIV__ ;
; neg64 ECX,EBX ; // remainder same sign as dividend
neg ECX ;
neg EBX ;
sbb ECX,0 ;
ret ;
L11: call __ULDIV__ ;
; neg64 ECX,EBX ; // remainder same sign as dividend
neg ECX ;
neg EBX ;
sbb ECX,0 ;
; neg64 EDX,EAX ; // quotient is negative
neg EDX ;
neg EAX ;
sbb EDX,0 ;
ret ;
L10: test ECX,ECX ; // [ECX,EBX] negative?
jns L12 ; // no (all is positive)
; neg64 ECX,EBX ;
neg ECX ;
neg EBX ;
sbb ECX,0 ;
call __ULDIV__ ;
; neg64 EDX,EAX ; // quotient is negative
neg EDX ;
neg EAX ;
sbb EDX,0 ;
ret ;
L12: jmp __ULDIV__ ;
__LDIV__ endp
;; * Input
;; * [ESP+4] QWORD: dividend
;; * [ESP+12] QWORD: divisor
;; * Output
;; * [EDX,EAX] = quotient
__alldiv proc
push EBX
mov EAX,[ESP+8]
mov EDX,[ESP+12]
mov EBX,[ESP+16]
mov ECX,[ESP+20]
call __LDIV__
pop EBX
ret 16
__alldiv endp
;; * Input
;; * [ESP+4] QWORD: dividend
;; * [ESP+12] QWORD: divisor
;; * Output
;; * [EDX,EAX] = remainder
__allrem proc
push EBX
mov EAX,[ESP+8]
mov EDX,[ESP+12]
mov EBX,[ESP+16]
mov ECX,[ESP+20]
call __LDIV__
mov EAX, EBX
mov EDX, ECX
pop EBX
ret 16
__allrem endp
;; * Input
;; * [ESP+4] QWORD: dividend
;; * [ESP+12] QWORD: divisor
;; * Output
;; * [EDX,EAX] = quotient
__aulldiv proc
push EBX
mov EAX,[ESP+8]
mov EDX,[ESP+12]
mov EBX,[ESP+16]
mov ECX,[ESP+20]
call __ULDIV__
pop EBX
ret 16
__aulldiv endp
;; * Input
;; * [ESP+4] QWORD: dividend
;; * [ESP+12] QWORD: divisor
;; * Output
;; * [EDX,EAX] = remainder
__aullrem proc
push EBX
mov EAX,[ESP+8]
mov EDX,[ESP+12]
mov EBX,[ESP+16]
mov ECX,[ESP+20]
call __ULDIV__
mov EAX, EBX
mov EDX, ECX
pop EBX
ret 16
__aullrem endp
_TEXT ends
end