跳转到数据段

mic*_*ard 5 c macos dep assembly

我正在测试我正在编写的汇编程序,它生成X86指令.我想做这样的事情来测试指令是否有效.

#include<stdio.h>

unsigned char code[2] = {0xc9, 0xc3};

int main() {
  void (*foo)();
  foo = &code;
  foo();
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是,由于DEP,OS X似乎阻止了这种情况.有没有办法(a)禁用此程序的DEP或(b)以另一种格式输入字节,以便我可以跳转到它们.

Die*_*Epp 6

如果你只是需要测试,试试这个,它是神奇的 ......

const unsigned char code[2] = {0xc9, 0xc3};
^^^^^
Run Code Online (Sandbox Code Playgroud)

const关键字使编译器将其放在const节中(警告!这是一个实现细节!),它与节相同text.整个段应该是可执行的.这样做可能更容易:

__attribute__((section("text"))
const unsigned char code[2] = {0xc9, 0xc3};
Run Code Online (Sandbox Code Playgroud)

你总是可以在一个程序集文件中做到这一点,

    .text
    .globl code
code:
    .byte 0xc9
    .byte 0xc3
Run Code Online (Sandbox Code Playgroud)

但是:如果要在运行时更改代码,则需要使用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);
}
Run Code Online (Sandbox Code Playgroud)

mprotect规范规定,如果内存不是最初映射其行为不确定mmap,但你正在测试,不发货,所以只是知道它工作得很好OS X上,因为OS X malloc使用mmap场景(专,我觉得背后).