我想知道在 os x 上哪里可以找到 mmap 标志值。 mmap 的手册页说要使用 MAP_PRIVATE、MAP_... 等,但如果您正在处理程序集,则必须知道进行系统调用的实际值。我尝试查找定义这些常量的头文件,但找不到。有人可以链接吗?
要首先找到正确的文件:有两个选项:
mmap
手册页仅提及 sys/mman.h
。ack
,因为它知道不搜索二进制文件,并且通常适合此类事情)。例如在我的 GNU/Linux 系统上,ack --hh MAP_PRIVATE /usr/include/ /usr/lib/gcc/x86_64-linux-gnu/5/
将仅搜索这两个目录下的 .h
文件 (--hh
),这是所有系统标头所在的位置。为了找到系统首先保存标题的位置,cpp 输出(不带
-dM
)包含当前行号设置行,告诉您包含了哪些标题。例如# 216 "/usr/lib/gcc/x86_64-linux-gnu/5/include/stddef.h" 3 4
如果任何常量采用 八进制 格式,例如
#define O_CREAT 00000100
中的 asm-generic/fcntl.h
,请注意 NASM 将 0100
视为十进制,因此您需要将其更改为 0q100
或 0o100
。
GNU 汇编器在整数文字的解释上与 C 匹配,因此即使对于
open()
标志,您也应该能够直接使用宏定义。 (如果您想使用像 S_IRUSR
这样的文件权限常量,而不是像普通汇编语言程序员那样编写八进制常量。:P)
gcc -E -dM
在处理结束时打印 only #define
行以及所有宏的最终值,而不是预处理的源。 -
告诉它从标准输入读取,因此您可以使用 echo
将代码片段通过管道传输到其中。
echo '#include <sys/mman.h>' | gcc -E - -dM | less
在
less
中,您当然可以使用/
进行搜索。 您还可以使用 &
进行过滤,隐藏与正则表达式不匹配的行。因此,您可以输入 &MAP_ 来获取 MAP_ 宏定义。
在 x86-64 GNU/Linux 上,我得到:
#define MAP_32BIT 0x40
#define MAP_TYPE 0x0f
#define MAP_EXECUTABLE 0x01000
#define MAP_FAILED ((void *) -1)
#define MAP_PRIVATE 0x02
...
如果您正在编写一些需要这些宏定义的实际 asm 代码,请记住
gcc -c foo.S
在汇编之前通过 C 预处理器运行 .S
文件。但是,sys/mman.h
包含宏定义以外的行(如 typedef unsigned char __u_char;
),这些行不是有效的 asm 语法。
最面向未来/可移植的方法可能是让您的构建脚本/Makefile使用
gcc -E -dM
来创建您需要的系统标头的本地仅宏版本。然后您的 .S
文件可以 #include "system_macros/mman.h"
等等。
但是,请注意
((void *) -1)
的 MAP_FAILED
定义:该语法无法汇编,因此这并不总是适用于编写在具有相同 ABI 但不同常量和系统调用号的不同系统上运行的可移植汇编。
对于系统调用号,系统
asm/unistd.h
通常只有宏,没有原型或类型定义。
你的asm源代码应该是这样的:
# 4th arg (flags) goes in r10 for the syscall ABI, vs. rcx for function calls
mov $(MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB), %r10d
括号不是必需的:一个
$
使整个操作数成为立即数,如 $foo|bar
。我想您可以将其视为优先级最低的运算符。
或者对于 NASM,使用类似
sed
的内容将 cpp 宏转换为 NASM .equ
定义:
mov r10d, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB
在 gcc 中使用
-E
选项可以让您查看预处理器之后源文件的输出。在以下源文件上使用 gcc -E test.c
#include <sys/mman.h>
int main() {
return MAP_PRIVATE;
}
输出
...
# 2 "asdf.c" 2
int main() {
return 0x02;
}
这表明
MAP_PRIVATE
等于我系统上的 0x02
。然而,这可能不适用于所有系统。