我正试图在我的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
关于我做错了什么/遗失的任何建议都会非常有帮助。感谢
答案 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)
.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上使用的。
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位绝对值,即使它也受支持。)