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:使用