NASM 64位汇编使用jg指令跳转触发SEGFAULT问题排查
错误原因
你的jg指令逻辑本身是对的:cmp rdi, 0时rdi=1满足大于条件,确实会跳转到greater标签。代码跑崩是三个汇编入门常见的逻辑错误,和跳转指令无关:
- 分支执行完没有流程控制,CPU直接跑飞。你把
greater标签放在了正常退出流程的后面,跳过去之后只执行了写内存的指令,既没有跳回打印/退出逻辑,也没有单独加退出指令,CPU执行完这几句就会顺着地址跑到后面的.bss数据段,把预留的数据空间当指令执行,直接触发段错误。你注释掉jg能跑,本质是程序顺序走完「写内容→打印→退出」的流程后,根本碰不到greater后面的冗余代码。 - 系统调用参数传错了。x86_64 Linux的
write调用要求rdx存要打印的字符串长度数值,你写mov rdx, msg_len传进去的是msg_len这个标签对应的内存地址,根本不是存在里面的长度值,正确写法是mov rdx, [msg_len]。另外你给msg_len只分配了1字节空间(resb 1),但rdx是8字节寄存器,往这个地址写值会越界覆盖后面的内存。 - 非跳转分支没做初始化。你原来的代码里,不满足跳转条件的分支直接调用
write,根本没给msg和msg_len赋值,打出来的只会是.bss段默认的零值,不可能是预期文本。
修正后的可运行代码
BITS 64 section .text global _start _start: mov rdi, 1 cmp rdi, 0 jg greater ; 小于等于分支:写入对应文本 mov rax, "Less!!!" mov [msg], rax mov byte [msg_len], 7 jmp print_and_exit greater: ; 大于分支:写入对应文本 mov rax, "More!!!" mov [msg], rax mov byte [msg_len], 7 print_and_exit: mov rax, 1 ; write系统调用号 mov rdi, 1 ; 标准输出文件描述符 mov rsi, msg ; 字符串首地址 mov rdx, [msg_len] ; 传入长度值,不是地址 syscall mov rax, 60 ; exit系统调用号 mov rdi, 0 syscall section .bss msg: resb 8 ; 预留8字节存7字符的字符串足够 msg_len: resb 1
容易混淆的概念点
汇编里的标签只是地址标记,不会自动分隔代码块:只要CPU的执行指针走到标签对应的地址,不管是不是跳转目标,都会顺着往后执行指令。所以写完分支逻辑后,一定要用跳转指令把流程导到公共逻辑或者退出点,绝对不能让CPU顺着地址跑到非代码段。另外要严格区分地址和地址里存的值:直接写标签名取到的是地址,加方括号[]才是访问该地址内存里存储的内容。
内容的提问来源于stack exchange,提问作者Lakshay Rohila
相关产品推荐
相关产品推荐

