3

我在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,但我不知道如何执行这个 multiplatform。网上的小文档说用于int 0x80执行对内核的调用,但这仅适用于 Linux,不适用于 Windows,我希望我的汇编代码是多平台的。

4

5 回答 5

2

您的程序膨胀主要来自 C 运行时库。在 Windows 中,如果您编写自己的“微型”CRT,一个简单的 hello world 程序可以小于 5K。这是一个项目的链接,它解释了有关如何将 EXE 缩小到尽可能小的尺寸的所有细节:

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

于 2012-09-21T14:41:54.900 回答
1

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

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

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

于 2012-09-20T20:46:59.970 回答
0

You should be able to link dynamically to the C runtime library instead of including it statically. I don't know how to do it in Linux, but in Windows you can use msvcrt.dll.

于 2012-09-21T01:50:08.710 回答
0

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

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

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

于 2012-09-22T00:39:09.493 回答
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

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

    add     esp, 4

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

于 2012-09-23T20:52:21.457 回答