TL;DR:一个整数作为第三个参数传递。
现在让我们回答 cmets 中的问题。
如果你打开 mman-common.h,它应该位于 /usr/include/asm-generic,你会找到这些值。
#define PROT_READ 0x1 /* page can be read */
#define PROT_WRITE 0x2 /* page can be written */
#define PROT_EXEC 0x4 /* page can be executed */
#define PROT_SEM 0x8 /* page may be used for atomic ops */
就在编译之前,预处理器将您的参数替换为上面的数字。
所以如果你有这个电话:
mprotect(myaddress, 256, PROT_READ | PROT_WRITE);
它将被以下代码替换:
mprotect(myaddress, 256, 0x1 | 0x2);
现在看看不同参数可以取的值:它们不是随机选择的,它们是 2 的幂,因此在二进制表示法中,它们仅由一个 1 数字和零表示。
PROT_READ = 0x1 = 00000001
PROT_WRITE = 0x2 = 00000010
PROT_EXEC = 0x4 = 00000100
选择 2 的幂很方便,因为当您使用二进制 OR 时,您获得的数字结合了前面的两个值,因此这两个信息都包含在 OR-ed 数字中。
PROT_WRITE | PROT_EXEC =
00000010
| 00000100
= 00000110
现在回到我们的电话:
如果您调用了mprotect(myaddress, 256, PROT_READ | PROT_WRITE),会发生的情况是PROT_READ | PROT_WRITE 会合并为0x1 | 0x2,即0x3。
现在在内核方面,假设PROT_READ | PROT_WRITE 是由用户编写的。内核接收到参数0x3,并想检查是否最初写入了PROT_READ。一种方法是这样写:
if (PROT_READ & userValue) { }
之所以有效,是因为 userValue 包含 PROT_READ 和 PROT_WRITE 的二进制版本:
PROT_READ & userValue =
00000001
&& 00000011
= 00000001
如果设置了标志,则此数字非零,因此内核知道已通过标志。
希望这会有所帮助。