不依赖libc的x86_64汇编如何获取Linux CLI参数?
在x86_64 Linux汇编中获取命令行参数的问题
我想在x86_64 Linux汇编中打印第一个命令行参数,但无法正确获取其值。使用的编译命令为:
as -o args.o args.s -g ld -o args args.o -g
我的代码如下:
.section .text .globl _start _start: movq (%rsi), %rsi # 此处会触发段错误,原因是%rsi的值为0,尝试访问地址0会导致段错误 movq $5, %rdx movq $1, %rax movq $1, %rdi syscall # exit movq $60, %rax movq $0, %rdi syscall
这段代码存在错误。如果依赖C库在main函数中编写,类似逻辑是正确的,因为main函数的参数里%rsi存储的是argv[],但我不想依赖libc,自行实现_start入口。
我的问题是:argv存储在何处?如何获取它的地址(如果它存储在内存中)?
注:这段代码还有其他问题,比如即使正确获取argv地址,它仍会打印程序的执行路径而非实际CLI参数,或者参数长度超过5时程序会失败,但为了简化我未修正这些问题。
问题解答
在x86_64 Linux系统中,程序的_start入口点的参数通过寄存器直接传递,和main函数由libc封装后的参数传递规则不同:
%rdi存储命令行参数的数量argc%rsi存储命令行参数数组argv的起始地址%rdx存储环境变量数组envp的起始地址
你的代码触发段错误,是因为误解了_start的寄存器传参规则。另外要注意:argv[0]是程序自身的执行路径,argv[1]才是第一个用户传入的命令行参数;如果没有传入任何参数,argv[1]会是NULL,直接访问会导致错误,所以需要先检查argc是否大于1。
正确获取第一个命令行参数的步骤
- 检查
%rdi(即argc)是否大于1,若小于等于1则说明没有用户参数,直接退出。 - 从
argv数组中取出argv[1]:由于x86_64下每个指针占8字节,所以argv[1]的地址是8(%rsi)(即argv起始地址偏移8字节)。
修正后的示例代码(仅修复参数获取逻辑,保留原代码的长度限制等问题):
.section .text .globl _start _start: # 检查是否有用户传入的参数 cmpq $1, %rdi jle exit # 获取第一个命令行参数 argv[1] movq 8(%rsi), %rsi # 执行write系统调用(原代码的长度限制保留) movq $5, %rdx movq $1, %rax movq $1, %rdi syscall exit: # 退出程序 movq $60, %rax movq $0, %rdi syscall
关于argv的存储位置:argv数组存储在进程的用户栈中,内核在启动进程时会将argc、argv、envp等信息初始化到栈上,然后通过%rsi寄存器将argv的起始地址传递给_start。
内容的提问来源于stack exchange,提问作者kaidezee
相关产品推荐
相关产品推荐

