汇编Linux系统调用与汇编OS x系统调用

我在我的Mac上运行汇编代码有问题。 我目前正在通过Jeff Duntemann的书Step by Step。 问题是它专注于为32位Linux系统编写程序集。 我正在使用一个64位的Mac OS X系统。 我仍然可以在使用nasm -f macho32的64位系统上运行32位程序集,但显然Duntemann书中的代码不起作用,因为在Linux和Mac OS x中的系统调用是不同的。 我将如何转换这个程序:

; Executable name : EATSYSCALL ; Version : 1.0 ; Created date : 1/7/2009 ; Last update : 2/18/2009 ; Author : Jeff Duntemann ; Description : A simple program in assembly for Linux, using NASM 2.05, ; demonstrating the use of Linux INT 80H syscalls to display text. ; ; Build using these commands: ; nasm -f elf -g -F stabs eatsyscall.asm ; ld -o eatsyscall eatsyscall.o ; SECTION .data ; Section containing initialised data EatMsg: db "Eat at Joe's!",10 EatLen: equ $-EatMsg SECTION .bss ; Section containing uninitialized data SECTION .text ; Section containing code global _start ; Linker needs this to find the entry point! _start: nop ; This no-op keeps gdb happy... mov eax,4 ; Specify sys_write call mov ebx,1 ; Specify File Descriptor 1: Standard Output mov ecx,EatMsg ; Pass offset of the message mov edx,EatLen ; Pass the length of the message int 80H ; Make kernel call mov eax,1 ; Code for Exit Syscall mov ebx,0 ; Return a code of zero int 80H ; Make kernel call 

这样它会运行在我的Mac OS X系统? 我宁愿在32位程序集的解决scheme,因为我正在试图学习,而不是64位组装,这是更复杂。

我已经find了一个在线解决scheme,但它使用堆栈,并具有其他差异,如从esp寄存器中减去,即使Duntemann的程序根本没有引用esp寄存器:

 global start section .text start: push dword msg.len push dword msg push dword 1 mov eax, 4 sub esp, 4 int 0x80 add esp, 16 push dword 0 mov eax, 1 sub esp, 12 int 0x80 section .data msg: db "Hello, world!", 10 .len: equ $ - msg 

所以我想我想知道的是如何将Linux系统调用转换为Mac OS X系统调用一步一步的过程? 通过这本书,我可以做到这一点,而不必在虚拟机上下载Linux。

那个解决方案是错误的 line sub esp, 12应该是sub esp, 4 。 它没有通过0作为退出状态; 它传递了一个垃圾值。

Mac OS X有BSD系统调用。 例子很难找到,因为大多数BSD程序不直接进行系统调用; 他们链接到libc并调用libc中的函数来包装系统调用。 但是在汇编语言中,直接系统调用比libc调用更简单。

对于32位英特尔代码,OS X和Linux都响应int 0x80 。 他们都采用eax的系统呼叫号码,他们都将结果返回给eax 。 主要区别在于:

  • Linux在寄存器( ebxecxedx )中获取参数,但是OS X在栈上获取参数。 您按相反顺序推入参数,然后再推送额外的4个字节。
  • 当发生错误时,Linux在eax放一个负数,但OS X在eax放一个正数。 OS X还设置了一个条件代码,以便在错误发生或没有发生时jbjnb会跳转。
  • 系统调用有不同的数字,有些有不同的参数。

重要文件: syscalls.master

BSD系统使用名为syscalls.master的文件来定义系统调用。 我已经从Mac OS X 10.4.11×86链接到syscalls.master 。 我们可以使用它来查找每个系统调用的名称,参数和返回类型。 例如:

 4 PRE NONE ALL { user_ssize_t write(int fd, user_addr_t cbuf, user_size_t nbyte); } 

write(2)系统调用是编号4,所以我们用4加载eax 。它有3个参数,所以我们按照相反的顺序推入它们:我们按下缓冲区中的字节数,然后把一个指针指向缓冲区,然后推送文件描述符。 推入参数之后,我们推送4个额外的字节,也许带有sub esp, 4 。 然后我们做int 0x80 。 那么我们可能想要add esp, 16来删除我们推送的内容。

大多数参数和返回值是4字节的整数,但OS X中的off_t总是8字节的整数。 我们必须小心,像lseek(2)。

 199 NONE NONE ALL { off_t lseek(int fd, off_t offset, int whence); } 

偏移参数是一个8字节的整数,所以我们把它作为一对4字节的双字。 英特尔处理器是小端,并且堆栈增长减少,所以我们在推低dword之前推高dword。 lseek(2)的返回类型也是off_t。 它来自寄存器eaxedxeax的低位字和edx中的高位字。

有些系统调用很奇怪。 为了捕捉信号,OS X没有系统调用信号(3),与Linux不同。 我们必须使用sigaction(2),但是很奇怪:

 46 NONE KERN ALL { int sigaction(int signum, struct __sigaction *nsa, struct sigaction *osa); } 

第二个参数不是常规的sigaction结构。 这是一个更大的结构,包括一个额外的蹦床领域。 如果我们不在libc中调用sigaction(),那么我们必须提供我们自己的蹦床 ! 这与Linux和其他BSD内核不同。