7

开始学习汇编时,我得到了一些在 Linux 课程中创建的 Hello World 汇编代码。我想让它适用于 64 位 Mac OS X。

代码.asm

SECTION .data       
    hola:   db "Hola!",10   
    tam:    equ $-hola      

SECTION .text       
    global main     

main:               

    mov edx,tam     
    mov ecx,hola        
    mov ebx,1       
    mov eax,4       
    int 0x80        

    mov ebx,0       
    mov eax,1       
    int 0x80        

这就是我所做的:

nasm -f macho32 -o object.o code.asm
gcc -m32 -o program object.o

这告诉我:

架构 i386 的未定义符号:“_main”,引用自:开始于 crt1.10.6.o ld:未找到架构 i386 的符号

搜索这个错误,我发现了这个问题:nasm and gcc: 32 bit linking failed (64 bit Mac OS X)

一个答案说

您遇到的问题是您正在创建一个与 Mac OS X 对象格式不兼容的 32 位 Linux(ELF) 对象文件。尝试将“-f elf”切换为“-f macho32”。

但我肯定在使用-f macho32. 那么那会是什么问题呢?

4

2 回答 2

8

我也一直在尝试自学一些入门级的汇编编程,我也遇到了类似的问题。我最初是使用nasmwith编译的elf,但是当我尝试使用它ld来链接目标文件并创建可执行文件时,它不起作用。

我认为您的主要问题的答案"what would the problem be then?" [to get this to run on 64bit MacOSX]是:您正在使用-f macho32但希望它在 64 位机器上运行,您需要将命令选项更改为-f macho64. 当然,这不会解决您的汇编代码是为不同的体系结构编写的事实(稍后会详细介绍)。

我在正确的命令上找到了这个方便的答案,用于在这个实例中编译和链接你的代码(在你重构你的汇编代码以使用正确的语法而不是 *nix 作为duskwuff所述):nasm -f macho64 main.asm -o main.o && ld -e _main -macosx_version_min 10.8 -arch x86_64 main.o -lSystem

经过一番搜索,这是我学到的……

  1. 在 Mac 64 位上,使用汇编程序可能会更好,as而不是nasm(如果您想要更本机的东西),但如果您想要更多可移植代码(了解差异)。
  2. nasm不附带默认安装的 macho64 输出类型
  3. 组装是一件痛苦的事情(除了这个)

现在我的学习咆哮已经结束了......

这是应该在 MacOSX 64 上运行的代码nasm(如果您已使用 更新nasm,请macho64归功于Dustin Schultz):

section .data
hello_world     db      "Hello World!", 0x0a

section .text
global start

start:
mov rax, 0x2000004      ; System call write = 4
mov rdi, 1              ; Write to standard out = 1
mov rsi, hello_world    ; The address of hello_world string
mov rdx, 14             ; The size to write
syscall                 ; Invoke the kernel
mov rax, 0x2000001      ; System call number for exit = 1
mov rdi, 0              ; Exit success = 0
syscall                 ; Invoke the kernel

as我与MacOSX64 原生的汇编程序一起使用的工作代码:

.section __TEXT,__text

.global start

start:
  movl $0x2000004, %eax           # Preparing syscall 4
  movl $1, %edi                   # stdout file descriptor = 1
  movq str@GOTPCREL(%rip), %rsi   # The string to print
  movq $100, %rdx                 # The size of the value to print
  syscall

  movl $0, %ebx
  movl $0x2000001, %eax           # exit 0
  syscall

.section __DATA,__data
str:
  .asciz "Hello World!\n"

编译命令:as -arch x86_64 -o hello_as_64.o hello_as_64.asm

链接命令:ld -o hello_as_64 hello_as_64.o

执行命令:./hello_as_64

我在旅途中发现了一些有用的资源:

ASOSX 汇编器参考https ://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/Assembler/Assembler.pdf

在 Mac OSX 上编写 64 位汇编http ://www.idryman.org/blog/2014/12/02/writing-64-bit-assembly-on-mac-os-x/

无法使用链接目标文件ld无法使用 ld 链接目标文件 - Mac OS X

OSX i386 系统调用http ://www.opensource.apple.com/source/xnu/xnu-1699.26.8/osfmk/mach/i386/syscall_sw.h

OSX 主系统调用定义http ://www.opensource.apple.com/source/xnu/xnu-1504.3.12/bsd/kern/syscalls.master

OSX 系统调用https ://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/syscall.2.html

于 2015-11-08T01:07:44.817 回答
4

您需要:

  1. 将标签名称从 更改main_main(在两个地方)。在 Mac OS X 下,符号命名的工作方式略有不同。

  2. 更改将参数传递给系统调用的方式。Mac OS X 使用与 Linux 不同的内核调用约定;此代码不可移植!我不知道它是如何工作的,因为有任何官方文档说明它是如何工作的,但是在 GDB 中查看标准库函数的反汇编_exit()可能是有启发性的。

例如,这是_exit在我的系统上:

    <_exit+0>:  mov    $0x40001,%eax
    <_exit+5>:  call   0x96f124c2 <_sysenter_trap>
    <_exit+10>: jae    0x96f10086 <_exit+26>
    <_exit+12>: call   0x96f1007d <_exit+17>
    <_exit+17>: pop    %edx
    <_exit+18>: mov    0x15a3bf9f(%edx),%edx
    <_exit+24>: jmp    *%edx
    <_exit+26>: ret
    <_exit+27>: nop

设置的额外位0x40001......很奇怪,但可以在这里安全地忽略。

调用后的_sysenter_trap内容用于错误处理。

_sysenter_trap是:

    <_sysenter_trap+0>: pop    %edx
    <_sysenter_trap+1>: mov    %esp,%ecx
    <_sysenter_trap+3>: sysenter
    <_sysenter_trap+5>: nop

考虑到所有因素,您最好链接到 libSystem(OS X 的 libc 等效项),而不是尝试直接调用内核。

于 2013-09-08T23:55:11.380 回答