64位Ubuntu汇编HelloWorld程序段错误:非法add指令排查与修复
问题分析与解决方案
段错误原因
你在x86_64 Ubuntu系统上用int 0x80调用64位系统调用号是核心错误:int 0x80是32位Linux系统调用接口,它的系统调用号、传参规则和64位syscall接口完全不兼容:
- 32位环境下
exit的系统调用号是1,你误用了64位接口的93(实际是exit_group的调用号) - 错误的调用号会导致
exit调用无法正确终止进程,CPU从系统调用返回后,会执行程序末尾外的垃圾内存指令(也就是你看到的add %al,(%rax)),最终触发段错误。
即便调用号正确,若exit调用意外返回且后续无终止指令,也会执行到无效代码引发崩溃。
修复方案
有两种可靠的实现方式:
方式1:使用64位系统调用接口(推荐)
x86_64 Linux官方推荐用syscall指令,对应规则如下:
- 系统调用号存入
rax - 参数依次存入
rdi,rsi,rdx,r10,r8,r9 write的64位调用号是1,exit是60
示例代码:
section .data msg db 'Hello, World!', 0xA len equ $ - msg section .text global _start _start: ; write(1, msg, len) mov rax, 1 ; 64位write系统调用号 mov rdi, 1 ; stdout文件描述符 mov rsi, msg ; 字符串地址 mov rdx, len ; 字符串长度 syscall ; 触发64位系统调用 ; exit(0) mov rax, 60 ; 64位exit系统调用号 mov rdi, 0 ; 退出码0 syscall
方式2:兼容32位系统调用接口
若坚持用int 0x80,必须遵循32位规则:
- 系统调用号存入
eax - 参数依次存入
ebx,ecx,edx等 write的32位调用号是4,exit是1
示例代码:
section .data msg db 'Hello, World!', 0xA len equ $ - msg section .text global _start _start: ; write(1, msg, len) mov eax, 4 ; 32位write系统调用号 mov ebx, 1 ; stdout文件描述符 mov ecx, msg ; 字符串地址 mov edx, len ; 字符串长度 int 0x80 ; 触发32位系统调用 ; exit(0) mov eax, 1 ; 32位exit系统调用号 mov ebx, 0 ; 退出码0 int 0x80
编译链接命令保持不变:nasm -g -f elf64 hello_world.asm && ld hello_world.o,修复后运行不会再出现段错误。
生成Core Dump文件的方法
Ubuntu默认限制core dump生成,按以下步骤开启:
临时开启(当前会话有效)
执行命令解除core文件大小限制:ulimit -c unlimited之后运行程序,崩溃时会在当前目录生成
core文件。永久开启(系统全局)
编辑/etc/security/limits.conf,添加两行配置:* soft core unlimited * hard core unlimited保存后重启系统或重新登录会话即可生效。
自定义core文件命名(可选)
默认文件名是core,可以设置为带进程ID的格式方便区分:echo "/tmp/core-%e-%p-%t" > /proc/sys/kernel/core_pattern生成的文件会以
core-程序名-进程ID-时间戳的格式存放在/tmp目录。
内容的提问来源于stack exchange,提问作者CJG
相关产品推荐
相关产品推荐

