我正在测试我正在编写的生成 X86 指令的汇编程序。我想做这样的事情来测试说明是否有效。
#include<stdio.h>
unsigned char code[2] = {0xc9, 0xc3};
int main() {
void (*foo)();
foo = &code;
foo();
return 0;
}
但是,由于 DEP,OS X 似乎正在阻止这种情况。有没有办法(a)禁用该程序的 DEP 或(b)以另一种格式输入字节,以便我可以跳转到它们。
如果你只是需要测试,试试这个,它很神奇......
const unsigned char code[2] = {0xc9, 0xc3};
^^^^^
该const
关键字导致编译器将其放置在const
节中(警告!这是一个实现细节!),该节与节位于同一段中text
。整个段应该是可执行的。这样做可能更便携:
__attribute__((section("text"))
const unsigned char code[2] = {0xc9, 0xc3};
你总是可以在汇编文件中做到这一点,
.text
.globl code
code:
.byte 0xc9
.byte 0xc3
但是:如果要在运行时更改代码,则需要使用mprotect
. 默认情况下,内存中没有同时具有写入和执行权限的映射。
这是一个例子:
#include <stdlib.h>
#include <sys/mman.h>
#include <err.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
unsigned char *p = malloc(4);
int r;
// This is x86_64 code
p[0] = 0x8d;
p[1] = 0x47;
p[2] = 0x01;
p[3] = 0xc3;
// This is hackish, and in production you should do better.
// Casting 4095 to uintptr_t is actually necessary on 64-bit.
r = mprotect((void *) ((uintptr_t) p & ~(uintptr_t) 4095), 4096,
PROT_READ | PROT_WRITE | PROT_EXEC);
if (r)
err(1, "mprotect");
// f(x) = x + 1
int (*f)(int) = (int (*)(int)) p;
return f(1);
}
mprotect
规范指出,如果内存最初不是用 映射的,那么它的行为是未定义的,mmap
但是你正在测试,而不是发货,所以只要知道它在 OS X 上工作得很好,因为 OS X在幕后malloc
使用(独家,我认为mmap
)。
不知道你在 OSX 上的 DEP,但你可以做的另一件事是 malloc() 你编写代码的内存,然后跳转到这个 malloc'ed 区域。至少在 Linux 上,这个内存不会受到 exec 保护(事实上,这就是 JIT 通常的作用)。