x86 调用约定:堆栈传递的参数是否应该是只读的? [英] x86 calling convention: should arguments passed by stack be read-only?

查看:22
本文介绍了x86 调用约定:堆栈传递的参数是否应该是只读的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

似乎最先进的编译器将堆栈传递的参数视为只读.请注意,在 x86 调用约定中,调用者将参数压入堆栈,而被调用者使用堆栈中的参数.比如下面的C代码:

It seems state-of-art compilers treat arguments passed by stack as read-only. Note that in the x86 calling convention, the caller pushes arguments onto the stack and the callee uses the arguments in the stack. For example, the following C code:

extern int goo(int *x);
int foo(int x, int y) {
  goo(&x);
  return x;
}

由OS X 10.10中的clang -O3 -c g.c -S -m32编译成:

is compiled by clang -O3 -c g.c -S -m32 in OS X 10.10 into:

    .section    __TEXT,__text,regular,pure_instructions
    .macosx_version_min 10, 10
    .globl  _foo
    .align  4, 0x90
_foo:                                   ## @foo
## BB#0:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    movl    8(%ebp), %eax
    movl    %eax, -4(%ebp)
    leal    -4(%ebp), %eax
    movl    %eax, (%esp)
    calll   _goo
    movl    -4(%ebp), %eax
    addl    $8, %esp
    popl    %ebp
    retl


.subsections_via_symbols

这里首先将参数x(8(%ebp))加载到%eax中;然后存储在-4(%ebp)中;-4(%ebp)地址存放在%eax中;并且 %eax 被传递给函数 goo.

Here, the parameter x(8(%ebp)) is first loaded into %eax; and then stored in -4(%ebp); and the address -4(%ebp) is stored in %eax; and %eax is passed to the function goo.

我想知道为什么 Clang 生成的代码将存储在 8(%ebp) 中的值复制到 -4(%ebp),而不是仅仅传递地址 8(%ebp) 到函数 goo.它将节省内存操作并带来更好的性能.我在 GCC 中也观察到了类似的行为(在 OS X 下).更具体地说,我想知道为什么编译器不生成:

I wonder why Clang generates code that copy the value stored in 8(%ebp) to -4(%ebp), rather than just passing the address 8(%ebp) to the function goo. It would save memory operations and result in a better performance. I observed a similar behaviour in GCC too (under OS X). To be more specific, I wonder why compilers do not generate:

  .section  __TEXT,__text,regular,pure_instructions
    .macosx_version_min 10, 10
    .globl  _foo
    .align  4, 0x90
_foo:                                   ## @foo
## BB#0:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $8, %esp
    leal    8(%ebp), %eax
    movl    %eax, (%esp)
    calll   _goo
    movl    8(%ebp), %eax
    addl    $8, %esp
    popl    %ebp
    retl


.subsections_via_symbols

如果 x86 调用约定要求传递的参数是只读的,我会搜索文档,但我找不到任何关于此问题的信息.有人对这个问题有任何想法吗?

I searched for documents if the x86 calling convention demands the passed arguments to be read-only, but I couldn't find anything on the issue. Does anybody have any thought on this issue?

推荐答案

其实我只是用GCC编译了这个函数:

Actually, I just compiled this function using GCC:

int foo(int x)
{
    goo(&x);
    return x;
}

它生成了这段代码:

_foo:
        pushl       %ebp
        movl        %esp, %ebp
        subl        $24, %esp
        leal        8(%ebp), %eax
        movl        %eax, (%esp)
        call        _goo
        movl        8(%ebp), %eax
        leave
        ret

这是使用 GCC 4.9.2(如果重要的话,在 32 位 cygwin 上),没有优化.所以事实上,GCC 做了你认为它应该做的事情,并直接从调用者将它压入堆栈的地方使用了参数.

This is using GCC 4.9.2 (on 32-bit cygwin if it matters), no optimizations. So in fact, GCC did exactly what you thought it should do and used the argument directly from where the caller pushed it on the stack.

这篇关于x86 调用约定:堆栈传递的参数是否应该是只读的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆