【问题标题】:Create an exe file in assembly with NASM on 32-bit Windows在 32 位 Windows 上使用 NASM 在程序集中创建 exe 文件
【发布时间】:2016-09-21 07:12:39
【问题描述】:

我正在用 NASM 在 32 位 Windows 7 上用汇编语言制作一个 hello world 程序。我的代码是:

section .text 
global main ;must be declared for linker (ld) 
main: ;tells linker entry point 
    mov edx,len ;message length 
    mov ecx,msg ;message to write 
    mov ebx,1 ;file descriptor (stdout) 
    mov eax,4 ;system call number (sys_write) 
    int 0x80 ;call kernel 
    mov eax,1 ;system call number (sys_exit) 
    int 0x80 ;call kernel 

section .data 
    msg db 'Hello, world!', 0xa ;our dear string 
    len equ $ - msg ;length of our dear string

我将此程序保存为 hello.asm。接下来,我创建了 hello.o

nasm -f elf hello.asm 

现在我正在尝试使用以下命令创建 exe 文件:

ld -s -o hello hello.o 

但现在我收到此错误:

ld 不是内部或外部命令、可运行程序或批处理

为什么会出现此错误,我该如何解决?

【问题讨论】:

  • 当然,看看你正在使用的 NASM 代码会很有趣。如果您碰巧在学习 Linux 教程,请不要期望程序能够正常运行。您能否提供您正在使用的教程的链接?
  • 我已将您的代码放入您的问题中,作为对您的编辑。我怀疑你在 Windows 上使用 Linux 教程。不幸的是,Linux 不是 Windows。即使您将其链接到名为hello.exe 的可执行文件并运行它,它也会失败。 int 0x80 不适用于 Windows,它是 Linux 的 32 位系统调用。你将不得不找到一个关于用汇编程序编写 Windows 程序的教程。
  • 如果你要安装TDM-GCC(我的第一条评论中有一个链接),它安装了 GCC 和 LD(GNU 工具链的一部分),然后按照Stackoverflow answer 的第一部分您也许可以打印Hello World。该示例中的方法使用汇编代码中的 C 库函数 printf 进行打印。

标签: windows assembly linker x86 nasm


【解决方案1】:

下载并install Mingw。然后将 nasm 放入 Mingw bin 文件夹。 在名为Hellobin 文件夹中创建一个文件夹。在这个文件夹中, 使用以下代码创建一个名为 main.asm 的文件:

extern _printf
global _main

section .data
msg: db "Hello, world!",10,0

section .text
_main:
    push msg
    call _printf
    add esp,4   
    ret

从文件夹中打开终端并编译, 首先,使用 nasm 对象代码:

D:\MinGW\bin\Hello> ..\nasm -fwin32 main.asm

其次,调用gcc链接:

D:\MinGW\bin\Hello> ..\gcc main.obj -o main.exe

最后,测试一下:

D:\MinGW\bin\Hello> main.exe
Hello, world!

【讨论】:

  • 为什么要附加 0 ?对于换行 AFAIK,10 就足够了。
  • @Aritro Shome: printf 需要一个以零结尾的字符串,因此您应该包含一个明确的零值字节。
  • @ecm 但是当我们将 printf 与 C 或 C++ 一起使用时,我们没有明确包含零值字节。那么它是由编译器完成的吗?
  • @Aritro Shome:是的,它是由编译器完成的。汇编器不会自动添加它。您应该明确添加它。 (实际上,数据部分中的下一个字节可能无论如何都是零,但最好明确地包含它。)
【解决方案2】:

这是一个老问题,但我想知道为什么没有人提到标准 Windows 的解决方案link /subsystem:console /entry:_main main.obj

【讨论】:

  • 调用进程入口点main 似乎是个坏主意:通常该符号标记了由 CRT 启动代码调用的函数。我推荐_start 或其他东西,比如 Linux 默认使用的,除非你的命令行确实链接到 CRT 代码中。
  • 无论如何,是的,这是对标题问题的一个很好的回答;人们的搜索结果可能会在他们拥有可在 Windows 上运行的 asm 源代码时将他们带到这里,这与 OP 对 32 位 Linux int 0x80 ABI 的使用不同(这在 Windows 上不可用,不能通过 cygwin 甚至在Linux on Windows 子系统;它是纯 x86-64,没有 IA32 兼容 ABI。)
【解决方案3】:

OP 提供了一些他从教程中获得的代码,并用 NASM 组装了它。当他将输出链接到一个 Windows 可执行文件时,他无法让它工作。

@Michael Petch 注意到 in the comments on the question (top) 教程源代码是为 Linux 设计的 - 给出的代码永远无法在 Windows 上运行。他接着提到链接器不是由 NASM 提供的:OP 需要从 Microsoft 获得它。

【讨论】:

  • 您可以考虑this answer中提到的标准窗口link /subsystem:console /entry:_main main.obj
猜你喜欢
  • 1970-01-01
  • 2018-02-13
  • 1970-01-01
  • 1970-01-01
  • 2016-08-06
  • 2012-09-16
  • 1970-01-01
  • 2022-10-04
  • 2021-06-29
相关资源
最近更新 更多