/sample/bf.cpp
C++ | 211 lines | 206 code | 4 blank | 1 comment | 21 complexity | 73311d8388372468f78159de30d2db03 MD5 | raw file
Possible License(s): BSD-3-Clause
- #define XBYAK_NO_OP_NAMES
- #include "xbyak/xbyak.h"
- #include <stdio.h>
- #include <stdlib.h>
- #include <stack>
- #include <fstream>
- #ifdef _MSC_VER
- #pragma warning(disable : 4996) // scanf
- #define snprintf _snprintf_s
- #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;
- }
- Brainfuck(std::istream& is) : CodeGenerator(100000)
- {
- // void (*)(void* putchar, void* getchar, int *stack)
- using namespace Xbyak;
- #ifdef XBYAK32
- const Reg32& pPutchar(esi);
- const Reg32& pGetchar(edi);
- const Reg32& stack(ebp);
- const Address cur = dword [stack];
- 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
- const Address cur = dword [stack];
- 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
- const Address cur = dword [stack];
- push(rbx);
- push(rbp);
- push(r12);
- mov(pPutchar, rdi); // putchar
- mov(pGetchar, rsi); // getchar
- mov(stack, rdx); // stack
- #endif
- std::stack<Label> labelF, labelB;
- 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);
- add(stack, 4 * (c == '>' ? count : -count));
- }
- break;
- case '.':
- #ifdef XBYAK32
- push(cur);
- call(pPutchar);
- pop(eax);
- #elif defined(XBYAK64_WIN)
- mov(ecx, cur);
- sub(rsp, 32);
- call(pPutchar);
- add(rsp, 32);
- #else
- mov(edi, cur);
- 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
- mov(cur, eax);
- break;
- case '[':
- {
- Label B = L();
- labelB.push(B);
- mov(eax, cur);
- test(eax, eax);
- Label F;
- jz(F, T_NEAR);
- labelF.push(F);
- }
- break;
- case ']':
- {
- Label B = labelB.top(); labelB.pop();
- jmp(B);
- Label F = labelF.top(); labelF.pop();
- L(F);
- }
- 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();
- }
- };
- void dump(const uint8_t *code, size_t size)
- {
- 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[] = {");
- for (size_t i = 0; i < size; i++) {
- printf("0x%02x,", code[i]); if ((i % 16) == 15) putchar('\n');
- }
- puts("\n};");
- #ifdef _MSC_VER
- puts("#include <windows.h>");
- #else
- puts("#include <unistd.h>");
- puts("#include <sys/mman.h>");
- #endif
- puts("int main()\n{");
- #ifdef _MSC_VER
- puts("\tDWORD oldProtect;");
- puts("\tVirtualProtect((void*)code, sizeof(code), PAGE_EXECUTE_READWRITE, &oldProtect);");
- #else
- 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
- fprintf(stderr, "32bit mode\n");
- #else
- fprintf(stderr, "64bit mode\n");
- #endif
- if (argc == 1) {
- fprintf(stderr, "bf filename.bf [0|1]\n");
- return 1;
- }
- std::ifstream ifs(argv[1]);
- int mode = argc == 3 ? atoi(argv[2]) : 0;
- try {
- Brainfuck bf(ifs);
- if (mode == 0) {
- static int stack[128 * 1024];
- bf.getCode<void (*)(const void*, const void*, int *)>()(reinterpret_cast<const void*>(putchar), reinterpret_cast<const void*>(getchar), stack);
- } else {
- dump(bf.getCode(), bf.getSize());
- }
- } catch (std::exception& e) {
- printf("ERR:%s\n", e.what());
- } catch (...) {
- printf("unknown error\n");
- }
- }