Linux 为什么在映射内存时需要MAP_PRIVATE标志?

Linux 为什么在映射内存时需要MAP_PRIVATE标志?,linux,assembly,x86-64,Linux,Assembly,X86 64,我正在尝试匿名映射一页内存。这是: mov rax, 0x09 ; SYS_mmap mov rdi, 0x00 ; addr is NULL mov rsi, 0x8000 ; x86 page_size mov rdx, 0x02 ; PROT_WRITE mov r10, 0x20 ; MAP_ANONYMOUS mov r8, -1 ; fd = -1 mov r9, 0x00 ; offset = 0 syscall mov [rax], dword

我正在尝试匿名映射一页内存。这是:

mov rax, 0x09   ; SYS_mmap
mov rdi, 0x00   ; addr is NULL
mov rsi, 0x8000 ; x86 page_size
mov rdx, 0x02   ; PROT_WRITE
mov r10, 0x20   ; MAP_ANONYMOUS
mov r8, -1      ; fd = -1
mov r9, 0x00    ; offset = 0
syscall

mov [rax], dword -2 ; Segmentation fault, rax = -22
这是错误的。但当我将
MAP\u PRIVATE
添加到标志时,它工作正常:

mov rax, 0x09   ; SYS_mmap
mov rdi, 0x00   ; addr is NULL
mov rsi, 0x8000 ; x86 page_size
mov rdx, 0x02   ; PROT_WRITE
mov r10, 0x22   ; MAP_ANONYMOUS | MAP_PRIVATE 
mov r8, -1      ; fd = -1
mov r9, 0x00    ; offset = 0
syscall

mov [rax], dword -2 ; Now it works ok, rax = 0x7ffff7ff2000

我不明白为什么
mmap
会失败,为什么我们不指定
map\u PRIVATE
标志就匿名映射?

你不需要
map\u PRIVATE
,你需要
map\u PRIVATE
map\u SHARED
中的一个

flags参数确定是否更新映射 对映射相同区域的其他进程可见,以及 将更新传递到基础文件。这种行为是错误的 通过在标志中仅包含以下值之一确定:

MAP\u共享

共享此映射。[……]

MAP\u PRIVATE

在写映射时创建专用副本。[……]


用于选择如何传播对映射区域所做的任何更改:

  • MAP\u PRIVATE
    由文件备份
    映射同一文件的其他进程看不到任何更新。
    没有更新写入备份文件。
    对页面进行更新

    用于就地处理文件的内容

  • MAP\u PRIVATE\MAP\u ANONYMOUS
    (例如,未由文件备份)
    没有要更新的文件。
    对COW页面进行更新

    用于分配内存,而不是与分叉进程共享

  • MAP\u共享
    由文件备份
    更新对其他进程可见。
    更新将传播到备份文件

    用于转换文件。
    使用名称与其他进程共享内存区域非常有用(请参阅)

  • MAP|u SHARED | MAP|u ANONYMOUS
    (例如,未由文件备份)
    所有映射了相同区域的进程都可以看到更新。
    没有要更新的文件

    用于与分叉进程共享内部内存区域


您不需要
MAP\u PRIVATE
,您需要
MAP\u PRIVATE
MAP\u SHARED
中的一个

flags参数确定是否更新映射 对映射相同区域的其他进程可见,以及 将更新传递到基础文件。这种行为是错误的 通过在标志中仅包含以下值之一确定:

MAP\u共享

共享此映射。[……]

MAP\u PRIVATE

在写映射时创建专用副本。[……]


用于选择如何传播对映射区域所做的任何更改:

  • MAP\u PRIVATE
    由文件备份
    映射同一文件的其他进程看不到任何更新。
    没有更新写入备份文件。
    对页面进行更新

    用于就地处理文件的内容

  • MAP\u PRIVATE\MAP\u ANONYMOUS
    (例如,未由文件备份)
    没有要更新的文件。
    对COW页面进行更新

    用于分配内存,而不是与分叉进程共享

  • MAP\u共享
    由文件备份
    更新对其他进程可见。
    更新将传播到备份文件

    用于转换文件。
    使用名称与其他进程共享内存区域非常有用(请参阅)

  • MAP|u SHARED | MAP|u ANONYMOUS
    (例如,未由文件备份)
    所有映射了相同区域的进程都可以看到更新。
    没有要更新的文件

    用于与分叉进程共享内部内存区域


man mmap
:“仅包括一个共享的[…]地图[…]私有地图”。但是,即使使用
MAP\u SHARED
,它也会失败,您无法共享匿名映射,因为没有其他人可以打开它。您的代码似乎没有检查返回退出代码的系统调用。检测退出代码时的情况!=0将提高程序的健壮性,并有助于调试程序,因为系统调用错误代码至少在内核源代码中有记录。@Jester刚刚用
MAP\u SHARED
检查过。对我来说还不错。您是否遇到
分段错误
?@GrigoryRechistov:使用
strace
查看系统调用返回值比手工编写错误检查代码更容易,尤其是在asm中。对于实验,我总是使用
strace
而不是编写错误处理。如果编写一个实际的程序供将来使用,我用C语言编写,并在出错时使用
peror
。无论如何,这个问题的问题不包括
strace
输出,也不包括通过存储到映射来双重检查映射是否可用。(因为很容易意外地出现其他错误,这是错误。)@GrigoryRechistov:我只是说我计划从不添加错误检查的情况,例如,作为测试其他东西的实验的一部分,我不打算开发成一个长期维护的程序。由于
strace
和其他调试工具的存在,在创建实验/微基准时会出现许多此类情况。我同意如果你写的是真正有用的东西,你不应该跳过第一个版本中的错误检查。但是,即使使用
MAP\u SHARED
,它也会失败,您无法共享匿名映射,因为没有其他人可以打开它。您的代码似乎没有检查返回退出代码的系统调用。检测退出代码时的情况!=0将提高程序的健壮性,并有助于调试程序,因为系统调用错误代码至少在内核源代码中有记录。@Jester刚刚用
MAP\u SHARED
检查过。对我来说还不错。您是否遇到了
分段错误
?@GrigoryRechistov:使用