Macos 从mac os x中的32位程序集进行系统调用失败

Macos 从mac os x中的32位程序集进行系统调用失败,macos,assembly,system-calls,32-bit,Macos,Assembly,System Calls,32 Bit,我试图编写一个简短的32位汇编程序来测试MacOSX中的系统调用 我编写了如下所示的第一个版本,调用write()函数在屏幕上打印字符串。它确实有效 .data str: .ascii "Hello World\n" .text .globl _main _main: pushl $12 pushl $str pushl $1 movl $4, %eax

我试图编写一个简短的32位汇编程序来测试MacOSX中的系统调用

我编写了如下所示的第一个版本,调用write()函数在屏幕上打印字符串。它确实有效

.data
str:
    .ascii  "Hello World\n"

.text
.globl  _main
_main:
    pushl   $12
    pushl   $str                
    pushl   $1                  
    movl    $4, %eax            
    subl    $4, %esp            
    int     $0x80               
    addl    $16, %esp          
    pushl   $0                  
    movl    $1, %eax            
    subl    $12, %esp           
    int     $0x80 
在此之后,我决定编写另一个版本,使用mkdir()在“/tmp”中创建一个新目录,但失败了。mkdir()的系统调用号是0x88,我的代码如下所示。谁能告诉我哪里错了。非常感谢

.data
path:
    .ascii "/tmp/new_dir"

.text
.globl _main
_main:
    nop
    pushl   $path
    pushl   $0x1ff
    movl    $0x88, %eax
    subl    $8, %esp
    int     $0x80
    addl    $16, %esp

    pushl   $0                 
    movl    $1, %eax            
    subl    $12, %esp          
    int     $0x80 
我找到了一个简单的MacOS系统调用指南。根据我读到的内容,我假设
%eax
寄存器的值是唯一一个通过寄存器传递给syscall的值。其余寄存器必须从
EDX
开始推送到堆栈上

+----------+------------------------+--------------------------------+
| Register |          Use           |            Location            |
+----------+------------------------+--------------------------------+
| EAX      | Unused, just a padding | [ESP]                          |
| EBX      | Name of directory      | [ESP+4]                        |
| ECX      | Access                 | [ESP+8]                        |
| EDX      | Unused                 | Unused, but let's say [ESP+12] |
+----------+------------------------+--------------------------------+
根据此表,您的
mkdir
调用应该如下所示:

pushl $0        /* for EDX, unused */
pushl $0x1FF    /* for ECX */
pushl $path /* for EBX */
movl $0x88, %eax
pushl %eax     /* for EAX but unused */
int $0x80
addl $16, %esp  /* clean up */
此外,您的
exit
调用似乎也不正常(我不确定,我不太熟悉这种系统调用方式)

编辑:
在深入研究了有关BSD系统调用的一些资料之后,我还发现了一个源代码,建议将堆栈与16字节对齐。这意味着,当您使用少于4个参数调用系统调用时,您应该推送额外的双字,当您使用5个或全部6个参数调用系统调用时,您还应该推送一些双字(如果可用)
ESI
EBP
ESP

OSX需要堆栈对齐16字节。我已经推了8个字节。因此,我需要
subl$8
来对齐堆栈。堆栈对齐必须在推送参数之前进行。否则,被调用方如何知道在哪里找到参数?看看我的答案,了解更多的情况。是的,你是对的。对齐应该放在push参数之前。谢谢你的回答。但我想知道如何处理六个以上的参数?有些书说,如果需要六个以上的参数,则使用
%ebx
寄存器包含指向输入参数内存位置的指针,并按顺序存储。你能给我举一个处理六个以上参数的例子吗?据我所知,特定的系统调用通常有自己的附加参数格式。您对哪个系统调用感兴趣?我从来没有读过32位abi,但我假设您使用了一些通用寄存器,其余的都放在堆栈上。至少这是64位abi所规定的。没有,x86和x86-64系统调用约定是不同的。默认情况下,xyzBSD使用非unix方式将syscall参数传递给sycall过程。不过,有一种方法可以更改它(
brandelf
),您的表非常混乱。32位BSD/MacOS系统调用不关心EAX=调用号以外的寄存器。我认为该表是用于移植Linux系统调用的,但问题中没有任何内容是试图使用寄存器,所以您只是随便介绍一下,使它看起来像寄存器一样重要。不,你不必推EAX。在正常的BSD系统调用包装函数(在libc中)中,堆栈槽保存一个返回地址,因此包装函数可以在函数调用约定放置它们的参数处使用
int$0x80
subl %esp, $8 /* unused EDX and ECX */
pushl $0      /* for EBX */
movl $1, %eax
pushl %eax    /* unused EAX */
int 0x80