在 Mac OSX 上编译 NASM

sav*_*ger 5 compiler-construction macos linker gcc nasm

在学校写一个编译器,最后一个里程碑是生成汇编代码。尝试学习 NASM。从一开始,http://www.cs.lmu.edu/~ray/notes/nasmexamples/,试图编译一个Hello World。

; ----------------------------------------------------------------------------
; helloworld.asm
;
; This is a Win32 console program that writes "Hello, World" on one line and
; then exits.  It needs to be linked with a C library.
; ----------------------------------------------------------------------------

    global  _main
    extern  _printf

    section .text
_main:
    push    message
    call    _printf
    add     esp, 4
    ret
message:
    db      'Hello, World', 10, 0
Run Code Online (Sandbox Code Playgroud)

要在 Windows 下组装、链接和运行此程序:

nasm -fwin32 helloworld.asm
gcc helloworld.obj
a
Run Code Online (Sandbox Code Playgroud)

在 Linux 下,您需要从函数名称中删除前导下划线,然后执行

nasm -felf helloworld.asm
gcc helloworld.o
./a.out
Run Code Online (Sandbox Code Playgroud)

但我在 OSX 上。找到了这个小资源:http : //salahuddin66.blogspot.com/2009/08/nasm-in-mac-os-x.html。在 Mac OS X 中,我们应该使用格式 macho...

nasm -f macho -o hello.o hello.asm
Run Code Online (Sandbox Code Playgroud)

...对于链接器(我们需要指定入口点)...

ld -e main -o hello hello.o
Run Code Online (Sandbox Code Playgroud)

但是当我这样做时...

Undefined symbols:
    "printf", referenced from:
        _main in hello.o
ld: symbol(s) not found for inferred architecture i386
Run Code Online (Sandbox Code Playgroud)

抱歉,我知道要读很多书。我怀疑这些部分周围有很多 NASM 编码器,但值得一试,对吗?我很感激我能得到的任何帮助。

Ray*_*oal 7

您的示例中的程序是 32 位 Windows 程序。如今,编写 64 位程序可能会更好。

要将其转换为 64 位 macOS 程序,您应该确保您拥有最新版本的 nasm,并安装了 gcc。

该程序现在应如下所示:

; ----------------------------------------------------------------------------------------
; This is an macOS console program that writes "Hola, mundo" on one line and then exits.
; It uses puts from the C library.  To assemble and run:
;
;     nasm -fmacho64 hola.asm && gcc hola.o && ./a.out
; ----------------------------------------------------------------------------------------

          global    _main
          extern    _puts

          section   .text
_main:    push      rbx                     ; Call stack must be aligned
          lea       rdi, [rel message]      ; First argument is address of message
          call      _puts                   ; puts(message)
          pop       rbx                     ; Fix up stack before returning
          ret

          section   .data
message:  db        "Hola, mundo", 0        ; C strings need a zero byte at the end
Run Code Online (Sandbox Code Playgroud)

您会注意到一些差异:

  • 在64位域中,第一个参数在RDI中,而不是在堆栈中
  • 在调用之前,堆栈必须在 16 字节边界上对齐。当进入 main 时,操作系统已将 main 的(8 字节)返回地址放入堆栈中,因此rbx在调用之前压入puts可以使堆栈重新对齐。
  • 此外,macOS 上的 nasm 需要rel.


Bas*_*tch 3

函数printf是在某些 C 库中定义的(在 Linux 上,将在例如/lib/libc.so.6或中/lib/x86_64-linux-gnu/libc.so.6),因此您需要链接到该库(我不知道它在 MacOSX 上是什么)

您可以直接进行系统调用,即系统调用(我不知道 MacOSX 的详细信息,也不知道它们是否公开)。在 Linux 上,Linux Assembly Howto提供了详细信息。您需要找到适用于您的操作系统的等效详细信息。

(顺便说一句,使用完全免费的软件对于此类任务来说肯定更容易,因为它们的规范和源代码是可用的;对于像 MacOSX 这样的专有软件,您需要从软件提供商处获取,有时它非常昂贵)