【问题标题】:About Variable-Size Stack Frames, about the alignment of stack frame,an example from CSAPP关于 Variable-Size Stack Frames,关于栈帧的对齐,来自 CSAPP 的一个例子
【发布时间】:2019-01-06 15:04:51
【问题描述】:

C 代码:

long vframe(long n, long idx, long *q) {
    long i;
    long *p[n];
    p[0] = &i;

    for (i = 1; i < n; i++)
        p[i] = q;

    return *p[idx];
}

部分生成的汇编代码:

long vframe(long n, long idx, long *q)

n in %rdi, idx in %rsi, q in %rdx
Only portions of code shown
vframe:
pushq   %rbp            Save old %rbp
movq    %rsp, %rbp      Set frame pointer
subq    $16, %rsp       Allocate space for i (%rsp = s1)
leaq    22(,%rdi,8), %rax
andq    $-16, %rax
subq    %rax, %rsp      Allocate space for array p (%rsp = s2)
leaq    7(%rsp), %rax
shrq    $3, %rax
leaq    0(,%rax,8), %r8     Set %r8 to &p[0]
movq    %r8, %rcx       Set %rcx to &p[0] (%rcx = p)
...
Code for initialization loop
i in %rax and on stack, n in %rdi, p in %rcx, q in %rdx
.L3:                  loop:
movq    %rdx, (%rcx,%rax,8) Set p[i] to q
addq    $1, %rax        Increment i
movq    %rax, -8(%rbp)      Store on stack
.L2:
movq    -8(%rbp), %rax      Retrieve i from stack
cmpq    %rdi, %rax      Compare i:n
jl  .L3         If <, goto loop
...
Code for function exit
leave               Restore %rbp and %rsp
ret             Return

书中作者说:

leaq 中的指令

leaq    22(,%rdi,8), %rax

计算值8n + 22,然后通过andq 中的指令向下舍入到最接近的16 倍数

andq    $-16, %rax

n 为奇数时,结果值为8n + 8,当n 为偶数时,结果值为8n + 16,并从@987654334 中减去该值@给s2

让我困惑的是8n + 22。为什么一定是22,而不是16, 17, 18, 19, 20, 21, 23

【问题讨论】:

  • 它不一定是 22,因为 and 无论如何都会砍掉低 4 位。
  • 任何大于15小于23的数字都可以?gcc刚好选择了22这个数字?
  • GCC7 确实做到了这一点godbolt.org/z/Hedvqs。您希望(n+15)&amp;-16 将大小四舍五入为 16 的倍数。请注意,ABI 要求可变长度数组以 16 字节对齐。

标签: c gcc assembly x86-64 att


【解决方案1】:

我现在在这里阅读时也遇到了这个问题。

我尝试通过clang 使用命令编译源代码:

clang -Og -S source.c -o source.s

在 ubuntu18.04 和 windows 10 平台上,

汇编文件显示:

pushq   %rbp
movq    %rsp, %rbp
subq    $16, %rsp
movq    %rsp, %r8
movq    %rsp, %r9
leaq    15(,%rdi,8), %r10
andq    $-16, %r10
movq    %r9, %rax
     ...

clang 选择 15 甚至不是从 16 到 23,

我读过The x86-64 psABI version 1.0

3.2.2 The Stack Frame部分:

输入参数区域的末尾应对齐在 16(32 或 64,如果 __m256 或 __m512 在堆栈上传递)字节边界。换句话说,价值 (%rsp + 8) 当控制权转移到 函数入口点。堆栈指针 %rsp 始终指向 最新分配的堆栈帧。

所以我认为号码是2215 并不重要,

数字只是导致e1e2 的大小

clang选择15,那么当n为偶数时,e1e2会小于gcc版本,

关键是要保护16个字节对齐堆栈帧的结尾,

或可变大小堆栈帧中s2 - s1 的值。

【讨论】:

  • 您发布的这个答案如何回答这个问题?此外,ABI 要求可变长度数组按 16 对齐;这就是(n + 15) &amp; -16 正在做的事情。
  • 重点不是16字节对齐,而是加号8n,在你的评论中,n代替。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-06
相关资源
最近更新 更多