x86 调用约定:堆栈传递的参数是否应该是只读的? [英] x86 calling convention: should arguments passed by stack be read-only?
问题描述
似乎最先进的编译器将堆栈传递的参数视为只读.请注意,在 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屋!