1

在许多示例中,当我编译 c 函数(例如排序算法 shell 排序)时,堆栈地址(我猜它被称为?) ebp-4 / -4(%ebp) / [ebp]-4 或其他,哪个,据我了解,通常用于第一个局部变量,在我的情况下不使用。

所以我想知道是否有人知道它的用途,因为它不用于任何局部变量或其他任何东西。

此外,从堆栈指针中减去 20 以为语言环境变量分配堆栈空间 - 但是一个值仍然保存到 -24(%ebp) - 当只有 -20 之前的空间时,这怎么可能?

c 函数如下所示:

void shellsort(int a[], unsigned int n) {
    unsigned int gap, i, j;
for (gap = n / 2; gap > 0; gap = gap == 2 ? 1 : 5 * gap / 11) {
        for (i = gap; i < n; i++) {
            int tmp = a[i];
            for (j = i; j >= gap && tmp < a[j - gap]; j -= gap)
                a[j] = a[j - gap];
            a[j] = tmp;
        }
    }
}

这是我使用gcc -S32 位 Ubuntu的堆栈

 12(%ebp)  = n
 8(%ebp)   = a[]
 -8(%ebp)  = tmp
 -12(%ebp) = j
 -16(%ebp) = i
 -20(%ebp) = gap
 -24(%ebp) = (gap * 4) + gap

提前致谢 :)

4

2 回答 2

1

在 x86ebp上通常用作帧指针并且esp是堆栈指针。在帧指针周围保存调用者的帧指针和返回地址。这可以解释差距。在我的程序集中实际-4(%ebp)使用了,所以也许我们正在查看不同的 ABI,但堆栈管理应该始终存在差距。

关于-20从堆栈指针中减去并仍然访问:在您的程序集中-24(%ebp)可能有一个,这将占额外的 4 个字节。pushmovl %esp, %ebp

于 2013-06-17T12:05:43.143 回答
1

你的问题有两个部分。

据我了解,第一个与 [EBP-4] 的用途有关。为此,我建议您阅读什么是汇编中的堆栈框架?.

要正确回答您问题的整个 20/24 部分,我们需要查看反汇编代码。以下是您提供的 C 代码的反汇编摘录。

.LFB0:
        .cfi_startproc
        pushl   %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset 5, -8
        movl    %esp, %ebp           /* (1) */
        .cfi_def_cfa_register 5
        pushl   %ebx                 /* (2) */
        subl    $20, %esp            /* (3) */
        movl    12(%ebp), %eax
        shrl    %eax
        movl    %eax, -20(%ebp)
        jmp     .L2
        .cfi_offset 3, -12

我在上面的反汇编输出中确定了三 (3) 个关键行。

在 (1) 处,基指针被设置为堆栈指针。根据前面链接中提供的信息,这只是设置堆栈帧的一部分。

在 (2) 处,我们将 EBX(非易失性寄存器)保存到堆栈中。这会自动更新 ESP(但不是 EBP),从其当前值中减去四。请注意,在此操作之后,EBP = ESP + 4。

在 (3) 处,我们从 ESP 中减去 20。此操作后,EBP = ESP + 24。

这就是为什么访问 [EBP-20] 是安全的。

希望这可以帮助。

于 2013-06-17T12:39:02.883 回答