PageRenderTime 26ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/sample/bf.cpp

https://github.com/herumi/xbyak
C++ | 211 lines | 206 code | 4 blank | 1 comment | 21 complexity | 73311d8388372468f78159de30d2db03 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. #define XBYAK_NO_OP_NAMES
  2. #include "xbyak/xbyak.h"
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <stack>
  6. #include <fstream>
  7. #ifdef _MSC_VER
  8. #pragma warning(disable : 4996) // scanf
  9. #define snprintf _snprintf_s
  10. #endif
  11. class Brainfuck : public Xbyak::CodeGenerator {
  12. public:
  13. int getContinuousChar(std::istream& is, char c)
  14. {
  15. int count = 1;
  16. char p;
  17. while (is >> p) {
  18. if (p != c) break;
  19. count++;
  20. }
  21. is.unget();
  22. return count;
  23. }
  24. Brainfuck(std::istream& is) : CodeGenerator(100000)
  25. {
  26. // void (*)(void* putchar, void* getchar, int *stack)
  27. using namespace Xbyak;
  28. #ifdef XBYAK32
  29. const Reg32& pPutchar(esi);
  30. const Reg32& pGetchar(edi);
  31. const Reg32& stack(ebp);
  32. const Address cur = dword [stack];
  33. push(ebp); // stack
  34. push(esi);
  35. push(edi);
  36. const int P_ = 4 * 3;
  37. mov(pPutchar, ptr[esp + P_ + 4]); // putchar
  38. mov(pGetchar, ptr[esp + P_ + 8]); // getchar
  39. mov(stack, ptr[esp + P_ + 12]); // stack
  40. #elif defined(XBYAK64_WIN)
  41. const Reg64& pPutchar(rsi);
  42. const Reg64& pGetchar(rdi);
  43. const Reg64& stack(rbp); // stack
  44. const Address cur = dword [stack];
  45. push(rsi);
  46. push(rdi);
  47. push(rbp);
  48. mov(pPutchar, rcx); // putchar
  49. mov(pGetchar, rdx); // getchar
  50. mov(stack, r8); // stack
  51. #else
  52. const Reg64& pPutchar(rbx);
  53. const Reg64& pGetchar(rbp);
  54. const Reg64& stack(r12); // stack
  55. const Address cur = dword [stack];
  56. push(rbx);
  57. push(rbp);
  58. push(r12);
  59. mov(pPutchar, rdi); // putchar
  60. mov(pGetchar, rsi); // getchar
  61. mov(stack, rdx); // stack
  62. #endif
  63. std::stack<Label> labelF, labelB;
  64. char c;
  65. while (is >> c) {
  66. switch (c) {
  67. case '+':
  68. case '-':
  69. {
  70. int count = getContinuousChar(is, c);
  71. if (count == 1) {
  72. c == '+' ? inc(cur) : dec(cur);
  73. } else {
  74. add(cur, (c == '+' ? count : -count));
  75. }
  76. }
  77. break;
  78. case '>':
  79. case '<':
  80. {
  81. int count = getContinuousChar(is, c);
  82. add(stack, 4 * (c == '>' ? count : -count));
  83. }
  84. break;
  85. case '.':
  86. #ifdef XBYAK32
  87. push(cur);
  88. call(pPutchar);
  89. pop(eax);
  90. #elif defined(XBYAK64_WIN)
  91. mov(ecx, cur);
  92. sub(rsp, 32);
  93. call(pPutchar);
  94. add(rsp, 32);
  95. #else
  96. mov(edi, cur);
  97. call(pPutchar);
  98. #endif
  99. break;
  100. case ',':
  101. #if defined(XBYAK32) || defined(XBYAK64_GCC)
  102. call(pGetchar);
  103. #elif defined(XBYAK64_WIN)
  104. sub(rsp, 32);
  105. call(pGetchar);
  106. add(rsp, 32);
  107. #endif
  108. mov(cur, eax);
  109. break;
  110. case '[':
  111. {
  112. Label B = L();
  113. labelB.push(B);
  114. mov(eax, cur);
  115. test(eax, eax);
  116. Label F;
  117. jz(F, T_NEAR);
  118. labelF.push(F);
  119. }
  120. break;
  121. case ']':
  122. {
  123. Label B = labelB.top(); labelB.pop();
  124. jmp(B);
  125. Label F = labelF.top(); labelF.pop();
  126. L(F);
  127. }
  128. break;
  129. default:
  130. break;
  131. }
  132. }
  133. #ifdef XBYAK32
  134. pop(edi);
  135. pop(esi);
  136. pop(ebp);
  137. #elif defined(XBYAK64_WIN)
  138. pop(rbp);
  139. pop(rdi);
  140. pop(rsi);
  141. #else
  142. pop(r12);
  143. pop(rbp);
  144. pop(rbx);
  145. #endif
  146. ret();
  147. }
  148. };
  149. void dump(const uint8_t *code, size_t size)
  150. {
  151. puts("#include <stdio.h>\nstatic int stack[128 * 1024];");
  152. #ifdef _MSC_VER
  153. printf("static __declspec(align(4096)) ");
  154. #else
  155. printf("static __attribute__((aligned(4096)))");
  156. #endif
  157. puts("const unsigned char code[] = {");
  158. for (size_t i = 0; i < size; i++) {
  159. printf("0x%02x,", code[i]); if ((i % 16) == 15) putchar('\n');
  160. }
  161. puts("\n};");
  162. #ifdef _MSC_VER
  163. puts("#include <windows.h>");
  164. #else
  165. puts("#include <unistd.h>");
  166. puts("#include <sys/mman.h>");
  167. #endif
  168. puts("int main()\n{");
  169. #ifdef _MSC_VER
  170. puts("\tDWORD oldProtect;");
  171. puts("\tVirtualProtect((void*)code, sizeof(code), PAGE_EXECUTE_READWRITE, &oldProtect);");
  172. #else
  173. puts("\tlong pageSize = sysconf(_SC_PAGESIZE) - 1;");
  174. puts("\tmprotect((void*)code, (sizeof(code) + pageSize) & ~pageSize, PROT_READ | PROT_EXEC);");
  175. #endif
  176. puts(
  177. "\t((void (*)(void*, void*, int *))code)((void*)putchar, (void*)getchar, stack);\n"
  178. "}"
  179. );
  180. }
  181. int main(int argc, char *argv[])
  182. {
  183. #ifdef XBYAK32
  184. fprintf(stderr, "32bit mode\n");
  185. #else
  186. fprintf(stderr, "64bit mode\n");
  187. #endif
  188. if (argc == 1) {
  189. fprintf(stderr, "bf filename.bf [0|1]\n");
  190. return 1;
  191. }
  192. std::ifstream ifs(argv[1]);
  193. int mode = argc == 3 ? atoi(argv[2]) : 0;
  194. try {
  195. Brainfuck bf(ifs);
  196. if (mode == 0) {
  197. static int stack[128 * 1024];
  198. bf.getCode<void (*)(const void*, const void*, int *)>()(reinterpret_cast<const void*>(putchar), reinterpret_cast<const void*>(getchar), stack);
  199. } else {
  200. dump(bf.getCode(), bf.getSize());
  201. }
  202. } catch (std::exception& e) {
  203. printf("ERR:%s\n", e.what());
  204. } catch (...) {
  205. printf("unknown error\n");
  206. }
  207. }