繁体   English   中英

c&gcc:堆栈增长和对齐 - 对于64位机器

[英]c & gcc : Stack growth and alignment - for a 64 bit machine

我有以下程序。 我想知道为什么它在下面的64位机器上输出-4? 我的哪些假设出了问题?

[Linux ubuntu 3.2.0-23-generic#36-Ubuntu SMP Tue Apr 10 20:39:51 UTC 2012 x86_64 x86_64 x86_64 GNU / Linux]

  1. 在上面的机器和gcc编译器中,默认情况下应该先推送b和第二个。 堆栈向下增长。 所以b应该有更高的地址和更低的地址。 所以结果应该是积极的。 但我得到了-4。 任何人都能解释一下吗?

  2. 参数是在堆栈帧中占用2个字节的两个字符。 但是我看到差异为4,正如我所期望的那样1.即使有人说这是因为对齐,那么我想知道一个有2个字符的结构没有对齐4个字节。

 #include <stdio.h> #include <stdlib.h> #include <unistd.h> void CompareAddress(char a, char b) { printf("Differs=%ld\\n", (intptr_t )&b - (intptr_t )&a); } int main() { CompareAddress('a','b'); return 0; } /* Differs= -4 */ 

这是我的猜测:

在x64上的Linux中, 调用约定规定前几个参数由寄存器传递。

所以在你的情况下, ab都是通过寄存器而不是堆栈传递的。 但是,由于你获取了它的地址,编译器会在调用函数后将它存储在堆栈的某个地方。
(没有必要按向下顺序。)

这个函数也可能是完全内联的。

在任何一种情况下,编译器都会创建临时堆栈空间来存储变量。 这些可以按任何顺序进行,并且可以进行优化。 因此,它们可能没有您所期望的任何特定顺序。

回答这些问题(关于特定平台上特定编译器的行为)的最佳方法是查看汇编程序。 您可以通过传递-S标志来获取gcc以转储其汇编程序(并且-fverbose-asm标志也很好)。 运行

gcc -S -fverbose-asm file.c

给人一种file.s ,看起来像一个小(我已经删除了所有不相关的位,并在括号中的位是我的笔记):

CompareAddress:
        # ("allocate" memory on the stack for local variables)
        subq    $16, %rsp       
        # (put a and b onto the stack)
        movl    %edi, %edx      # a, tmp62
        movl    %esi, %eax      # b, tmp63
        movb    %dl, -4(%rbp)   # tmp62, a
        movb    %al, -8(%rbp)   # tmp63, b 
        # (get their addresses)
        leaq    -8(%rbp), %rdx  #, b.0
        leaq    -4(%rbp), %rax  #, a.1
        subq    %rax, %rdx      # a.1, D.4597 (&b - &a)
        # (set up the parameters for the printf call)
        movl    $.LC0, %eax     #, D.4598
        movq    %rdx, %rsi      # D.4597,
        movq    %rax, %rdi      # D.4598,
        movl    $0, %eax        #,
        call    printf  #

main:
        # (put 'a' and 'b' into the registers for the function call)
        movl    $98, %esi       #,
        movl    $97, %edi       #,
        call    CompareAddress

这个问题很好地解释了[re]bp[re]sp是什么。)

差异是负的原因是堆栈向下增长:即如果你将两个东西推到堆栈上,那么你先推入的那个将有一个更大的地址,并且ab之前被推送。

它是-4而不是-1的原因是编译器决定将参数与4字节边界对齐是“更好”,可能是因为32位/ 64位CPU在处理4个字节时比处理单个字节更好。

(另外,查看汇编程序会显示-mpreferred-stack-boundary具有的效果:它实质上意味着堆栈上的内存以不同大小的块分配。)

我认为程序给出的答案是正确的,GCC的默认首选堆栈边界是4,你可以设置-mpreferred-stack-boundary=num到GCC选项来改变堆栈boudary,然后程序会给你不同的按照你的设定回答。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM