mmap Mac:分段错误

Vad*_*Vad 7 c c++ system-calls

我的Mac上的以下内容成功:

int main() {
    int* addr = (int*) mmap(0, 100, 1 | 2, 2 | 4096, -1, 0);

    *addr = 25;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是下面的代码是相同的,但是当我尝试*addr使用分段错误写入时失败:

int main() {
    int* addr = (int*) syscall(SYS_mmap, 0, 100, 1 | 2, 2 | 4096, -1, 0);

    *addr = 25;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

syscall成功返回一个内存地址,但当我尝试写入它时失败.

我这样编译:

g++ ./c++/mmap.cc -o ./mmap && ./mmap
Run Code Online (Sandbox Code Playgroud)

如果我运行两个版本dtruss:

g++ ./c++/mmap.cc -o ./mmap && sudo dtruss ./mmap
Run Code Online (Sandbox Code Playgroud)

然后两个版本都成功了,我看到两个版本的相同mmap调用:

mmap(0x0, 0x64, 0x3, 0x1002, 0xFFFFFFFF, 0x0)            = 0xXXXXXXX 0
Run Code Online (Sandbox Code Playgroud)

为什么syscall版本会给我分段错误,我错过了什么?

PS如果我在Linux上做类似的事情它可以正常工作.

所以,据我所知mmap,Mac上的功能不会执行syscall(SYS_mmap, ....那它做什么用的?任何人都可以给我一些链接,我可以看到实现.

编辑:

看起来syscall在Mac上只返回前4个字节.有64位syscall版本吗?

拆解:

mmap 版:

_main:
0000000100000cf0        pushq   %rbp
0000000100000cf1        movq    %rsp, %rbp
0000000100000cf4        subq    $0x30, %rsp
0000000100000cf8        xorl    %eax, %eax
0000000100000cfa        movl    %eax, %ecx
0000000100000cfc        movl    $0x64, %eax
0000000100000d01        movl    %eax, %esi
0000000100000d03        movl    $0x3, %edx
0000000100000d08        movl    $0x1002, %eax
0000000100000d0d        movl    $0xffffffff, %r8d
0000000100000d13        movl    $0x0, -0x14(%rbp)
0000000100000d1a        movq    %rcx, %rdi
0000000100000d1d        movq    %rcx, -0x28(%rbp)
0000000100000d21        movl    %eax, %ecx
0000000100000d23        movq    -0x28(%rbp), %r9
0000000100000d27        callq   0x100000ed6 ## symbol stub for: _mmap
0000000100000d2c        movq    0x2cd(%rip), %rdi ## literal pool symbol address: __ZNSt3__14coutE
0000000100000d33        movq    %rax, -0x20(%rbp)
0000000100000d37        movq    -0x20(%rbp), %rax
0000000100000d3b        movq    %rax, %rsi
Run Code Online (Sandbox Code Playgroud)

syscall 版:

_main:
0000000100000cf0        pushq   %rbp
0000000100000cf1        movq    %rsp, %rbp
0000000100000cf4        subq    $0x30, %rsp
0000000100000cf8        movl    $0xc5, %edi
0000000100000cfd        xorl    %esi, %esi
0000000100000cff        movl    $0x64, %edx
0000000100000d04        movl    $0x3, %ecx
0000000100000d09        movl    $0x1002, %r8d
0000000100000d0f        movl    $0xffffffff, %r9d
0000000100000d15        movl    $0x0, -0x14(%rbp)
0000000100000d1c        movl    $0x0, (%rsp)
0000000100000d23        movb    $0x0, %al
0000000100000d25        callq   0x100000ed6 ## symbol stub for: _syscall
0000000100000d2a        movq    0x2cf(%rip), %rdi ## literal pool symbol address: __ZNSt3__14coutE
0000000100000d31        movslq  %eax, %r10
0000000100000d34        movq    %r10, -0x20(%rbp)
0000000100000d38        movq    -0x20(%rbp), %r10
0000000100000d3c        movq    %r10, %rsi
Run Code Online (Sandbox Code Playgroud)

Vad*_*Vad 5

显然Mac没有64位syscall功能,这里有一个简单的实现:

#include <sys/types.h>

#define CARRY_FLAG_BIT 1

inline int64_t syscall6(int64_t num, int64_t arg1, int64_t arg2, int64_t arg3, int64_t arg4, int64_t arg5, int64_t arg6) {
    int64_t result;
    int64_t flags;

    __asm__ __volatile__ (
        "movq %6, %%r10;\n"
        "movq %7, %%r8;\n"
        "movq %8, %%r9;\n"
        "syscall;\n"
        "movq %%r11, %1;\n"
        : "=a" (result), "=r" (flags)
        : "a" (num), "D" (arg1), "S" (arg2), "d" (arg3), "r" (arg4), "r" (arg5), "r" (arg6)
        : "%r10", "%r8", "%r9", "%rcx", "%r11"
    );

    return (flags & CARRY_FLAG_BIT) ? -result : result;
}
Run Code Online (Sandbox Code Playgroud)

您可以通过以下方式将系统调用号码转移到Mac上来使用它0x2000000:

int* addr = (int*) syscall6(0x2000000 + SYS_mmap, 0, 100, 1 | 2, 2 | 4096, -1, 0);
Run Code Online (Sandbox Code Playgroud)

你可以在这里找到更多.

  • 干得好!关于术语的一个小注:它不是*系统调用*号被移位,而是它(必需)*类*.请参见http://dustin.schultz.io/mac-os-x-64-bit-assembly-system-calls.html.因为它在OS X上是必需的,你可以将它放入你的调用例程中. (2认同)