我不确定我做错了什么,但我已经尝试阅读有关 GCC 调用约定的手册,但没有发现任何有用的东西。我当前的问题是 GCC 为非常简单的操作生成了过大的代码,如下所示。
主.c:
#ifdef __GNUC__
// defines for GCC
typedef void (* push1)(unsigned long);
#define PUSH1(P,A0)((push1)P)((unsigned long)A0)
#else
// defines for MSC
typedef void (__stdcall * push1)(unsigned long);
#define PUSH1(P,A0)((push1)P)((unsigned long)A0)
#endif
int main() {
// pointer to nasm-linked exit syscall "function".
// will not work for win32 target, provided as an example.
PUSH1(0x08048200,0x7F);
}
现在,让我们使用 gcc 构建并转储它:gcc -c main.c -Os;objdump -d main.o
:
main.o: file format elf32-i386
Disassembly of section .text:
00000000 <.text>:
0: 8d 4c 24 04 lea 0x4(%esp),%ecx
4: 83 e4 f0 and $0xfffffff0,%esp
7: ff 71 fc pushl -0x4(%ecx)
a: b8 00 82 04 08 mov $0x8048200,%eax
f: 55 push %ebp
10: 89 e5 mov %esp,%ebp
12: 51 push %ecx
13: 83 ec 10 sub $0x10,%esp
16: 6a 7f push $0x7f
18: ff d0 call *%eax
1a: 8b 4d fc mov -0x4(%ebp),%ecx
1d: 83 c4 0c add $0xc,%esp
20: c9 leave
21: 8d 61 fc lea -0x4(%ecx),%esp
24: c3 ret
这是我能够获得的最小大小代码...如果我不指定 -O* 或指定其他值,它将是 0x29 + 字节长。
现在,让我们使用 ms c 编译器 v 6(是的,98 年 iirc 之一)构建它:wine/mnt/ssd/msc/6/cl/c/TC main.c;wine/mnt/ssd/msc/6/dumpbin/disasm main.obj
:
Dump of file main.obj
File Type: COFF OBJECT
_main:
00000000: 55 push ebp
00000001: 8B EC mov ebp,esp
00000003: 6A 7F push 7Fh
00000005: B8 00 82 04 08 mov eax,8048200h
0000000A: FF D0 call eax
0000000C: 5D pop ebp
0000000D: C3 ret
如何让 GCC 生成类似大小的代码?任何提示,技巧?您不同意生成的代码应该这么小吗?为什么 GCC 会附加这么多无用的代码?我认为在优化大小时它会比像 msc6 这样的旧东西更聪明。我在这里缺少什么?
最佳答案
main() 在这里很特别:gcc 正在做一些额外的工作,使堆栈在程序的入口点对齐 16 字节。所以结果的大小不能直接比较...尝试将 main() 重命名为 f(),您会看到 gcc 生成截然不同的代码。
(MSVC 编译的代码不需要关心对齐,因为 Windows 有不同的堆栈对齐规则。)
关于c - GCC 4.3/4.4 与 MSC 6 在 i386 上的大小优化失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7301969/