调用glibc时x86-64 ELF初始堆栈布局
基本上,我通读了部分,在第29页,它显示了C程序的初始进程堆栈 我的问题是:我正在尝试从x86-64 nasm与glibc接口,根据上面显示的内容,argc应该位于rsp。因此,以下代码应打印argc:调用glibc时x86-64 ELF初始堆栈布局,c,assembly,x86-64,nasm,glibc,C,Assembly,X86 64,Nasm,Glibc,基本上,我通读了部分,在第29页,它显示了C程序的初始进程堆栈 我的问题是:我正在尝试从x86-64 nasm与glibc接口,根据上面显示的内容,argc应该位于rsp。因此,以下代码应打印argc: [SECTION .data] PrintStr: db "You just entered %d arguments.", 10, 0 [SECTION .bss] [SECTION .text] extern printf global main main: mov rax,
[SECTION .data]
PrintStr: db "You just entered %d arguments.", 10, 0
[SECTION .bss]
[SECTION .text]
extern printf
global main
main:
mov rax, 0 ; Required for functions taking in variable no. of args
mov rdi, PrintStr
mov rsi, [rsp]
call printf
ret
但事实并非如此。如果我的代码中有任何错误,有人能告诉我吗?或者告诉我实际的堆栈结构是什么
谢谢
更新:我只是随机尝试了一些偏移,并将“mov rsi,[rsp]”更改为“mov rsi,[rsp+28]”成功了
但这意味着显示的堆栈结构是错误的。有人知道x86-64 elf的初始堆栈布局是什么吗?一份相当于一份工作的报告会非常好
更新2:
我遗漏了如何构建这段代码。我通过以下方式做到这一点:
nasm -f elf64 -g <filename>
gcc <filename>.o -o <outputfile>
nasm-f elf64-g
gcc.o-o
初始堆栈布局在堆栈指针处包含argc
,后跟数组char*argv[]
,而不是像main
那样指向它的指针。因此,要调用main,您需要执行以下操作:
pop %rdi
mov %rsp,%rsi
call main
pop %rdi
pop %rdi
call puts
xor %edi,%edi
jmp exit
实际上,通常有一个包装函数调用main
,而不是启动代码直接调用它
如果只想打印argv[0]
,可以执行以下操作:
pop %rdi
mov %rsp,%rsi
call main
pop %rdi
pop %rdi
call puts
xor %edi,%edi
jmp exit
初始堆栈布局在堆栈指针处包含
argc
,后跟数组char*argv[]
,而不是像main
那样指向它的指针。因此,要调用main,您需要执行以下操作:
pop %rdi
mov %rsp,%rsi
call main
pop %rdi
pop %rdi
call puts
xor %edi,%edi
jmp exit
实际上,通常有一个包装函数调用main
,而不是启动代码直接调用它
如果只想打印argv[0]
,可以执行以下操作:
pop %rdi
mov %rsp,%rsi
call main
pop %rdi
pop %rdi
call puts
xor %edi,%edi
jmp exit
嗨,谢谢你的回复。只是澄清一下,我不是用一个main函数调用一个C程序,而是使用C库函数。我更新了问题中代码的构建方式。我尝试让另一个全局标签调用主标签,但在链接阶段失败(gcc用于链接代码)。显然,在这种情况下,main必须是一个全局标签。如果要使用libc函数,应该注意绕过libc启动代码可能会导致它们崩溃。例如,glibc可能想要初始化
%gs
线程本地存储选择器,即使没有使用线程,也要使用它进行syscenter
类型的系统调用,并在那里存储其他随机垃圾。您应该在asm中创建一个全局main
,并让libc启动代码调用它,或者完全忽略libc并在asm中执行所有系统调用。您好,我在这里绕过libc启动代码了吗?我一直在关注Jeff Duntemann的“逐步汇编语言”如何从nasm调用C代码。如果我这样做的话,你能给我举个例子说明如何不绕过libc启动代码吗?谢谢哦,我是个傻瓜。不知怎的,我以为你写了一个\u start
入口点,因为大多数人都是这样做的。如果使用了main
,那么堆栈将不包含任何有意义的内容,并且rdi
中的参数将是argc
,而rsi
中的参数将是argv
(类型为char**
)\u start
getargc
后跟堆栈上的字符串指针数组,而main
getargc
后跟argv
(指向字符串指针数组的指针),后跟指向环境变量字符串指针数组的指针(通常未使用且非标准)。您好,谢谢你的回复。只是澄清一下,我不是用一个main函数调用一个C程序,而是使用C库函数。我更新了问题中代码的构建方式。我尝试让另一个全局标签调用主标签,但在链接阶段失败(gcc用于链接代码)。显然,在这种情况下,main必须是一个全局标签。如果要使用libc函数,应该注意绕过libc启动代码可能会导致它们崩溃。例如,glibc可能想要初始化%gs
线程本地存储选择器,即使没有使用线程,也要使用它进行syscenter
类型的系统调用,并在那里存储其他随机垃圾。您应该在asm中创建一个全局main
,并让libc启动代码调用它,或者完全忽略libc并在asm中执行所有系统调用。您好,我在这里绕过libc启动代码了吗?我一直在关注Jeff Duntemann的“逐步汇编语言”如何从nasm调用C代码。如果我这样做的话,你能给我举个例子说明如何不绕过libc启动代码吗?谢谢哦,我是个傻瓜。不知怎的,我以为你写了一个\u start
入口点,因为大多数人都是这样做的。如果使用了main
,那么堆栈将不包含任何有意义的内容,并且rdi
中的参数将是argc
,而rsi
中的参数将是argv
(类型为char**
)\u start
获取堆栈上的argc
后接字符串指针数组,而main
获取argc
,后接argv
(字符串指针数组),后接指向环境变量字符串指针数组的指针(通常未使用且非标准)。