在Mac 0SX上使用x86汇编程序的Hello World

时间:2010-11-26 22:24:07

标签: macos linker x86 assembly

我正试图在我的Mac上深入研究一些x86汇编程序,但是在生成可执行文件时遇到了麻烦。这个问题似乎处于关联阶段。

helloWorld.s:

.data

    HelloWorldString:
    .ascii "Hello World\n"

.text

.globl _start

_start:
    # load all the arguments for write()
    movl $4, %eax
    movl $1, %ebx
    movl $HelloWorldString, %ecx
    movl $12, %edx
    # raises software interrupt to call write()
    int $0x80

    # call exit()
    movl $1, %eax
    movl $0, %ebx
    int $0x80

组装程序:

as -o helloWorld.o helloWorld.s

链接目标文件:

ld -o helloWorld helloWorld.o

此时我得到的错误是:

ld: could not find entry point "start" (perhaps missing crt1.o) for inferred architecture x86_64

关于我做错了什么/遗失的任何建议都会非常有帮助。感谢

4 个答案:

答案 0 :(得分:19)

您可能会发现使用gcc构建更容易,而不是尝试对汇编器和链接器进行微观管理,例如。

$ gcc helloWorld.s -o helloWorld

(如果你选择这条路线,你可能希望将_start更改为_main。)

顺便说一下,从一个有效的C程序开始,从中研究生成的asm是有益的。 E.g。

#include <stdio.h>

int main(void)
{
    puts("Hello world!\n");

    return 0;
}

使用gcc -Wall -O3 -m32 -fno-PIC hello.c -S -o hello.S编译时生成:

    .cstring
LC0:
    .ascii "Hello world!\12\0"
    .text
    .align 4,0x90
.globl _main
_main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $24, %esp
    movl    $LC0, (%esp)
    call    _puts
    xorl    %eax, %eax
    leave
    ret
    .subsections_via_symbols

您可能需要考虑将此作为您自己的“Hello world”或其他实验性asm程序的模板,特别是考虑到它已经构建并运行:

$ gcc -m32 hello.S -o hello
$ ./hello 
Hello world!

最后一条评论:谨防从面向Linux的asm书籍或教程中获取示例并尝试在OS X下应用它们 - 存在重要的差异!

答案 1 :(得分:4)

尝试:

ld -e _start -arch x86_64 -o HelloWorld HelloWorld.S

然后:

./HelloWorld

信息:

-e <entry point>
-arch <architecture>, You can check your architecture by uname -a 
-o <output file>

答案 2 :(得分:3)

hello.asm

.data

    HelloWorldString:
    .ascii "Hello World!\n"

.text

.globl start

start:
    ; load all the arguments for write()
    movl $0x2000004, %eax
    movl $1, %ebx
    movq HelloWorldString@GOTPCREL(%rip), %rsi
    movq $100, %rdx
    ; raises software interrupt to call write()
    syscall

    ; call exit()
    movl $0x2000001, %eax
    movl $0, %ebx
    syscall

然后运行:

$ as -arch x86_64  -o hello.o hello.asm
$ ld -o hello hello.o
$ ./hello

这是适用于Mac OS X Mach-0基于GNU的汇编程序的工作解决方案

答案 3 :(得分:1)

问题中的代码看起来像是在int $0x80 ABI和EBX,ECX,EDX中带有参数的32位Linux上使用的。

MacOS上的

x86-64代码使用syscall指令,并且与用于Linux的x86-64 System V ABI中记录的参数具有arg传递和返回值 。它与int $0x80完全不同,唯一的相似之处在于呼叫号码是通过EAX / RAX传递的。但是电话号码不同:https://sigsegv.pl/osx-bsd-syscalls/0x2000000或。

Arg与函数调用位于相同的寄存器中。 (R10代替RCX。)

另请参阅basic assembly not working on Mac (x86_64+Lion)?How to get this simple assembly to run?


我认为这是另一个答案中建议的更整洁,更直观的版本。

OS X使用start而非_start作为流程入口点。

.data
str:
  .ascii "Hello world!\n"
  len = . - str                  # length = start - end.   . = current position

.text
.globl start
start:
    movl   $0x2000004, %eax
    movl   $1, %edi
    leaq   str(%rip), %rsi  
    movq   $len, %rdx          
    syscall                       # write(1, str, len)

    movl   $0x2000001, %eax 
    movl   $0, %edi
    syscall                       # _exit(0)

通常,当寄存器暗含操作符大小的后缀时,您将忽略它。并使用xor %edi,%edi将RDI设为零。

并使用mov $len, %edx,因为您知道其大小小于4GB,因此可以像设置RAX那样将更有效的32位零扩展mov-immediate用作呼叫号码。

请注意,使用相对RIP的LEA将静态数据的地址保存到寄存器中。 MacOS上的x86-64代码不能使用32位绝对寻址,因为可执行文件将被映射的基址在2 ^ 32以上。

32位绝对地址没有重定位类型,因此您不能使用它们。 (并且您还希望相对于RIP,而不是64位绝对值,即使它也受支持。)