IDIV指令异常排查:4除以2得到错误结果-2147483646
问题分析与解决
你遇到的这个问题根源在于两个关键错误:错误读取64位数据而非32位数组元素,以及printf格式符与参数类型不匹配,咱们一步步拆解:
1. 数组元素读取的隐藏错误
你的array定义为.int(32位有符号整数),每个元素仅占4字节,但你用mov rax, [rdi]读取数据——在x86-64的Intel语法中,这条指令默认会读取8字节(64位)内存内容。也就是说,它会把数组第一个元素4和第二个元素31一起加载到rax中,最终rax的值是0x0000001F00000004(十进制214748364804),根本不是你以为的4。
你说“除法前rax和rcx的值经打印确认是正确的”,大概率是打印时也犯了格式符不匹配的错误,导致误判了rax的实际值。
2. printf格式符的类型不匹配
idiv执行后,rax存储的是64位除法结果,但你用%d(对应32位int类型)打印,这会截断rax的低32位。前面错误的rax值除以2后得到0x0000000F80000002,低32位是0x80000002,对应十进制的-2147483646——这正是你看到的错误结果。
修正后的代码
.intel_syntax noprefix .data outfmt: .asciz "%lld\n" ; 用%lld匹配64位整数输出 array: .int 4,31,5,4 .text .global main main: enter 0,0 xor rcx, rcx inc rcx inc rcx ; rcx最终为2 lea rdi, array mov eax, [rdi] ; 读取32位数组元素,赋值eax会自动清零rax高32位,保证rax是正确的64位值4 cqto ; 将rax符号位扩展到rdx,准备有符号除法 idiv rcx ; rax = 4/2 = 2,rdx = 0 lea rdi, outfmt mov rsi, rax ; 传递64位结果给printf call printf leave ret
关键修正点说明
- 替换
mov rax, [rdi]为mov eax, [rdi]:确保只读取32位数组元素,同时赋值eax会自动清空rax的高32位,保证rax中是正确的64位扩展值。 - 格式符改为
%lld:匹配x86-64中printf的64位整数参数(对应long long类型)。
如果你想继续用%d打印32位结果,也可以在除法后把rax的值转到32位寄存器,修改这部分代码即可:
idiv rcx lea rdi, outfmt mov esi, eax ; 用eax的32位值传递给%d参数 call printf
内容的提问来源于stack exchange,提问作者monolith937
相关产品推荐
相关产品推荐

