64位NASM汇编逻辑异常:rax非零时jz跳转仍触发问题求助
问题根源
你遇到的问题是64位汇编和32位汇编规则混用导致的,核心有两个错误点:
- 指令解码异常
你声明了BITS 64生成64位指令,但大概率汇编的时候生成的是32位目标文件。cmp rax, 0是64位特有指令,在32位模式下会被错误解码为无效指令或者其他逻辑,导致ZF标志位判断错误。而cmp eax, 0的指令编码在32位和64位模式下完全一致,所以修改后判断逻辑正常。 - 系统调用接口混用
int 0x80是32位Linux的标准系统调用接口,在64位环境下仅兼容处理32位参数:
- 你用
mov ecx, str_3传递字符串地址,相当于把64位地址截断为32位,大概率会触发无效地址错误,write系统调用会返回负数错误码写入rax寄存器 - 你最后退出逻辑用了64位
syscall指令,但是赋值rax=1,而64位下exit的系统调用号为60,1对应write系统调用,会导致程序退出逻辑异常
修复方案
你可以选择任意一种规则统一的方案:
方案1:完全使用32位汇编
- 删除代码开头的
BITS 64声明 - 所有系统调用都用
int 0x80实现,最后的退出逻辑也保持mov rax,1+int 0x80即可 - 汇编时指定32位格式:
nasm -f elf32 你的文件名.asm,链接时也指定32位:ld -m elf_i386 你的文件名.o -o 输出文件名
方案2:完全使用64位汇编
- 替换所有
int 0x80调用为syscall,系统调用号对应为:write=1,exit=60 - 64位
syscall参数寄存器规则为:第1参数存rdi,第2存rsi,第3存rdx - 示例64位write调用写法:
; write(1, str_3, 15) mov rax, 1 mov rdi, 1 mov rsi, str_3 mov rdx, 15 syscall
- 最后的exit调用写法:
mov rax, 60 mov rdi, 0 syscall
- 汇编时指定64位格式:
nasm -f elf64 你的文件名.asm,链接时用默认64位规则即可
内容的提问来源于stack exchange,提问作者Dyn Pallomah
相关产品推荐
相关产品推荐

