使用 memcpy 进行内联线程调度
Inline threaded dispatch with memcpy
我正在测试一种称为 inline threading and I can't seem to branch into executable memory without segfaulting. I am using the labels as values GCC 扩展的解释器调度技术,以确定每个操作码范围的开始和结束。
test.c:
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
int main (int argc, char** argv) {
int i = 0;
if (argc > 0x10) {
// prevent optimization
inc_start: i++; inc_end:;
ret_start: goto end; ret_end:;
}
void* m = mmap(
0,
getpagesize(),
PROT_WRITE | PROT_EXEC,
MAP_ANONYMOUS | MAP_PRIVATE,
-1,
0);
if (!m) {
return -1;
}
{
char* x = m;
memcpy(x, &&inc_start, &&inc_end - &&inc_start); x += &&inc_end - &&inc_start;
memcpy(x, &&inc_start, &&inc_end - &&inc_start); x += &&inc_end - &&inc_start;
memcpy(x, &&ret_start, &&ret_end - &&ret_start); x += &&ret_end - &&ret_start;
}
goto *m;
end:
return i;
}
编译并 运行 使用:
gcc test.c -O0 && ./a.out; echo $?
我期待 main 到 return 2,但是 :
Segmentation fault
139
我正在 64 位 linux 机器上使用 gcc 4.7.2 进行编译,我相信没有任何优化。关于如何让它工作的任何提示?
使用 GCC,我 pinned a variable to a callee saved register 为 x86_64 和 aarch64 in 消除了相对寻址和相对跳转问题。由于引入了不需要的跳转,因此在检查生成的程序集后我还重组了标签。从那以后,我用针对 x86_64-linux-gnu 的 gcc 4.8.4 版和针对 aarch64-linux-android 的 gcc 6.1.0 版编译了它,并且都产生了2.
的预期结果
// gcc test.c -O3 && ./a.out; echo $?
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#if defined(__amd64__) || defined(__x86_64__)
register long i asm ("r15");
#elif defined(__arch64__)
register long i asm ("x16");
#else
#error Unsupported architecture. Supported: x86_64, aarch64
#endif
long main (int argc, char** argv) {
i = 0;
void* m = mmap(0, getpagesize(),
PROT_WRITE | PROT_EXEC,
MAP_ANONYMOUS | MAP_PRIVATE,
-1, 0);
if (!m) {
return -1;
}
{
char* x = m;
memcpy(x, &&L00, &&L01 - &&L00); x += &&L01 - &&L00; // inc
memcpy(x, &&L00, &&L01 - &&L00); x += &&L01 - &&L00; // inc
memcpy(x, &&L01, &&L02 - &&L01); x += &&L02 - &&L01; // ret
}
goto *m;
L00: i++; // inc
L01: return i; // ret
L02:;
return -2;
}
编译并 运行 使用:
gcc test.c -O3 && ./a.out; echo $?
2
我将继续寻找不涉及将变量显式固定到寄存器的解决方案。
我正在测试一种称为 inline threading and I can't seem to branch into executable memory without segfaulting. I am using the labels as values GCC 扩展的解释器调度技术,以确定每个操作码范围的开始和结束。
test.c:
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
int main (int argc, char** argv) {
int i = 0;
if (argc > 0x10) {
// prevent optimization
inc_start: i++; inc_end:;
ret_start: goto end; ret_end:;
}
void* m = mmap(
0,
getpagesize(),
PROT_WRITE | PROT_EXEC,
MAP_ANONYMOUS | MAP_PRIVATE,
-1,
0);
if (!m) {
return -1;
}
{
char* x = m;
memcpy(x, &&inc_start, &&inc_end - &&inc_start); x += &&inc_end - &&inc_start;
memcpy(x, &&inc_start, &&inc_end - &&inc_start); x += &&inc_end - &&inc_start;
memcpy(x, &&ret_start, &&ret_end - &&ret_start); x += &&ret_end - &&ret_start;
}
goto *m;
end:
return i;
}
编译并 运行 使用:
gcc test.c -O0 && ./a.out; echo $?
我期待 main 到 return 2,但是 :
Segmentation fault
139
我正在 64 位 linux 机器上使用 gcc 4.7.2 进行编译,我相信没有任何优化。关于如何让它工作的任何提示?
使用 GCC,我 pinned a variable to a callee saved register 为 x86_64 和 aarch64 in 消除了相对寻址和相对跳转问题。由于引入了不需要的跳转,因此在检查生成的程序集后我还重组了标签。从那以后,我用针对 x86_64-linux-gnu 的 gcc 4.8.4 版和针对 aarch64-linux-android 的 gcc 6.1.0 版编译了它,并且都产生了2.
的预期结果// gcc test.c -O3 && ./a.out; echo $?
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#if defined(__amd64__) || defined(__x86_64__)
register long i asm ("r15");
#elif defined(__arch64__)
register long i asm ("x16");
#else
#error Unsupported architecture. Supported: x86_64, aarch64
#endif
long main (int argc, char** argv) {
i = 0;
void* m = mmap(0, getpagesize(),
PROT_WRITE | PROT_EXEC,
MAP_ANONYMOUS | MAP_PRIVATE,
-1, 0);
if (!m) {
return -1;
}
{
char* x = m;
memcpy(x, &&L00, &&L01 - &&L00); x += &&L01 - &&L00; // inc
memcpy(x, &&L00, &&L01 - &&L00); x += &&L01 - &&L00; // inc
memcpy(x, &&L01, &&L02 - &&L01); x += &&L02 - &&L01; // ret
}
goto *m;
L00: i++; // inc
L01: return i; // ret
L02:;
return -2;
}
编译并 运行 使用:
gcc test.c -O3 && ./a.out; echo $?
2
我将继续寻找不涉及将变量显式固定到寄存器的解决方案。