Linux下x86-64汇编中如何正确通过参数传递数据?
问题:x86-64 Linux汇编中无法正确获取命令行参数
我在x86-64 Linux汇编程序中尝试通过命令行参数获取文件名和整数,但加载参数到寄存器时得不到预期结果。以下是我的代码和相关信息:
Makefile
AS = /usr/bin/nasm LD = /usr/bin/ld ASFLAGS = -g -f elf64 LDFLAGS = -static SRCS = lab.s OBJS = $(SRCS:.s=.o) EXE = lab all: $(SRCS) $(EXE) clean: rm -rf $(EXE) $(OBJS) $(EXE): $(OBJS) $(LD) $(LDFLAGS) $(OBJS) -o $@ .s.o: $(AS) $(ASFLAGS) $< -o $@
lab.s 汇编代码
bits 64 ; Print text file global _start _start: cmp dword [rsp], 3 mov rax, [rsp] mov rdx, [rsp + 8] mov rbx, [rsp + 16] mov rsi, [rsp + 24] mov rsi, [rsi] mov eax, 1 ; write mov edi, 1 ; standart_output mov rsi, [rsp + 16] ; name xor edx, edx ; size = 0 -> find_size: cmp byte [rsi+rdx], 0 je print inc edx jmp find_size print: syscall mov edi, 1 mov eax, 60 syscall
调试信息
- 参数地址:栈中
rsp指向的参数个数为3,后续依次是程序名、文件名参数、整数参数的内存地址。 - 数值获取异常:尝试加载整数参数值时,寄存器中未能得到预期的整数值。
问题分析与解决
核心问题
- 对命令行参数结构理解错误:x86-64 Linux下,
rsp初始指向命令行参数个数(argc),后续每个8字节是参数的字符串指针,而非参数的直接数值。你用mov rsi, [rsi]试图获取整数值,实际只是取了字符串首地址指向的8字节原始数据,并非字符串转整数后的结果。 - 缺少参数合法性检查分支:代码开头
cmp dword [rsp], 3后没有处理参数个数不符的情况,会导致后续非法栈访问。 - 寄存器使用不符合规范:
rbx是Linux系统调用的保留寄存器,随意使用可能破坏程序上下文。
修复方案
- 添加参数检查逻辑:参数个数不等于3时直接退出,避免非法操作:
cmp dword [rsp], 3 jne exit_fail - 实现字符串转整数逻辑:命令行参数都是字符串形式,必须手动转换为整数(类似C语言的
atoi函数)。 - 规范寄存器使用:改用非保留寄存器存储临时数据,比如
rcx。
修复后的示例代码
bits 64 global _start _start: ; 检查参数个数是否为3 cmp dword [rsp], 3 jne exit_fail ; 提取参数指针:[rsp+16]是文件名,[rsp+24]是整数字符串 mov rdi, [rsp + 16] mov rsi, [rsp + 24] ; 打印文件名 mov eax, 1 mov rdx, 0 find_size: cmp byte [rdi + rdx], 0 je print_name inc rdx jmp find_size print_name: syscall ; 将整数字符串转换为整数,结果存在rax中 xor rax, rax atoi_loop: movzx rcx, byte [rsi] test rcx, rcx je atoi_done sub rcx, '0' imul rax, 10 add rax, rcx inc rsi jmp atoi_loop atoi_done: ; 此处可使用rax中的整数进行后续操作 ; 正常退出 mov eax, 60 xor edi, edi syscall exit_fail: mov eax, 60 mov edi, 1 syscall
关键提示
- 所有命令行参数均为ASCII字符串,必须通过字符串转整数逻辑才能得到数值类型的参数值。
- 遵守x86-64 Linux系统调用的寄存器约定:
rax存储系统调用号,rdi/rsi/rdx传递参数,rbx/rbp/r12-r15为保留寄存器,使用前需保存上下文(如需恢复)。
内容的提问来源于stack exchange,提问作者GektorPestarzt
相关产品推荐
相关产品推荐

