xbyak/sample/bf.cpp

223 lines
4.6 KiB
C++
Raw Normal View History

2010-04-15 18:33:04 -07:00
#include "xbyak/xbyak.h"
#include <stdio.h>
#include <stdlib.h>
#include <stack>
#include <fstream>
#ifdef _MSC_VER
#pragma warning(disable : 4996) // scanf
2012-05-21 21:38:44 -07:00
#define snprintf _snprintf_s
2010-04-15 18:33:04 -07:00
#endif
class Brainfuck : public Xbyak::CodeGenerator {
public:
int getContinuousChar(std::istream& is, char c)
{
int count = 1;
char p;
while (is >> p) {
if (p != c) break;
count++;
}
is.unget();
return count;
}
2011-02-04 00:22:38 -07:00
Brainfuck(std::istream& is) : CodeGenerator(100000)
2010-04-15 18:33:04 -07:00
{
// void (*)(void* putchar, void* getchar, int *stack)
using namespace Xbyak;
#ifdef XBYAK32
const Reg32& pPutchar(esi);
const Reg32& pGetchar(edi);
const Reg32& stack(ebp);
2024-08-20 19:18:12 -07:00
const Address cur = byte [stack];
2010-04-15 18:33:04 -07:00
push(ebp); // stack
push(esi);
push(edi);
const int P_ = 4 * 3;
mov(pPutchar, ptr[esp + P_ + 4]); // putchar
mov(pGetchar, ptr[esp + P_ + 8]); // getchar
mov(stack, ptr[esp + P_ + 12]); // stack
#elif defined(XBYAK64_WIN)
const Reg64& pPutchar(rsi);
const Reg64& pGetchar(rdi);
const Reg64& stack(rbp); // stack
2024-08-20 19:18:12 -07:00
const Address cur = byte [stack];
2010-04-15 18:33:04 -07:00
push(rsi);
push(rdi);
push(rbp);
mov(pPutchar, rcx); // putchar
mov(pGetchar, rdx); // getchar
mov(stack, r8); // stack
#else
const Reg64& pPutchar(rbx);
const Reg64& pGetchar(rbp);
const Reg64& stack(r12); // stack
2024-08-20 19:18:12 -07:00
const Address cur = byte [stack];
2010-04-15 18:33:04 -07:00
push(rbx);
push(rbp);
push(r12);
mov(pPutchar, rdi); // putchar
mov(pGetchar, rsi); // getchar
mov(stack, rdx); // stack
#endif
2018-09-03 19:41:11 -07:00
std::stack<Label> labelF, labelB;
2010-04-15 18:33:04 -07:00
char c;
while (is >> c) {
switch (c) {
case '+':
case '-':
{
int count = getContinuousChar(is, c);
if (count == 1) {
c == '+' ? inc(cur) : dec(cur);
} else {
add(cur, (c == '+' ? count : -count));
}
}
break;
case '>':
case '<':
{
int count = getContinuousChar(is, c);
2024-08-20 19:18:12 -07:00
add(stack, (c == '>' ? count : -count));
2010-04-15 18:33:04 -07:00
}
break;
case '.':
#ifdef XBYAK32
push(cur);
call(pPutchar);
pop(eax);
#elif defined(XBYAK64_WIN)
2024-08-20 19:18:12 -07:00
movzx(ecx, cur);
2010-04-15 18:33:04 -07:00
sub(rsp, 32);
call(pPutchar);
add(rsp, 32);
#else
2024-08-20 19:18:12 -07:00
movzx(edi, cur);
2010-04-15 18:33:04 -07:00
call(pPutchar);
#endif
break;
case ',':
#if defined(XBYAK32) || defined(XBYAK64_GCC)
call(pGetchar);
#elif defined(XBYAK64_WIN)
sub(rsp, 32);
call(pGetchar);
add(rsp, 32);
#endif
2024-08-20 19:18:12 -07:00
mov(cur, al);
2010-04-15 18:33:04 -07:00
break;
case '[':
2018-09-03 19:41:11 -07:00
{
Label B = L();
labelB.push(B);
2024-08-20 19:18:12 -07:00
movzx(eax, cur);
2018-09-03 19:41:11 -07:00
test(eax, eax);
Label F;
jz(F, T_NEAR);
labelF.push(F);
}
2010-04-15 18:33:04 -07:00
break;
case ']':
{
2018-09-03 19:41:11 -07:00
Label B = labelB.top(); labelB.pop();
jmp(B);
Label F = labelF.top(); labelF.pop();
L(F);
2010-04-15 18:33:04 -07:00
}
break;
default:
break;
}
}
#ifdef XBYAK32
pop(edi);
pop(esi);
pop(ebp);
#elif defined(XBYAK64_WIN)
pop(rbp);
pop(rdi);
pop(rsi);
#else
pop(r12);
pop(rbp);
pop(rbx);
#endif
ret();
}
};
2020-09-07 23:14:18 -07:00
void dump(const uint8_t *code, size_t size)
2010-04-15 18:33:04 -07:00
{
2017-04-10 01:50:01 -07:00
puts("#include <stdio.h>\nstatic int stack[128 * 1024];");
#ifdef _MSC_VER
printf("static __declspec(align(4096)) ");
#else
printf("static __attribute__((aligned(4096)))");
#endif
puts("const unsigned char code[] = {");
2010-04-15 18:33:04 -07:00
for (size_t i = 0; i < size; i++) {
printf("0x%02x,", code[i]); if ((i % 16) == 15) putchar('\n');
}
puts("\n};");
2017-04-10 01:50:01 -07:00
#ifdef _MSC_VER
puts("#include <windows.h>");
#else
2010-04-15 18:33:04 -07:00
puts("#include <unistd.h>");
puts("#include <sys/mman.h>");
#endif
2017-04-10 01:50:01 -07:00
puts("int main()\n{");
#ifdef _MSC_VER
puts("\tDWORD oldProtect;");
puts("\tVirtualProtect((void*)code, sizeof(code), PAGE_EXECUTE_READWRITE, &oldProtect);");
#else
2010-04-15 18:33:04 -07:00
puts("\tlong pageSize = sysconf(_SC_PAGESIZE) - 1;");
puts("\tmprotect((void*)code, (sizeof(code) + pageSize) & ~pageSize, PROT_READ | PROT_EXEC);");
#endif
puts(
"\t((void (*)(void*, void*, int *))code)((void*)putchar, (void*)getchar, stack);\n"
"}"
);
}
int main(int argc, char *argv[])
{
#ifdef XBYAK32
2011-02-04 00:22:38 -07:00
fprintf(stderr, "32bit mode\n");
2010-04-15 18:33:04 -07:00
#else
2011-02-04 00:22:38 -07:00
fprintf(stderr, "64bit mode\n");
2010-04-15 18:33:04 -07:00
#endif
if (argc == 1) {
2024-09-29 03:44:49 -07:00
fprintf(stderr, "bf filename.bf [0|1|2]\n");
2010-04-15 18:33:04 -07:00
return 1;
}
std::ifstream ifs(argv[1]);
int mode = argc == 3 ? atoi(argv[2]) : 0;
2011-02-04 00:22:38 -07:00
try {
Brainfuck bf(ifs);
2024-09-29 03:44:49 -07:00
switch (mode) {
case 0: {
2011-02-04 00:22:38 -07:00
static int stack[128 * 1024];
2018-10-21 01:23:26 -07:00
bf.getCode<void (*)(const void*, const void*, int *)>()(reinterpret_cast<const void*>(putchar), reinterpret_cast<const void*>(getchar), stack);
2024-09-29 03:44:49 -07:00
break;
}
case 1: {
2011-02-04 00:22:38 -07:00
dump(bf.getCode(), bf.getSize());
2024-09-29 03:44:49 -07:00
break;
}
default: {
const char *dumpName = "bf.dump";
printf("dump to %s\n", dumpName);
std::ofstream ofs(dumpName, std::ios::binary);
ofs.write((const char*)bf.getCode(), bf.getSize());
break;
}
2011-02-04 00:22:38 -07:00
}
} catch (std::exception& e) {
printf("ERR:%s\n", e.what());
2011-02-04 00:22:38 -07:00
} catch (...) {
printf("unknown error\n");
2010-04-15 18:33:04 -07:00
}
}