MacOS(ARM64 架构)上的 mmap() RWX 页面?

Kla*_*ius 5 macos apple-silicon apple-m1

我一直在尝试映射一个既可写又可执行的页面。

    mov x0, 0                   // start address
    mov x1, 4096                // length
    mov x2, 7                   // rwx
    mov x3, 0x1001              // flags
    mov x4, -1                  // file descriptor
    mov x5, 0                   // offset
    movl x16, 0x200005c         // mmap
    svc 0   
Run Code Online (Sandbox Code Playgroud)

这给了我一个 0xD 错误代码(EACCESS,文档毫无帮助地将其归咎于无效的文件描述符,尽管相同的文档说使用“-1”)。我认为代码是正确的,如果我只是传递“r--”以获得权限,它会返回一个有效的 mmap。

我知道相同的代码可以在 Catalina 和 x64 架构中工作。我测试了禁用 SIP 模式时会发生相同的错误。

为了获得更多上下文,我正在尝试将 FORTH 实现移植到 MacOs/ARM64,而这个 FORTH 与许多其他实现一样,在运行时大量使用自修改代码/汇编代码。并且进行汇编/编译的代码驻留在新创建的代码的中间(事实上,编译器的一部分将作为运行 FORTH 的一部分以机器语言生成),因此分离 FORTH JIT 编译器是非常困难/不可行的(如果你这样称呼它)来自生成的代码。

现在,我真的不想最终得到这样的答案:“苹果认为他们比你更了解,不适合你!”,但这就是到目前为止的样子。谢谢你的帮助!

Stu*_*ffe 1

您需要在可写或可执行之间切换线程,不能同时两者。我认为实际上可以使用两个不同的线程使用相同的内存来完成这两个任务,但我还没有尝试过。

在写入映射的内存之前,请调用以下命令:

pthread_jit_write_protect_np(0);
sys_icache_invalidate(addr, size);
Run Code Online (Sandbox Code Playgroud)

然后,当您完成写入后,您可以像这样再次切换回来:

pthread_jit_write_protect_np(1);
sys_icache_invalidate(addr, size);
Run Code Online (Sandbox Code Playgroud)

这是我现在正在使用的完整代码

#include <stdio.h>
#include <sys/mman.h>
#include <pthread.h>
#include <libkern/OSCacheControl.h>
#include <stdlib.h>
#include <stdint.h>

uint32_t* c_get_memory(uint32_t size) {
    int prot = PROT_READ | PROT_WRITE | PROT_EXEC;
    int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_JIT;
    int fd = -1;
    int offset = 0;
    uint32_t* addr = 0;

    addr = (uint32_t*)mmap(0, size, prot, flags, fd, offset);
    if (addr == MAP_FAILED){
        printf("failure detected\n");
        exit(-1);
    }

    pthread_jit_write_protect_np(0);
    sys_icache_invalidate(addr, size);

    return addr;
}

void c_jit(uint32_t* addr, uint32_t size) {
    pthread_jit_write_protect_np(1);
    sys_icache_invalidate(addr, size);

    void (*foo)(void) = (void (*)())addr;
    foo();    
}
Run Code Online (Sandbox Code Playgroud)