我已经开始在 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 来说似乎真的很愚蠢。:(如果您有建议,请留下答案。