x86添加64位返回的A + B-C + D

问题描述:

你好,我正在努力解决大学中的一个问题。 我们正在学习x86 asm,到目前为止,我花了很多时间来正确理解代码。 我试图以签名的方式添加+ b -c + d并返回一个64位值(long long)x86添加64位返回的A + B-C + D

问题是,代码实际上起作用,我不明白它为什么会这样做。 以下变量声明main.c中作为全局

char op8 = 0; 
short op16 = 0; 
int op32a=0,op32b=0; 

int main() { 

// (op1 + op2) - op3 + op4 
op8 = 127; 
op16 = 30767; 
//op8 + op16 = 30894 
op32a = 1; 
op32b = 2147483647; 
//(op8 + op16 - op32a) =30893; 
//30893 + 2147483647 = 2146514540 
long long result = specialsum(); 

printf("%lld\n",result); 

}

.section .data 
.global op8 
.global op16 
.global op32a 
.global op32b 
.section .text 
.global specialsum 
specialsum: 
# prologue 
pushl %ebp 
movl %esp,%ebp 

# inicializar tudo a zero 
movl $0,%eax 
movl $0,%ebx 
movl $0,%ecx 
movl $0,%edx 

# carregar os valores para os registos 
mov op16,%ax 
mov op8,%bl 

# adicionar a eax o ebx 
# A + B 
add %bx,%ax 
adc $0,%eax 

# remover op32a a eax 
# (A+B) - C 
movl op32a,%ebx 
subl %ebx,%eax 

# (A+B-C) + D 
movl op32b,%ebx 
addl %ebx,%eax 


jmp fim 

fim: 

movl %ebp,%esp 
popl %ebp 

# o retorno de 64 bits é 
# EDX:EAX 
# H:L 
ret 

以下代码actualy产生右输出。 但我以为,我添加ADC $ 0,则在最后一次操作EDX%这样它会返回一个实际的64位数字

# (A+B-C) + D 
movl op32b,%ebx 
addl %ebx,%eax 
adc $0,%edx 

我不明白为什么它会产生即使我不加入合适的输出携带到edx

有人可以解释一下吗?

+0

如果我想让程序更健壮,我应该在哪里添加溢出检查? – frost

+0

哪部分你不明白? – Neo

+0

如果C是一个真正的高负数(a + b) - ( - C) 它应该溢出吗? 如何将此大数字添加到D并将其拆分为EDX:EAX – frost

您唯一的测试用例产生的结果为2146514540,这是正数但小于2^31-1,所以EDX = 0是正确的。你做零EDX(与mov而不是通常的xor %edx,%edx),所以你的固定常数上半部恰好对你测试的输入是正确的。

如果您对某些需要负面结果的测试或者大于2^31-1的正面结果进行测试,则会发现函数中存在一些错误。

其他测试用例:op16 = 0xffop8 = 1或更高,所以add %bx,%ax会产生一个进位和adc $0,%eax会产生垃圾。 当您观察寄存器值时,通过调试器单步执行代码。

提示,加载movswl op16, %eax; cltdop16标记为edx:eax