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
|
;***
;lldiv.asm - signed long divide routine
;
; Copyright (c) Microsoft Corporation. All rights reserved.
; SPDX-License-Identifier: BSD-2-Clause-Patent
;
;Purpose:
; defines the signed long divide routine
; __alldiv
;
;Original Implemenation: MSVC 14.29.30133
;
;*******************************************************************************
.686
.model flat,C
.code
;***
;lldiv - signed long divide
;
;Purpose:
; Does a signed long divide of the arguments. Arguments are
; not changed.
;
;Entry:
; Arguments are passed on the stack:
; 1st pushed: divisor (QWORD)
; 2nd pushed: dividend (QWORD)
;
;Exit:
; EDX:EAX contains the quotient (dividend/divisor)
; NOTE: this routine removes the parameters from the stack.
;
;Uses:
; ECX
;
;Exceptions:
;
;*******************************************************************************
_alldiv PROC NEAR
HIWORD EQU [4] ;
LOWORD EQU [0]
push edi
push esi
push ebx
; Set up the local stack and save the index registers. When this is done
; the stack frame will look as follows (assuming that the expression a/b will
; generate a call to lldiv(a, b)):
;
; -----------------
; | |
; |---------------|
; | |
; |--divisor (b)--|
; | |
; |---------------|
; | |
; |--dividend (a)-|
; | |
; |---------------|
; | return addr** |
; |---------------|
; | EDI |
; |---------------|
; | ESI |
; |---------------|
; ESP---->| EBX |
; -----------------
;
DVND equ [esp + 16] ; stack address of dividend (a)
DVSR equ [esp + 24] ; stack address of divisor (b)
; Determine sign of the result (edi = 0 if result is positive, non-zero
; otherwise) and make operands positive.
xor edi,edi ; result sign assumed positive
mov eax,HIWORD(DVND) ; hi word of a
or eax,eax ; test to see if signed
jge short L1 ; skip rest if a is already positive
inc edi ; complement result sign flag
mov edx,LOWORD(DVND) ; lo word of a
neg eax ; make a positive
neg edx
sbb eax,0
mov HIWORD(DVND),eax ; save positive value
mov LOWORD(DVND),edx
L1:
mov eax,HIWORD(DVSR) ; hi word of b
or eax,eax ; test to see if signed
jge short L2 ; skip rest if b is already positive
inc edi ; complement the result sign flag
mov edx,LOWORD(DVSR) ; lo word of a
neg eax ; make b positive
neg edx
sbb eax,0
mov HIWORD(DVSR),eax ; save positive value
mov LOWORD(DVSR),edx
L2:
;
; Now do the divide. First look to see if the divisor is less than 4194304K.
; If so, then we can use a simple algorithm with word divides, otherwise
; things get a little more complex.
;
; NOTE - eax currently contains the high order word of DVSR
;
or eax,eax ; check to see if divisor < 4194304K
jnz short L3 ; nope, gotta do this the hard way
mov ecx,LOWORD(DVSR) ; load divisor
mov eax,HIWORD(DVND) ; load high word of dividend
xor edx,edx
div ecx ; eax <- high order bits of quotient
mov ebx,eax ; save high bits of quotient
mov eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend
div ecx ; eax <- low order bits of quotient
mov edx,ebx ; edx:eax <- quotient
jmp short L4 ; set sign, restore stack and return
;
; Here we do it the hard way. Remember, eax contains the high word of DVSR
;
L3:
mov ebx,eax ; ebx:ecx <- divisor
mov ecx,LOWORD(DVSR)
mov edx,HIWORD(DVND) ; edx:eax <- dividend
mov eax,LOWORD(DVND)
L5:
shr ebx,1 ; shift divisor right one bit
rcr ecx,1
shr edx,1 ; shift dividend right one bit
rcr eax,1
or ebx,ebx
jnz short L5 ; loop until divisor < 4194304K
div ecx ; now divide, ignore remainder
mov esi,eax ; save quotient
;
; We may be off by one, so to check, we will multiply the quotient
; by the divisor and check the result against the orignal dividend
; Note that we must also check for overflow, which can occur if the
; dividend is close to 2**64 and the quotient is off by 1.
;
mul dword ptr HIWORD(DVSR) ; QUOT * HIWORD(DVSR)
mov ecx,eax
mov eax,LOWORD(DVSR)
mul esi ; QUOT * LOWORD(DVSR)
add edx,ecx ; EDX:EAX = QUOT * DVSR
jc short L6 ; carry means Quotient is off by 1
;
; do long compare here between original dividend and the result of the
; multiply in edx:eax. If original is larger or equal, we are ok, otherwise
; subtract one (1) from the quotient.
;
cmp edx,HIWORD(DVND) ; compare hi words of result and original
ja short L6 ; if result > original, do subtract
jb short L7 ; if result < original, we are ok
cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words
jbe short L7 ; if less or equal we are ok, else subtract
L6:
dec esi ; subtract 1 from quotient
L7:
xor edx,edx ; edx:eax <- quotient
mov eax,esi
;
; Just the cleanup left to do. edx:eax contains the quotient. Set the sign
; according to the save value, cleanup the stack, and return.
;
L4:
dec edi ; check to see if result is negative
jnz short L8 ; if EDI == 0, result should be negative
neg edx ; otherwise, negate the result
neg eax
sbb edx,0
;
; Restore the saved registers and return.
;
L8:
pop ebx
pop esi
pop edi
ret 16
_alldiv ENDP
end
|