在调用函数之前强制GCC在堆栈上推送参数(使用PUSH指令)

时间:2012-11-29 02:44:41

标签: gcc arguments push inline-assembly

我已经开始在GCC / G ++下开发一个小型的16位操作系统。 我正在使用GCC交叉编译器,我在Cygwin下编译,我将asm(“。code16gcc \ n”)作为每个.CPP文件的第一行,使用Intel ASM语法和用于编译和链接的命令行.CPP文件如下所示:

G++: i586-elf-g++ -c $(CPP_FILE) -o $(OBJECT_OUTPUT) -nostdinc -ffreestanding -nostdlib -fno-builtin -fno-rtti -fno-exceptions -fpermissive -masm=intel

LD: i586-elf-ld -T $(LD_SCRIPT) $(OBJECT_OUTPUT) -o $(BINARY_OUTPUT)

我目前面临的问题是GCC将函数调用代码转换为汇编的方式。

更具体地说,GCC不是使用PUSH指令来传递参数,而是“计算”相对于参数应该位于ESP的ESP的偏移量,然后使用MOV指令手动写入堆栈。

这对我没有好处,因为我依赖于汇编代码中的PUSH指令。为了更清楚地说明我的问题,请使用以下两个函数:

void f2(int x);

void f1(){
    int arg = 8;
    asm("mov eax, 5");
    asm("push eax");
    f2(arg);
    asm("pop eax");
}
void f2(int x){
}

在函数f1中,我使用PUSH指令保存EAX,我希望在调用f2并执行“POP EAX”指令后将其恢复为5。然而事实证明EAX变为8而不是5.那是因为汇编代码GCC生成的看起来像这样(为了清晰起见,我也包括了源代码):

void f1()
C++: {
    push ebp
    mov ebp,esp
    sub esp,byte +0x14

    C++: int arg = 8;
        mov dword [ebp-0x4],0x8

    C++: asm("mov eax, 5");
        mov eax,0x5

    C++: asm("push eax");
        push eax

    C++: f2(arg);
        mov eax,[ebp-0x4]
        mov [dword esp],eax =======>>>>>> HERE'S THE PROBLEM, WHY NOT 'PUSH EAX' ?!!
        call f2

    C++: asm("pop eax");
        pop eax

C++: }
    o32 leave
    o32 ret

void f2(int x)
C++: {
    push ebp
    mov ebp,esp
C++: }
    pop ebp
    o32 ret

我尝试过使用一些G ++编译标志,比如-mpush-args或-mno-push-args,另一个我不记得了,GCC仍然不想使用PUSH。我正在使用的版本是i586-elf-g++ (GCC) 4.7.2(在Cygwin中重新编译的交叉编译器)。

提前谢谢!

更新:这是我找到的网页:http://fixunix.com/linux/6799-gcc-function-call-pass-arguments-via-push.html

对于GCC而言,这似乎真的很愚蠢,因为它限制了内联汇编对复杂内容的可用性。 :(如果您有任何建议,请留下答案。

2 个答案:

答案 0 :(得分:4)

我很幸运找到了解决这个问题的方法,但它终于完成了我想要它做的事情。 以下是版本4.7.2的GCC手册:

-mpush-args
-mno-push-args
Use PUSH operations to store outgoing parameters. This method is shorter
and usually equally fast as method using SUB/MOV operations and is enabled
by default. In some cases disabling it may improve performance because of
improved scheduling and reduced dependencies.

-maccumulate-outgoing-args
If enabled, the maximum amount of space required for outgoing arguments will
be computed in the function prologue. This is faster on most modern CPUs
because of reduced dependencies, improved scheduling and reduced stack usage
when preferred stack boundary is not equal to 2. The drawback is a notable
increase in code size. This switch implies ‘-mno-push-args’.

我说我很幸运,因为-mpush-args无效,有效的是“-mno-accumulate-outgoing-args”,甚至没有记录!

答案 1 :(得分:1)

我最近遇到了类似的问题,人们并没有发现它很重要我猜,我发现至少对于GCC 4.8.1没有文档的选项,不知道最新的4.9版本。

有人说他得到了“警告:堆栈探测需要-maccumulate-outgoing-args正确[默认启用]”错误消息。

要禁用堆栈探测,请使用-mno-stack-arg-probe,所以传递这些选项以确保:

-mpush-args -mno-accumulate-outgoing-args -mno-stack-arg-probe

对我而言,现在它可以使用PUSH,更小更好的代码,并且使用OllyDbg更容易调试。