我正在查看主要开头的堆栈,但主要的ebp丢失了。
我声明了一个变量来检查它在堆栈中的位置,结果发现此变量和返回地址之间有零n __libc_start_main
!
系统我正在使用
I'm using fedora Linux 3.1.2-1.fc16.i686
ASLR is disabled.
Debugging with GDB.
以下是代码:
void main(){
char ret ='a';
}
注册信息:
(gdb)
eax 0x1 1
ecx 0xbffff5f4 -1073744396
edx 0xbffff584 -1073744508
ebx 0x2dbff4 2998260
esp 0xbffff554 0xbffff554
**ebp 0xbffff558 0xbffff558**
esi 0x0 0
edi 0x0 0
eip 0x804839a 0x804839a <main+6>
堆
(gdb) x/8xw $esp
0xbffff554: 0x00000000(local var) 0x00000000(missing ebp!) 0x0014d6b3(return to libc_start) 0x00000001
0xbffff564: 0xbffff5f4 0xbffff5fc 0x00131fc4 0x0000082d
我能想到的唯一一件事就是libc_start_main
的函数序言并没有因某种原因推动主要的ebp!
编辑1:
- 没有Opatmization编译(gcc -ggdb文件file.c)
主要装配(gcc版本4.6.2 20111027)
push %ebp
mov %esp,%ebp
sub $0x10,%esp
movb $0x61,-0x1(%ebp)
leave
ret
查看堆栈的局部变量的断点显示变量后跟零的相同内容然后返回libc_start
答案 0 :(得分:2)
如果你在没有优化的情况下进行编译,你几乎肯定会发现ebp
/ rbp
实际上被推入堆栈然后根据esp
/ {{1 }}。但是,它由rsp
本身完成,而不是由main
按照您的建议完成。
以下是libc
生成的汇编代码:
gcc 4.4.5
如果使用优化选项进行编译,您可能会发现main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
movq %rsp, %rbp
.cfi_offset 6, -16
.cfi_def_cfa_register 6
movb $97, -1(%rbp)
leave
ret
.cfi_endproc
的整个主体已被优化(main
):
gcc -O3
为什么不查看反汇编(例如在main:
.LFB0:
.cfi_startproc
rep
ret
.cfi_endproc
中)看看你的具体情况会发生什么?而不是猜测?
此外,即使在未经优化的情况下,您也必须实际执行函数序言,以便按照您期望的方式设置寄存器。
最后,当您看到堆栈上的数据之间存在明显差距时,您不应该感到惊讶,因为堆栈需要对齐:
gdb
答案 1 :(得分:2)
对于在编译器生成的汇编代码中使用的特定调用约定,没有要求。这就是为什么它被称为约定而不是要求: - )
在任何情况下,您都需要记住,C的'普通'x86调用约定要求函数本身处理堆栈帧的设置和拆除。换句话说,这是main
的责任,而不是启动代码(通常在你的main
之前运行的代码来设置C运行时环境,例如堆栈设置,创建argc/argv
,任何库预初始化等等。
此外,在构建当前堆栈帧之前,推送到堆栈的ebp
是之前的值ebp
。
当前堆栈帧的部分构建过程是保存当前的ebp,然后将新值加载到ebp
寄存器中,以便轻松访问传递的参数和本地。
您可以通过使用gcc -S
编译代码段来了解这一点:
main:
pushl %ebp ; Push PREVIOUS ebp.
movl %esp, %ebp ; Load ebp for variable access.
subl $16, %esp ; Allocate space on stack.
movb $97, -1(%ebp) ; Store 'a' into variable.
leave ; Tear down frame and return.
ret
前三行和后两行是彼此的镜像,即设置和拆除代码。在这种情况下,很有可能启动代码将ebp
设置为零,可能是因为它并不关心 - 除了确保argc
和{之外,它不必担心调用约定。 {1}}在那里。
答案 2 :(得分:0)
如果您正在为x86_64进行编译,则ebp
/ rbp
将被调用者保存。这意味着main()
应该在需要使用它时保存它。如果不是,则不需要被调用者或调用者保存旧的寄存器值。
如果您有兴趣,请参阅AMD64 ABI的第3.2节以获取更多信息。