2017-12-24 17 views
7

次は成功します。のmmapマック:私のMac上でセグメンテーションフォールト

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

    *addr = 25; 

    return 0; 
} 

を以下のコードは同じですが、私はセグメンテーションフォールトで*addrに書き込みをしようとすると失敗するしかし:

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

    *addr = 25; 

    return 0; 
} 

すなわち、 syscallは私にメモリアドレスを返すことに成功しましたが、書き込むときに失敗します。

私はこのようにそれをコンパイルします。

g++ ./c++/mmap.cc -o ./mmap && ./mmap 

私はdtrussとの両方のバージョンを実行した場合:

g++ ./c++/mmap.cc -o ./mmap && sudo dtruss ./mmap 

を、両方のバージョンが成功すると、私は両方のために同じmmapコール参照:

mmap(0x0, 0x64, 0x3, 0x1002, 0xFFFFFFFF, 0x0)   = 0xXXXXXXX 0 

syscallバージョンで私にセグメンテーションf ault、私は何が欠けていますか?

P.S.私がLinux上で似たようなことをすれば、うまく動作します。

Macではmmapの機能はsyscall(SYS_mmap, ...を実行しないことを理解しています。それはどうしますか?誰も私に実装を見ることができるいくつかのリンクを教えてください。

EDIT:

それは、Mac上でsyscallのように見えるだけで最初の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 

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 
+0

なぜこれを閉じたいのですか?システムプログラミングフォーラムにもっと属している可能性があります。しかし私は(完全に)同意しない。 –

+0

@意味 - 正確に、なぜですか?これは良い質問です。 – Vad

+0

@ meaning-matters推奨事項/リンクを求める。 [FAQ]を参照してください。また、なぜ '' SYS_mmap'を起動するのですか? – t0mm13b

答えて

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; 
} 

そして、あなたは0x2000000により、システムコール番号をずらすことでMac上でそれを使用する:

int* addr = (int*) syscall6(0x2000000 + SYS_mmap, 0, 100, 1 | 2, 2 | 4096, -1, 0); 

あなたはhere詳細を見つけることができます。

+2

素敵な仕事!用語に関する軽微な注記:シフトされた*システムコール*番号ではなく、(必須)*クラス*である。 http://dustin.schultz.io/mac-os-x-64-bit-assembly-system-calls.htmlを参照してください。 OS Xで必要とされるように、それをあなたの呼び出しルーチンに収めることができます。 – usr2564301

+1

これはx86 IIRCにのみ当てはまるので、私は '' a '(num) 'が' * ax'に置かれることにあまり信頼を置いていません。あなたは明示的な 'movq%2、%% rax'、IMHOを持つ方がよいでしょう。 – edmz

関連する問題