的地址参数mprotect
需要是页面对齐的,并且大小参数是页面的整数。此外,将页面设置为PROT_WRITE
单独意味着您不再允许阅读它 - 这个特定页面将在文本段中,所以它也需要PROT_EXEC
,否则程序会在它返回时崩溃mprotect
(因为该页面上的代码不再被视为可执行文件)。
您的程序的这种修改可以满足您的需求:
/* file A */
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/mman.h>
extern const int foo;
int
main (int argc, char *argv[])
{
printf("Before modification: foo = %d @ %p\n", foo, (void *)&foo);
size_t pagesize = sysconf(_SC_PAGESIZE);
void *foo_page = (void *) (((uintptr_t)&foo) & ~(pagesize - 1));
if (mprotect(foo_page, pagesize, PROT_READ|PROT_WRITE|PROT_EXEC)) {
perror("mprotect");
return 1;
}
*(int *)&foo = 42; /* this is still undefined behavior! */
printf("After modification: foo = %d @ %p\n", foo, (void *)&foo);
return 0;
}
/* file B */
const int foo = 23;
警告:写入const
数据会触发未定义的行为,无论您是否使用操作系统原语来禁用包含它的页面的写保护。当我第一次测试这段代码时,我没有const int foo = 23;
在它自己的文件中,并且 GCC将这两个 printf
调用都重写为printf("...", 23, &foo)
. 这是一个有效的优化。 如果我打开链接时优化,我希望即使常量的定义被移动到它自己的文件中也会发生这种情况。此外,GCC 也有权替换*(int *)&foo = 42;
为无条件abort()
或陷阱指令。