在 linux 上根据 x86-64 调用约定设置本地堆栈

Posted

技术标签:

【中文标题】在 linux 上根据 x86-64 调用约定设置本地堆栈【英文标题】:Setting up local stack according to x86-64 calling convention on linux 【发布时间】:2015-02-06 07:37:11 【问题描述】:

我正在对在 64 位 linux 上运行的 gnu C 代码进行一些扩展的汇编优化。我想从汇编代码中打印调试消息,这就是我遇到以下问题的方式。我希望有人能解释在这种情况下我应该做什么。

看看这个示例函数:

    void test(int a, int b, int c, int d)


        __asm__ volatile (

        "movq $0, %%rax\n\t"
        "pushq %%rax\n\t"
        "popq %%rax\n\t"


        :
        :"m" (a)
        :"cc", "%rax"
        );


由于函数的四个参数属于 INTEGER 类,它们将通过寄存器传递,然后压入堆栈。对我来说奇怪的是 gcc 是如何做到的:

test:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    %edi, -4(%rbp)
        movl    %esi, -8(%rbp)
        movl    %edx, -12(%rbp)
        movl    %ecx, -16(%rbp)

        movq $0, %rax
        pushq %rax
        popq %rax

        popq    %rbp
        ret

传递的参数被压入堆栈,但堆栈指针没有递减。因此,当我执行pushq %rax 时,ab 的值将被覆盖。 我想知道:有没有办法让 gcc 正确设置本地堆栈?难道我根本不应该在函数调用中使用pushpop

【问题讨论】:

【参考方案1】:

x86-64 abi 在堆栈指针下提供了一个 128 字节的红色区域,编译器决定使用它。您可以使用-mno-red-zone 选项将其关闭。

【讨论】:

谢谢,这行得通。有没有办法在功能到功能的基础上强制执行此选项? 不这么认为。但是你可以把你的函数放到一个单独的文件中。另外,如果你的代码依赖于这个设置,你可能做错了什么。

以上是关于在 linux 上根据 x86-64 调用约定设置本地堆栈的主要内容,如果未能解决你的问题,请参考以下文章

为啥 x86-64 Linux 系统调用使用 6 个寄存器集?

基于x86-64 Linux-5.0.1的Socket与系统调用深度分析

x86-64 内核在设置 IDT 时崩溃

X86-64和ARM64用户栈的结构 ---进程用户栈的初始化

Linux x86-64 上物理内存中的用户空间和内核之间是不是存在显式拆分?

Oracle Database 11.2.0.4.0 已在 中标麒麟Linux x86-64 NeoKylin Linux Advanced Server 6 上通过认证