在Mac OSX上编译NASM

时间:2011-12-09 21:31:31

标签: macos gcc compiler-construction linker 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

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

nasm -fwin32 helloworld.asm
gcc helloworld.obj
a

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

nasm -felf helloworld.asm
gcc helloworld.o
./a.out

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

nasm -f macho -o hello.o hello.asm

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

ld -e main -o hello hello.o

但是当我这样做的时候......

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

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

2 个答案:

答案 0 :(得分:3)

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

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

(BTW,使用完全免费的软件对于此类任务来说肯定更容易,因为它们的规格和源代码是可用的;使用像MacOSX这样的专有软件,你需要从软件提供商那里获得,有时它非常昂贵)

答案 1 :(得分:2)

您的示例中的程序是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

你会注意到一些不同之处:

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