2012-09-05 15 views
1

我知道函数参数是填充目标字的大小,但与什么?ELF如何填充“短”?

特别是在x86 Linux GNU工具链的上下文中,这些函数返回什么?

int iMysteryMeat(short x) 
{ 
    return *((int *)&x); 
} 
unsigned uMysteryMeat(unsigned short x) 
{ 
    return *((unsigned *)&x); 
} 

的问题是,是否,当手工编码在组件的功能,有必要通过掩蔽到sterilze“小”参数或“大”的上下文(andlimull)使用它们之前签署延伸他们。

我也会对这种情况是否有更多的通用或跨平台标准感兴趣。

+1

使用gcc -S然后回来告诉我们! –

+2

你的问题与ELF无关 – TJD

+0

你是对的。这与黑暗中的一枪相同。 – bug

回答

2

这取决于ABI。 ABI需要指定调用者或被调用者(以及如何)扩展小参数的选项。不幸的是,ABI的这部分通常没有详细说明,导致不同的编译器做出不同的选择。因此,为了防止用不同的遗留编译器编译的代码之间的不兼容性,大多数现代编译器(我特别知道的关于i386gcc)在谨慎的方面犯错,并且两者兼而有之。

int a(short x) { 
    return x; 
} 
int b(int x); 
int c(short x) { 
    b(x); 
} 

gcc -m32 -O3 -S tmp.c -o tmp.s 

_a: 
pushl %ebp 
movl %esp, %ebp 
movswl 8(%ebp),%eax 
leave 
ret 

_c: 
pushl %ebp 
movl %esp, %ebp 
movswl 8(%ebp),%eax 
movl %eax, 8(%ebp) 
leave 
jmp _b 

注意a不承担有关其论点的扩展规则,而是延伸它本身。同样,c确保在将其传递给b(通过尾部呼叫)之前扩展其参数。

+0

谢谢你的方法和原因。我实际上是在系统上辅导我的同学,这足以解释它。 – bug

0
int iMysteryMeat(short x) 
{ 
    return *((int *)&x); 
} 

这是C中未定义的行为,这违反了别名规则,也可能违反对齐要求。在short不要这样做。

+0

我很清楚,这是令人反感的C代码,永远不会实际使用它,但它有意暴露下面的丑陋。如果你愿意的话,我可以在程序集中为你提供特定的用例。 – bug

+0

作为未定义的行为意味着C标准给予了实现的所有自由度来解释这一点,并没有给出任何限制。 – ouah

+1

这就是我指定我使用的对象架构和编译器的原因。可移植性不在窗口中。 – bug

0

虽然基思的回答符合我的问题的精神,但是根据Alex的要求,我想我会为自己尝试一下。

有趣的是,在这种情况下,我的例子中更多的文字回答是“垃圾”。

#include <stdio.h> 

int iMysteryMeat(short x) 
{ 
    return *((int *)&x); 
} 
unsigned uMysteryMeat(unsigned short x) 
{ 
    return *((unsigned *)&x); 
} 
int main() 
{ 
    printf("iMeat: 0x%08x\n", iMysteryMeat(-23)); 
    printf("uMeat: 0x%08x\n", uMysteryMeat(-23)); 
    return 0; 
} 

gcc -m32 -S meat.c 

iMysteryMeat: 
    pushl %ebp 
    movl %esp, %ebp 
    subl $4, %esp 
    movl 8(%ebp), %eax 
    movw %ax, -4(%ebp) 
    leal -4(%ebp), %eax 
    movl (%eax), %eax 
    leave 
    ret 
uMysteryMeat: 
    pushl %ebp 
    movl %esp, %ebp 
    subl $4, %esp 
    movl 8(%ebp), %eax 
    movw %ax, -4(%ebp) 
    leal -4(%ebp), %eax 
    movl (%eax), %eax 
    leave 
    ret 

./a.out 
iMeat: 0x0804ffe9 
uMeat: 0x0043ffe9 

正如你所看到的,不仅是overrided通常的符号扩展协议(即Keith的a()比较),它实际上使X为未初始化的堆栈空间movw,使返回值垃圾的上半部分不管什么main()都给它。

所以,再次,作为ouah说,永远为此在C和汇编(或一般,真的),总是消毒您输入