0

我已经开始在 GCC/G++ 下开发一个小型的 16 位操作系统。我正在使用我在 Cygwin 下编译的 GCC 交叉编译器,我将 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 的偏移量,然后使用 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 来说似乎真的很愚蠢。:(如果您有建议,请留下答案。

4

2 回答 2

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”,它甚至没有记录!

于 2012-11-29T03:49:16.293 回答
3

我最近有类似的问题,我猜人们并不觉得它很重要,我至少发现了 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 进行调试。

于 2014-07-27T15:22:38.013 回答