c - Hooking mmap系统提供实时类型转换?

标签 c linux mmap

我正在处理一些我想内存映射一些包含数字数据的大文件的东西。问题在于数据可以是多种格式,包括实际字节/短/整数/长/浮点/ double 和复杂字节/短/整数/长/浮点/ double 。自然而然地始终处理所有这些类型很快就会变得笨拙,因此我正在考虑实现一个可以为用户进行实时类型转换的内存映射接口(interface)。

我真的很喜欢映射文件的想法,这样你就可以在内存中取回一个指针,做任何你需要做的事,然后取消映射。不需要缓冲学或其他任何东西。因此,一个读取数据并为我进行类型转换的函数会大大减少它。

我在想我可以内存映射正在操作的文件,然后同时映射一个匿名文件,以某种方式捕获页面获取/存储并按需进行类型转换。我将在 64 位上工作,因此在这些情况下这将为您提供 63 位地址空间,但是哦,好吧。

有谁知道这种 mmap Hook 是否可行,如果可行,如何实现?

最佳答案

是的(-ish)。您可以创建不可访问的 mmap 区域。每当有人试图触摸一个时,通过修复其权限、填充它和恢复来处理引发的 SIGSEGV

long *long_view =
   mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
double *double_view =
   mmap(NULL, 4096, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

static void on_segv(int signum, siginfo_t *info, void *data) {
    void *addr = info->si_addr;
    if ((uintptr_t)addr - (uintptr_t)long_view < 4096) {
        mprotect(long_view, 4096, PROT_READ|PROT_WRITE);
        /* translate from double_view to long_view */
        mprotect(double_view, 4096, PROT_NONE);
    } else if ((uintptr_t)addr - (uintptr_t)double_view < 4096) {
        mprotect(double_view, 4096, PROT_READ|PROT_WRITE);
        /* translate from long_view to long_view */
        mprotect(double_view, 4096, PROT_NONE);
    } else {
        abort();
    }
}

struct sigaction segv_action = {
    .sa_sigaction = on_segv,
    .sa_flags = SA_RESTART | SA_SIGINFO,
};
sigaction(SIGSEGV, &segv_action, NULL);

long_view[0] = 42;
/* hopefully, this will trigger the code to fixup double_view and resume */
printf("%g\n", double_view[0]);

(未经测试,但按照这些思路应该可以工作...)

如果你不想一次填满整个页面,我认为这仍然可行......第三个参数可以转换为 ucontext_t *,你可以用它来解码指令正在执行并修复它,就好像它已经执行了预期的操作一样,同时留下内存 PROT_NONE 来捕获进一步的访问......但是它会慢很多,因为你捕获了每一个访问而不是不仅仅是第一个。

关于c - Hooking mmap系统提供实时类型转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11642318/

相关文章:

c - 通过引用修改结构与其他指针之间的区别

c - 如何将主机指针传递到映射设备内存而不复制主机数据?

c++ - "Standard library"用于使用 Make 构建 C/C++ 项目

linux - MEM_SHARED、mmap 和硬链接(hard link)

c - 我怎样才能访问正在运行的程序的内存?

c - 带内部振荡器的 sleep 模式(PIC18f46j50)

linux - 系统日志问题

linux - 如何在Linux上使用cfsetispeed和tcsetattr命令将端口波特率配置为9600?

linux - 在Nginx上服务外部文件

c - mmap 与 mmap64 有什么区别吗?