如何减少汇编程序可执行文件的膨胀?

时间:2012-09-20 20:42:11

标签: optimization assembly filesize

我在GasNASMYASM中使用了多平台Hello World代码,我想将相应的可执行文件从76KB缩小到更合理的Hello World汇编程序,作为一个基本的Hello World C程序,导致80KB的可执行文件,并且汇编应该小得多。我相信大部分可执行文件都充满了来自链接器选项的垃圾。

跟踪:

LIBS=c:/strawberry/c/i686-w64-mingw32/lib/crt2.o -Lc:/strawberry/c/i686-w64-mingw32/lib -lmingw32 -lmingwex -lmsvcrt

ld ld -o $(EXECUTABLE) hello.o $(LIBS)

hello.exe
Hello World!

代码:

.data

msg: .ascii "Hello World!\0"

.text

.global _main

_main:

pushl $msg
call _puts

leave
movl $0, %eax
ret

如果我删除了LIBS中的任何选项,则链接进程失败,或者生成的可执行文件在运行时引发Windows错误。所以合乎逻辑的做法是用更简单的东西替换puts调用,比如sys_write,但是我不知道如何做这个多平台。在线的小文档说使用int 0x80来执行对内核的调用,但这仅适用于Linux,而不适用于Windows,我希望我的汇编代码是多平台的。

5 个答案:

答案 0 :(得分:2)

您的程序膨胀主要来自C运行时库。在Windows中,一个简单的hello world程序可以<如果你写自己的“小”CRT,你需要5K。以下是项目的链接,该项目解释了有关如何将EXE缩小到最小尺寸的所有详细信息:

http://www.codeproject.com/Articles/15156/Tiny-C-Runtime-Library

答案 1 :(得分:1)

对于Windows,您可以调用本机Win32 API函数(例如GetStdHandle()WriteFile())直接写入stdout。

对于类Unix系统,您可以使用文件描述符1为stdout调用write()系统调用。

具体如何执行这些操作的详细信息取决于您使用的汇编程序和操作系统。

答案 2 :(得分:0)

您应该能够动态链接到C运行时库,而不是静态地包含它。我不知道如何在Linux中执行此操作,但在Windows中,您可以使用msvcrt.dll

答案 3 :(得分:0)

汇编程序膨胀很可能来自C lib依赖项,尤其是puts。重构代码以在不使用C调用的情况下打印Hello World很可能需要特定于操作系统的汇编代码,因为Unix标准涉及调用内核的中断,并且Windows有类似于此类任务的类似VB的API。 p>

我确实找到了一个可以创建小型可执行文件的解决方案,同时仍然保持平台不可知性。通常,C预处理程序指令可以解决问题,但我不确定哪些汇编语言甚至具有预处理器语法。但是通过使用受控的,包含的汇编代码文件可以实现类似的效果。包装器代码文件的集合可以处理特定于OS的汇编代码,而包含的汇编文件则完成其余的工作。一个简单的Makefile可以运行相应的构建控制台命令来引用所需平台上的相应包装器代码。

例如,我能够快速构建以这种方式工作的FASM代码。 (虽然我还没有通知它实际上用不那么臃肿的东西绕过puts。)无论如何,这是进展。

答案 4 :(得分:0)

因为几乎所有C函数都使用CDECL调用约定,调用者调整堆栈而不是被调用者(函数)。

如果你现在不学习如何正确地做事,你会遇到麻烦,更加努力地追踪错误。

试试这个:

    push    szLF
    push    esp
    push    fmtint2
    call    printf
    add     esp, 4 * 3

    push msg
    call puts 

    push    szLF
    push    esp
    push    fmtint2
    call    printf
    add     esp, 4 * 3

运行它并注意调用puts之前和之后的数字。他们不同吗?嗯,他们应该是一样的。现在添加:

    add     esp, 4

在你打电话再次运行之后..现在的数字是一样的吗?这意味着你有一个平衡的堆栈指针,该函数使用CDECL调用约定。