我正在尝试从第二版现代x86汇编语言编程中学习x64汇编语言的基础。
第2章中的第五个示例程序介绍了如何使用各种宽度参数执行简单的整数除法,并提供了一个简单的示例测试例程来展示结果。我遇到的问题是,我似乎正在返回错误的结果,并且无法一生理解为什么。
例程提供的C ++代码如下:
void UnsignedIntegerDiv(void)
{
uint8_t a = 12;
uint16_t b = 17;
uint32_t c = 71000000;
uint64_t d = 90000000000;
uint8_t e = 101;
uint16_t f = 37;
uint32_t g = 25;
uint64_t h = 5;
uint64_t quo1, rem1;
uint64_t quo2, rem2;
quo1 = (a + b + c + d) / (e + f + g + h);
rem1 = (a + b + c + d) % (e + f + g + h);
UnsignedIntegerDiv_(a, b, c, d, e, f, g, h, &quo2, &rem2);
cout << "\nResults for UnsignedIntegerDiv\n";
cout << "a = " << (unsigned)a << ", b = " << b << ", c = " << c << ' ';
cout << "d = " << d << ", e = " << (unsigned)e << ", f = " << f << ' ';
cout << "g = " << g << ", h = " << h << '\n';
cout << "quo1 = " << quo1 << ", rem1 = " << rem1 << '\n';
cout << "quo2 = " << quo2 << ", rem2 = " << rem2 << '\n';
}
并且相应的汇编例程为:
UnsignedIntegerDiv_ proc
; Calculate a + b + c + d
movzx rax,cl ;rax = zero_extend(a)
movzx rdx,dx ;rdx = zero_extend(b)
add rax,rdx ;rax = a + b
mov r8d,r8d ;r8 = zero_extend(c)
add r8,r9 ;r8 = c + d
add rax,r8 ;rax = a + b + c + d
xor rdx,rdx ;rdx:rax = a + b + c + d
; Calculate e + f + g + h
movzx r8,byte ptr [rsp+40] ;r8 = zero_extend(e)
movzx r9,word ptr [rsp+48] ;r9 = zero_extend(f)
add r8,r9 ;r8 = e + f
mov r10d,[rsp+56] ;r10 = zero_extend(g)
add r10,[rsp+64] ;r10 = g + h;
add r8,r10 ;r8 = e + f + g + h
jnz DivOK ;jump if divisor is not zero
xor eax,eax ;set error return code
jmp done
; Calculate (a + b + c + d) / (e + f + g + h)
DivOK: div r8 ;unsigned divide rdx:rax / r8
mov rcx,[rsp+72]
mov [rcx],rax ;save quotient
mov rcx,[rsp+80]
mov [rcx],rdx ;save remainder
mov eax,1 ;set success return code
Done: ret
尽管代码似乎很有意义,但是与汇编实现相比,我从例程的C ++实现获得的输出有所不同(C ++实现为quo1,rem1提供了预期的结果-quo2,rem2是不正确的) :
Results for UnsignedIntegerDiv
a = 12, b = 17, c = 71000000 d = 90000000000, e = 101, f = 37 g = 25, h = 5
quo1 = 536136904, rem1 = 157
quo2 = 0, rem2 = 90071000029
哪个让我scratch不解为什么。我的猜测是,我错失了一个错字(尽管我从GitHub图书页面的可下载代码中得到了相同的结果)导致ASM部分某处的溢出或截断。
来自社区的任何帮助将不胜感激,因为我知道我不足以独自解决此问题。
好像我一直在遭受代码盲目:)
UnsignedIntegerDiv_函数的原型的参数之一的数据类型不正确(以下定义中的h):
extern "C" int UnsignedIntegerDiv_(uint8_t a, uint16_t b, uint32_t c, uint64_t d, uint8_t e, uint16_t f, uint32_t g, uint32_t h, uint64_t* quo, uint64_t* rem);
代替
extern "C" int UnsignedIntegerDiv_(uint8_t a, uint16_t b, uint32_t c, uint64_t d, uint8_t e, uint16_t f, uint32_t g, uint64_t h, uint64_t* quo, uint64_t* rem);
感谢@Peter Cordes向我指出正确的方向。