【问题标题】:What is gcc doing with my stack?gcc 对我的堆栈做了什么?
【发布时间】:2011-05-07 00:30:34
【问题描述】:

编辑真正的问题在帖子的末尾 我试图理解 gcc 如何管理堆栈大小,但我有一些问题我没有找到答案。

当我在另一个函数中调用一个函数时,Gcc 会做一些奇怪的事情。它分配了额外的字节,我不明白是为了什么。

这是有史以来最简单的 C 代码:

int f(){
    int i =12;
    return 0;
}


int main(void){
    f();
    return 0;
}

然后是 gdb 产生的 f() 的 disass :

0x08048386 <+0>:     push   %ebp
0x08048387 <+1>:     mov    %esp,%ebp
0x08048389 <+3>:     sub    $0x10,%esp <- this part
0x0804838c <+6>:     movl   $0xc,-0x4(%ebp)
0x08048393 <+13>:    mov    $0x0,%eax
0x08048398 <+18>:    leave  
0x08048399 <+19>:    ret  

好吧,我不明白。 gcc 按原样制作 16 字节对齐堆栈 一个 int (so 4 bytes) gcc 在堆栈上为 i 分配 16 个字节。

但是,一旦我在 f() 中调用了一个函数,我就不明白 gcc 在做什么。 这是新的 C 代码:

int g(int i){
    i=12;
    return i;
}

int f(){
    int i =12;
    g(i);
    return 0;
}


int main(void){
    f();
    return 0;
}

然后是 f() disass :

0x08048386 <+0>:     push   %ebp
0x08048387 <+1>:     mov    %esp,%ebp
0x08048389 <+3>:     sub    $0x14,%esp <- Here is my understanding
0x0804838c <+6>:     movl   $0xc,-0x4(%ebp)
0x08048393 <+13>:    mov    -0x4(%ebp),%eax
0x08048396 <+16>:    mov    %eax,(%esp)
0x08048399 <+19>:    call   0x8048374 <g>
0x0804839e <+24>:    mov    $0x0,%eax
0x080483a3 <+29>:    leave  
0x080483a4 <+30>:    ret

然后 gcc 分配了 4 个额外的字节,而没有比 f() 更多的变化 正在调用 g()。

当我使用更多功能时,情况可能会更糟。

所以你们中的任何人都知道这些额外的字节是什么以及 gcc 是什么 堆栈分配策略?

提前谢谢你。

编辑:真正的问题

好的,抱歉我写的太快了,其实没关系 sub 0x14 %esp 我真正理解的是这段代码:

int f(){
    char i[5];
    char j[5];
    i[4]=0;
    j[4]=0;
    strcpy(i,j);
    return 0;
}


int main(void){
    f();
    return 0;
}

然后是 f() 的反驳:

0x080483a4 <+0>:     push   %ebp
0x080483a5 <+1>:     mov    %esp,%ebp
0x080483a7 <+3>:     sub    $0x28,%esp
0x080483aa <+6>:     movb   $0x0,-0x9(%ebp)
0x080483ae <+10>:    movb   $0x0,-0xe(%ebp)
0x080483b2 <+14>:    lea    -0x12(%ebp),%eax
0x080483b5 <+17>:    mov    %eax,0x4(%esp)
0x080483b9 <+21>:    lea    -0xd(%ebp),%eax
0x080483bc <+24>:    mov    %eax,(%esp)
0x080483bf <+27>:    call   0x80482d8 <strcpy@plt>
0x080483c4 <+32>:    mov    $0x0,%eax
0x080483c9 <+37>:    leave  
0x080483ca <+38>:    ret

堆栈看起来像这样:

[oldip][oldebp][Extra(8B)][Arrays(10B)][重新排列堆栈(14B)][Argument1(4B)][Argument2(4B)]

这里我们看到在保存的 ebp 和 局部变量。所以这真的是我的理解。

抱歉发得太快了,仍然感谢您的快速 回答。

【问题讨论】:

  • f 在两个代码清单中的定义完全相同。您的意思是在第一个代码中添加一些不同的代码吗?
  • 收集你丢弃的返回值?

标签: gcc assembly stack policy


【解决方案1】:
0x08048386 <+0>:     push   %ebp
0x08048387 <+1>:     mov    %esp,%ebp
0x08048389 <+3>:     sub    $0x14,%esp <- include 0x10 bytes for stack alignment and 4 byte for 1 parameter
0x0804838c <+6>:     movl   $0xc,-0x4(%ebp)
0x08048393 <+13>:    mov    -0x4(%ebp),%eax
0x08048396 <+16>:    mov    %eax,(%esp)
0x08048399 <+19>:    call   0x8048374 <g>
0x0804839e <+24>:    mov    $0x0,%eax
0x080483a3 <+29>:    leave  
0x080483a4 <+30>:    ret

如你所见,它分配了 16 个字节,包括 i 和堆栈对齐,加上 4 个字节用于一个参数,堆栈将如下所示。

00 7f 7c 13              --> return from call address
00 00 00 00              --> this one for parameter when call g(i)  --> low address
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 0C ---> i       (ignore about edian)        --> high address 

【讨论】:

    【解决方案2】:

    我认为在第一种情况下,4 个字节用于调用 g() 时所需的一个参数。在第二种情况下,调用 strcpy() 时两个参数需要两个 4 字节字。用三个参数调用一个dummy函数,看看它是否变成了12字节。

    【讨论】:

    • 我不这么认为,因为参数存储在两个数组之后,然后额外的 8 个字节在这个数组之前:[oldeip][oldebp][Dummy 8bytes][array(16bytes)][虚拟 8bytes][arguments(8bits)]
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-25
    • 2017-02-01
    • 2018-09-01
    • 1970-01-01
    • 2021-12-04
    • 1970-01-01
    • 2021-02-22
    相关资源
    最近更新 更多