x86 용 어셈블러에서 부호없는 64 비트 정수를 쉽게 나눌 수있는 방법이 필요합니다. 내 번호는 두 개의 32b 레지스터에 저장됩니다. EDX : EAX 및 결과를 EDX : EAX에 다시 저장해야합니다. Factor는 32b 정수입니다. 일부 코드는 제발?어셈블러 64b division
3
A
답변
5
정확하게 질문을 해석하면 (특히 부품 번호 Factor is in 32b integer
) 64 비트 배당을 32 비트 제수로 나누고 64 비트 지수를 얻고 싶습니다.
그 해석이 정확하다면 실제로 32 비트 코드로하기 쉽습니다.
아이디어는 제수에 의해 배당의 "절반"을 나누고 나머지를 두 번째 나누기의 첫 번째 나누기에서 다시 사용한다는 아이디어입니다.
C 코드 도시 그 방법 :
#include <stdio.h>
#include <limits.h>
#define C_ASSERT(expr) extern char CAssertExtern[(expr)?1:-1]
#if UINT_MAX >= 0xFFFFFFFF
typedef unsigned int uint32;
#else
typedef unsigned long uint32;
#endif
typedef unsigned long long uint64;
typedef unsigned long ulong;
// Make sure uint32=32 bits and uint64=64 bits
C_ASSERT(sizeof(uint32) * CHAR_BIT == 32);
C_ASSERT(sizeof(uint64) * CHAR_BIT == 64);
int div64by32eq64(uint64* dividend, uint32 divisor)
{
uint32 dividendHi = (uint32)(*dividend >> 32);
uint32 dividendLo = (uint32)*dividend;
uint32 quotientHi;
uint32 quotientLo;
if (divisor == 0)
return 0;
// This can be done as one 32-bit DIV, e.g. "div ecx"
quotientHi = dividendHi/divisor;
dividendHi = dividendHi % divisor;
// This can be done as another 32-bit DIV, e.g. "div ecx"
quotientLo = (uint32)((((uint64)dividendHi << 32) + dividendLo)/divisor);
*dividend = ((uint64)quotientHi << 32) + quotientLo;
return 1;
}
int main(void)
{
static const struct
{
uint64 dividend;
uint32 divisor;
} testData[] =
{
{ 1 , 0 },
{ 0xFFFFFFFFFFFFFFFFULL, 1 },
{ 0xFFFFFFFFFFFFFFFFULL, 2 },
{ 0xFFFFFFFF00000000ULL, 0xFFFFFFFFUL },
{ 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFUL },
};
int i;
for (i = 0; i < sizeof(testData)/sizeof(testData[0]); i++)
{
uint64 dividend = testData[i].dividend;
uint32 divisor = testData[i].divisor;
printf("0x%016llX/0x%08lX = ", dividend, (ulong)divisor);
if (div64by32eq64(÷nd, divisor))
printf("0x%016llX\n", dividend);
else
printf("division by 0 error\n");
}
return 0;
}
출력 (ideone)
0x0000000000000001/0x00000000 = division by 0 error
0xFFFFFFFFFFFFFFFF/0x00000001 = 0xFFFFFFFFFFFFFFFF
0xFFFFFFFFFFFFFFFF/0x00000002 = 0x7FFFFFFFFFFFFFFF
0xFFFFFFFF00000000/0xFFFFFFFF = 0x0000000100000000
0xFFFFFFFFFFFFFFFF/0xFFFFFFFF = 0x0000000100000001
이제 0으로 나누기 확인없이 어셈블리 (NASM 구문)에 해당하는 분할 코드
:; 64-bit dividend
mov edx, 0xFFFFFFFF
mov eax, 0xFFFFFFFF
; 32-bit divisor
mov ecx, 0xFFFFFFFF
push eax
mov eax, edx
xor edx, edx
div ecx ; get high 32 bits of quotient
xchg eax, [esp] ; store them on stack, get low 32 bits of dividend
div ecx ; get low 32 bits of quotient
pop edx ; 64-bit quotient in edx:eax now
; edx:eax should now be equal 0x0000000100000001
0
0
빠른 용어 요점 : 분자/제수 = + 결과 나머지/제수
먼저 확인 약수 (이 경우 중단) 0 인 경우. 제로로
xor ebp,ebp ;ebp = bits shifted so far
test edx,(1 << 31)
jne .l2
.l1:
shld edx,eax,1
shl eax,1
inc ebp
test edx,(1 << 31)
jne .l1
.l2:
현재 결과를 설정합니다 :
xor esi,esi
xor edi,edi
는 지금을 이동하면 한 얼마나 많은 변화를 추적하면서 MSB가 설정 될 때까지
test eax,eax
jne .ok
test edx,edx
je .divisionByZero
.ok:
이동은 제수 왼쪽 원래 위치로 약수. 이때 EDX에서
.nextBit:
shld edi,esi,1
shl esi,1
cmp ecx,edx
jb .doneBit
ja .subtract
cmp ebx,eax
jb .doneBit
.subtract:
sub ecx,edx
sbb ebx,eax
or esi,1
.doneBit:
sub ebp,1
jnc .nextBit
: 결과에 약간의 분자 잔존하고 설정에서 현재 제수를 감산하는 동안 언제든지 현재 제수 전류 분자 미만 EAX는 그것이 동일한 값이고, EDI는 : ESI의 결과이며 ECX : EBX가 나머지입니다.
경고 : 위의 모든 내용은 완전히 테스트되지 않았습니다. 그것은 단지 예시/묘사 일뿐입니다.
참고 : 숫자가 서명 된 경우 먼저 분자 및 제수에서 부호 비트를 제거해야합니다. 결과에 부호 비트를 설정하고 나머지는 나중에 설정하십시오 (sign = numerator_sign XOR divisor_sign
).
관련 문제
- 1. TableRow division
- 2. atoi (어셈블러) printf (어셈블러)
- 3. 어셈블러
- 4. 파이썬에서 term division by term (division termino와 en python)
- 5. MySQL에 "all appear"(division division?) 연산이 내장되어 있습니까?
- 6. 음수 MASM division
- 7. VB에서 Modulus Division
- 8. masm division overflow
- 9. 정수형 long 및 division
- 10. 드루팔 (Drupal sections division)
- 11. Division of VB.NET
- 12. jquery show hide division
- 13. 마이크로 소프트 어셈블러 대 GNU 어셈블러 변환
- 14. Java int division confusing me
- 15. Cython float division PyExc_ZeroDivisionError 검사
- 16. ZeroDivisionError : float division in Python
- 17. haskell division 유형이 일치하지 않습니까?
- 18. 어셈블러 코드는
- 19. 어셈블러 루프와
- 20. 어셈블러 출력
- 21. 어셈블러 연습
- 22. 어셈블러 설치
- 23. aws (m1.large)의 대기 시간이 MongoDB 64b 2.x
- 24. MARIE 어셈블러 - 곱셈 방법
- 25. 액션 스크립트 3 어셈블러
- 26. NASM 어셈블러 디버거
- 27. 어셈블러 작업 시간
- 28. 어셈블러 부동 소수점 연산
- 29. 어셈블러 : 상대 점프
- 30. 어셈블러 - 일부 튜토리얼을 통해
설명을 위해 x64 명령어 사용 여부에 관계없이 사용 하시겠습니까? 즉, 데이터를 64 비트 레지스터 (예 : RAX)로 가져 와서 64 비트 나누기를 한 다음 32 비트 레지스터로 다시 분할하거나 32 비트 프로세서에서 64 비트 나누기를 에뮬레이트하려고하는지 여부입니다 ? – WeirdlyCheezy
64b reg없이 - 32b에서 64b division을 에뮬레이트하려고합니다. – Nick
그런 경우라면 거의 기본적으로 바이너리 분할을 구현하는 것처럼 들립니다. 그것은 SO 질문에 대해 조금 광범위하게 보인다. 지금까지 뭐 해봤 어? 더 구체적인 부분이 있습니까? – WeirdlyCheezy