No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

606 líneas
24 KiB

  1. #include "molasses/parser_primitives.h"
  2. #include "molasses/generator_primitives.h"
  3. #include "molasses/errors.h"
  4. namespace molasses {
  5. namespace unix_system {
  6. #ifdef linux
  7. struct syscall1 {
  8. int64_t operator()(int64_t syscall_id, int64_t p1) const {
  9. int64_t ret;
  10. asm volatile("syscall" : "=a"(ret) : "0"(syscall_id), "D"(p1) : "rcx", "r11", "memory");
  11. return ret;
  12. }
  13. };
  14. struct syscall2 {
  15. int64_t operator()(int64_t syscall_id, int64_t p1, int64_t p2) const {
  16. int64_t ret;
  17. asm volatile("syscall" : "=a"(ret) : "0"(syscall_id), "D"(p1), "S"(p2) : "rcx", "r11", "memory");
  18. return ret;
  19. }
  20. };
  21. struct syscall3 {
  22. int64_t operator()(int64_t syscall_id, int64_t p1, int64_t p2, int64_t p3) const {
  23. int64_t ret;
  24. asm volatile("syscall"
  25. : "=a"(ret)
  26. : "0"(syscall_id), "D"(p1), "S"(p2), "d"(p3)
  27. : "rcx", "r11", "memory");
  28. return ret;
  29. }
  30. };
  31. struct syscall4 {
  32. int64_t operator()(int64_t syscall_id, int64_t p1, int64_t p2, int64_t p3, int64_t p4) const {
  33. int64_t ret;
  34. register long r10 asm("r10") = p4;
  35. asm volatile("syscall"
  36. : "=a"(ret)
  37. : "0"(syscall_id), "D"(p1), "S"(p2), "d"(p3), "r"(r10)
  38. : "rcx", "r11", "memory");
  39. return ret;
  40. }
  41. };
  42. struct syscall5 {
  43. int64_t operator()(int64_t syscall_id, int64_t p1, int64_t p2, int64_t p3, int64_t p4, int64_t p5) const {
  44. int64_t ret;
  45. register long r10 asm("r10") = p4;
  46. register long r8 asm("r8") = p5;
  47. asm volatile("syscall"
  48. : "=a"(ret)
  49. : "0"(syscall_id), "D"(p1), "S"(p2), "d"(p3), "r"(r10), "r"(r8)
  50. : "rcx", "r11", "memory");
  51. return ret;
  52. }
  53. };
  54. struct syscall6 {
  55. int64_t operator()(int64_t syscall_id, int64_t p1, int64_t p2, int64_t p3, int64_t p4, int64_t p5, int64_t p6) const {
  56. int64_t ret;
  57. register long r10 asm("r10") = p4;
  58. register long r8 asm("r8") = p5;
  59. register long r9 asm("r9") = p6;
  60. asm volatile("syscall"
  61. : "=a"(ret)
  62. : "0"(syscall_id), "D"(p1), "S"(p2), "d"(p3), "r"(r10), "r"(r8), "r"(r9)
  63. : "rcx", "r11", "memory");
  64. return ret;
  65. }
  66. };
  67. #endif
  68. }
  69. std::string marshal(const std::string& target) {
  70. std::stringstream builder;
  71. bool is_first = true;
  72. for(char character : target) {
  73. if(isalpha(character)) {
  74. builder << character;
  75. } else if(isdigit(character) and is_first) {
  76. builder << "___" << (int)character << "___";
  77. } else {
  78. builder << "__" << (int)character << "__";
  79. }
  80. is_first = false;
  81. }
  82. return builder.str();
  83. }
  84. std::string escape(const std::string& target) {
  85. std::stringstream builder;
  86. for(char character : target) {
  87. switch(character) {
  88. case 0:
  89. builder << "\\0";
  90. break;
  91. case '\n':
  92. builder << "\\n";
  93. break;
  94. case '"':
  95. builder << "\\\"";
  96. break;
  97. case '\t':
  98. builder << "\\t";
  99. break;
  100. case '\'':
  101. builder << "\\'";
  102. break;
  103. default:
  104. builder << character;
  105. }
  106. }
  107. return builder.str();
  108. }
  109. template<>
  110. parser_context register_i32_operations<architecture_t::x86_64_linux>(parser_context ctx) {
  111. ctx.operations.emplace_back(
  112. std::make_shared<molasses::primitive_operation>(
  113. std::string{"+"},
  114. std::vector<std::string>({"i32", "i32"}),
  115. std::vector<std::string>({"i32"}),
  116. std::vector<std::string>({
  117. " popq %rax\n",
  118. " popq %rbx\n",
  119. " addl %ebx, %eax\n",
  120. " andl $0xFFFFFFFF, %eax\n",
  121. " pushq %rax\n"
  122. }),
  123. [](const generate_context&, interpreter_stack& current_stack){
  124. auto value_a = current_stack.top();current_stack.pop();
  125. auto value_b = current_stack.top();current_stack.pop();
  126. if(not std::holds_alternative<int32_t>(value_a) or not std::holds_alternative<int32_t>(value_b)) {
  127. throw interpreter_error("+ expects i32 i32 as input");
  128. }
  129. current_stack.emplace(get<int32_t>(value_a) + get<int32_t>(value_b));
  130. }
  131. )
  132. );
  133. ctx.operations.emplace_back(
  134. std::make_shared<molasses::primitive_operation>(
  135. std::string{"+_i64"},
  136. std::vector<std::string>({"i64", "i64"}),
  137. std::vector<std::string>({"i64"}),
  138. std::vector<std::string>({
  139. " popq %rax\n",
  140. " popq %rbx\n",
  141. " addq %rbx, %rax\n",
  142. " pushq %rax\n"
  143. }),
  144. [](const generate_context&, interpreter_stack& current_stack){
  145. auto value_a = current_stack.top();current_stack.pop();
  146. auto value_b = current_stack.top();current_stack.pop();
  147. if(not std::holds_alternative<int64_t>(value_a) or not std::holds_alternative<int64_t>(value_b)) {
  148. throw interpreter_error("+_i64 expects i64 i64 as input");
  149. }
  150. current_stack.emplace(get<int64_t>(value_a) + get<int64_t>(value_b));
  151. }
  152. )
  153. );
  154. ctx.operations.emplace_back(
  155. std::make_shared<molasses::primitive_operation>(
  156. std::string{"/%_i64"},
  157. std::vector<std::string>({"i64", "i64"}),
  158. std::vector<std::string>({"i64", "i64"}),
  159. std::vector<std::string>({
  160. " popq %rax\n",
  161. " popq %rbx\n",
  162. " divq %rbx, %rax\n",
  163. " pushq %rax\n",
  164. " pushq %rdx\n"
  165. // TODO: this is actually unsigned division, so it needs improvements on negative numbers
  166. }),
  167. [](const generate_context&, interpreter_stack& current_stack){
  168. auto value_a = current_stack.top();current_stack.pop();
  169. auto value_b = current_stack.top();current_stack.pop();
  170. if(not std::holds_alternative<int64_t>(value_a) or not std::holds_alternative<int64_t>(value_b)) {
  171. throw interpreter_error("/%_i64 expects i64 i64 as input");
  172. } else if(get<int64_t>(value_b) == 0) {
  173. throw interpreter_error("/%_i64 division by zero");
  174. }
  175. current_stack.emplace(get<int64_t>(value_a) / get<int64_t>(value_b));
  176. current_stack.emplace(get<int64_t>(value_a) % get<int64_t>(value_b));
  177. }
  178. )
  179. );
  180. ctx.operations.emplace_back(
  181. std::make_shared<molasses::primitive_operation>(
  182. std::string{"u8-ptr_to_i64"},
  183. std::vector<std::string>({"u8 ptr"}),
  184. std::vector<std::string>({"i64"}),
  185. std::vector<std::string>({
  186. }),
  187. [](const generate_context&, interpreter_stack& current_stack){
  188. auto value = current_stack.top();current_stack.pop();
  189. if(not std::holds_alternative<ptr_type>(value) && not (get<ptr_type>(value).pointed->name() == "u8 ptr")) {
  190. throw interpreter_error("u8-ptr_to_i64 expects u8 ptr as input");
  191. }
  192. current_stack.emplace(intptr_t(get<ptr_type>(value).ptr));
  193. }
  194. )
  195. );
  196. ctx.operations.emplace_back(
  197. std::make_shared<molasses::primitive_operation>(
  198. std::string{"*"},
  199. std::vector<std::string>({"i32", "i32"}),
  200. std::vector<std::string>({"i32"}),
  201. std::vector<std::string>({
  202. " popq %rax\n",
  203. " popq %rbx\n",
  204. " imull %ebx, %eax\n",
  205. " andl $0xFFFFFFFF, %eax\n",
  206. " pushq %rax\n"
  207. }),
  208. [](const generate_context&, interpreter_stack& current_stack){
  209. auto value_a = current_stack.top();current_stack.pop();
  210. auto value_b = current_stack.top();current_stack.pop();
  211. if(not std::holds_alternative<int32_t>(value_a) or not std::holds_alternative<int32_t>(value_b)) {
  212. throw interpreter_error("* expects i32 i32 as input");
  213. }
  214. current_stack.emplace(get<int32_t>(value_a) * get<int32_t>(value_b));
  215. }
  216. )
  217. );
  218. ctx.operations.emplace_back(
  219. std::make_shared<molasses::primitive_operation>(
  220. std::string{"-"},
  221. std::vector<std::string>({"i32", "i32"}),
  222. std::vector<std::string>({"i32"}),
  223. std::vector<std::string>({
  224. " popq %rax\n",
  225. " popq %rbx\n",
  226. " subl %ebx, %eax\n",
  227. " andl $0xFFFFFFFF, %eax\n",
  228. " pushq %rax\n"
  229. }),
  230. [](const generate_context&, interpreter_stack& current_stack){
  231. auto value_a = current_stack.top();current_stack.pop();
  232. auto value_b = current_stack.top();current_stack.pop();
  233. if(not std::holds_alternative<int32_t>(value_a) or not std::holds_alternative<int32_t>(value_b)) {
  234. throw interpreter_error("- expects i32 i32 as input");
  235. }
  236. current_stack.emplace(get<int32_t>(value_a) - get<int32_t>(value_b));
  237. }
  238. )
  239. );
  240. ctx.operations.emplace_back(
  241. std::make_shared<molasses::primitive_operation>(
  242. std::string{"i32-to-i64"},
  243. std::vector<std::string>({"i32"}),
  244. std::vector<std::string>({"i64"}),
  245. std::vector<std::string>({
  246. " popq %rax\n",
  247. " movslq %eax, %rax\n",
  248. " pushq %rax\n"
  249. }),
  250. [](const generate_context&, interpreter_stack& current_stack){
  251. auto value = current_stack.top();current_stack.pop();
  252. if(not std::holds_alternative<int32_t>(value)) {
  253. throw interpreter_error("i32-to-i64 expects i32 as input");
  254. }
  255. current_stack.emplace(int64_t(get<int32_t>(value)));
  256. }
  257. )
  258. );
  259. ctx.operations.emplace_back(
  260. std::make_shared<molasses::primitive_operation>(
  261. std::string{"drop_i64"},
  262. std::vector<std::string>({"i64"}),
  263. std::vector<std::string>({}),
  264. std::vector<std::string>({
  265. " popq %rax\n"
  266. }),
  267. [](const generate_context&, interpreter_stack& current_stack){
  268. auto value = current_stack.top();current_stack.pop();
  269. if(not std::holds_alternative<int64_t>(value)) {
  270. throw interpreter_error("i32-to-i64 expects i32 as input");
  271. }
  272. }
  273. )
  274. );
  275. ctx.operations.emplace_back(
  276. std::make_shared<molasses::primitive_operation>(
  277. std::string{"syscall1"},
  278. std::vector<std::string>({"i64", "i64"}),
  279. std::vector<std::string>({"i64"}),
  280. std::vector<std::string>({
  281. " popq %rax\n",
  282. " popq %rdi\n",
  283. " syscall\n",
  284. " pushq %rax\n"
  285. }),
  286. [](const generate_context&, interpreter_stack& current_stack){
  287. auto value_0 = current_stack.top();current_stack.pop();
  288. auto value_1 = current_stack.top();current_stack.pop();
  289. if(
  290. not std::holds_alternative<int64_t>(value_0) or
  291. not std::holds_alternative<int64_t>(value_1)
  292. ) {
  293. throw interpreter_error("syscall1 expects i64 i64 as input");
  294. }
  295. #ifdef linux
  296. unix_system::syscall1{}(get<int64_t>(value_0), get<int64_t>(value_1));
  297. #endif
  298. }
  299. )
  300. );
  301. ctx.operations.emplace_back(
  302. std::make_shared<molasses::primitive_operation>(
  303. std::string{"syscall2"},
  304. std::vector<std::string>({"i64", "i64", "i64"}),
  305. std::vector<std::string>({"i64"}),
  306. std::vector<std::string>({
  307. " popq %rax\n",
  308. " popq %rdi\n",
  309. " popq %rsi\n",
  310. " syscall\n",
  311. " pushq %rax\n"
  312. }),
  313. [](const generate_context&, interpreter_stack& current_stack){
  314. auto value_0 = current_stack.top();current_stack.pop();
  315. auto value_1 = current_stack.top();current_stack.pop();
  316. auto value_2 = current_stack.top();current_stack.pop();
  317. if(
  318. not std::holds_alternative<int64_t>(value_0) or
  319. not std::holds_alternative<int64_t>(value_1) or
  320. not std::holds_alternative<int64_t>(value_2)
  321. ) {
  322. throw interpreter_error("syscall2 expects i64 i64 i64 as input");
  323. }
  324. #ifdef linux
  325. unix_system::syscall2{}(get<int64_t>(value_0), get<int64_t>(value_1), get<int64_t>(value_2));
  326. #endif
  327. }
  328. )
  329. );
  330. ctx.operations.emplace_back(
  331. std::make_shared<molasses::primitive_operation>(
  332. std::string{"syscall3"},
  333. std::vector<std::string>({"i64", "i64", "i64", "i64"}),
  334. std::vector<std::string>({"i64"}),
  335. std::vector<std::string>({
  336. " popq %rax\n",
  337. " popq %rdi\n",
  338. " popq %rsi\n",
  339. " popq %rdx\n",
  340. " syscall\n",
  341. " pushq %rax\n"
  342. }),
  343. [](const generate_context&, interpreter_stack& current_stack){
  344. auto value_0 = current_stack.top();current_stack.pop();
  345. auto value_1 = current_stack.top();current_stack.pop();
  346. auto value_2 = current_stack.top();current_stack.pop();
  347. auto value_3 = current_stack.top();current_stack.pop();
  348. if(
  349. not std::holds_alternative<int64_t>(value_0) or
  350. not std::holds_alternative<int64_t>(value_1) or
  351. not std::holds_alternative<int64_t>(value_2) or
  352. not std::holds_alternative<int64_t>(value_3)
  353. ) {
  354. throw interpreter_error("syscall3 expects i64 i64 i64 i64 as input");
  355. }
  356. #ifdef linux
  357. unix_system::syscall3{}(get<int64_t>(value_0), get<int64_t>(value_1), get<int64_t>(value_2), get<int64_t>(value_3));
  358. #endif
  359. }
  360. )
  361. );
  362. ctx.operations.emplace_back(
  363. std::make_shared<molasses::primitive_operation>(
  364. std::string{"syscall4"},
  365. std::vector<std::string>({"i64", "i64", "i64", "i64", "i64"}),
  366. std::vector<std::string>({"i64"}),
  367. std::vector<std::string>({
  368. " popq %rax\n",
  369. " popq %rdi\n",
  370. " popq %rsi\n",
  371. " popq %rdx\n",
  372. " popq %r10\n",
  373. " syscall\n",
  374. " pushq %rax\n"
  375. }),
  376. [](const generate_context&, interpreter_stack& current_stack){
  377. auto value_0 = current_stack.top();current_stack.pop();
  378. auto value_1 = current_stack.top();current_stack.pop();
  379. auto value_2 = current_stack.top();current_stack.pop();
  380. auto value_3 = current_stack.top();current_stack.pop();
  381. auto value_4 = current_stack.top();current_stack.pop();
  382. if(
  383. not std::holds_alternative<int64_t>(value_0) or
  384. not std::holds_alternative<int64_t>(value_1) or
  385. not std::holds_alternative<int64_t>(value_2) or
  386. not std::holds_alternative<int64_t>(value_3) or
  387. not std::holds_alternative<int64_t>(value_4)
  388. ) {
  389. throw interpreter_error("syscall4 expects i64 i64 i64 i64 i64 as input");
  390. }
  391. #ifdef linux
  392. unix_system::syscall4{}(get<int64_t>(value_0), get<int64_t>(value_1), get<int64_t>(value_2), get<int64_t>(value_3), get<int64_t>(value_4));
  393. #endif
  394. }
  395. )
  396. );
  397. ctx.operations.emplace_back(
  398. std::make_shared<molasses::primitive_operation>(
  399. std::string{"syscall5"},
  400. std::vector<std::string>({"i64", "i64", "i64", "i64", "i64", "i64"}),
  401. std::vector<std::string>({"i64"}),
  402. std::vector<std::string>({
  403. " popq %rax\n",
  404. " popq %rdi\n",
  405. " popq %rsi\n",
  406. " popq %rdx\n",
  407. " popq %r10\n",
  408. " popq %r8\n",
  409. " syscall\n",
  410. " pushq %rax\n"
  411. }),
  412. [](const generate_context&, interpreter_stack& current_stack){
  413. auto value_0 = current_stack.top();current_stack.pop();
  414. auto value_1 = current_stack.top();current_stack.pop();
  415. auto value_2 = current_stack.top();current_stack.pop();
  416. auto value_3 = current_stack.top();current_stack.pop();
  417. auto value_4 = current_stack.top();current_stack.pop();
  418. auto value_5 = current_stack.top();current_stack.pop();
  419. if(
  420. not std::holds_alternative<int64_t>(value_0) or
  421. not std::holds_alternative<int64_t>(value_1) or
  422. not std::holds_alternative<int64_t>(value_2) or
  423. not std::holds_alternative<int64_t>(value_3) or
  424. not std::holds_alternative<int64_t>(value_4) or
  425. not std::holds_alternative<int64_t>(value_5)
  426. ) {
  427. throw interpreter_error("syscall5 expects i64 i64 i64 i64 i64 i64 as input");
  428. }
  429. #ifdef linux
  430. unix_system::syscall5{}(get<int64_t>(value_0), get<int64_t>(value_1), get<int64_t>(value_2), get<int64_t>(value_3), get<int64_t>(value_4), get<int64_t>(value_5));
  431. #endif
  432. }
  433. )
  434. );
  435. ctx.operations.emplace_back(
  436. std::make_shared<molasses::primitive_operation>(
  437. std::string{"syscall6"},
  438. std::vector<std::string>({"i64", "i64", "i64", "i64", "i64", "i64", "i64"}),
  439. std::vector<std::string>({"i64"}),
  440. std::vector<std::string>({
  441. " popq %rax\n",
  442. " popq %rdi\n",
  443. " popq %rsi\n",
  444. " popq %rdx\n",
  445. " popq %r10\n",
  446. " popq %r8\n",
  447. " popq %r9\n",
  448. " syscall\n",
  449. " pushq %rax\n"
  450. }),
  451. [](const generate_context&, interpreter_stack& current_stack){
  452. auto value_0 = current_stack.top();current_stack.pop();
  453. auto value_1 = current_stack.top();current_stack.pop();
  454. auto value_2 = current_stack.top();current_stack.pop();
  455. auto value_3 = current_stack.top();current_stack.pop();
  456. auto value_4 = current_stack.top();current_stack.pop();
  457. auto value_5 = current_stack.top();current_stack.pop();
  458. auto value_6 = current_stack.top();current_stack.pop();
  459. if(
  460. not std::holds_alternative<int64_t>(value_0) or
  461. not std::holds_alternative<int64_t>(value_1) or
  462. not std::holds_alternative<int64_t>(value_2) or
  463. not std::holds_alternative<int64_t>(value_3) or
  464. not std::holds_alternative<int64_t>(value_4) or
  465. not std::holds_alternative<int64_t>(value_5) or
  466. not std::holds_alternative<int64_t>(value_6)
  467. ) {
  468. throw interpreter_error("syscall6 expects i64 i64 i64 i64 i64 i64 i64 as input");
  469. }
  470. #ifdef linux
  471. unix_system::syscall6{}(
  472. get<int64_t>(value_0),
  473. get<int64_t>(value_1),
  474. get<int64_t>(value_2),
  475. get<int64_t>(value_3),
  476. get<int64_t>(value_4),
  477. get<int64_t>(value_5),
  478. get<int64_t>(value_6)
  479. );
  480. #endif
  481. }
  482. )
  483. );
  484. return ctx;
  485. }
  486. template<>
  487. std::vector<std::string> generate_call<architecture_t::x86_64_linux>(const std::string& target) {
  488. return {
  489. " call "+marshal(target)+"\n",
  490. };
  491. }
  492. template<>
  493. std::vector<std::string> generate_string<architecture_t::x86_64_linux>(const symbol& representation, const std::string& string_value) {
  494. return {
  495. "__EMITED_STRING_____"+std::to_string(representation.id)+"___:\n",
  496. " .asciz \""+escape(string_value)+"\"\n",
  497. };
  498. }
  499. template<>
  500. std::vector<std::string> generate_push_string_ptr<architecture_t::x86_64_linux>(const symbol& representation) {
  501. return {
  502. " pushq $__EMITED_STRING_____"+std::to_string(representation.id)+"___\n"
  503. };
  504. }
  505. template<>
  506. std::vector<std::string> generate_push_int32<architecture_t::x86_64_linux>(int32_t target) {
  507. return {
  508. " pushq $" +std::to_string(target)+ "\n"
  509. };
  510. }
  511. template<>
  512. std::vector<std::string> generate_push_int64<architecture_t::x86_64_linux>(int64_t target) {
  513. return {
  514. " pushq $" +std::to_string(target)+ "\n"
  515. };
  516. }
  517. template<>
  518. std::vector<std::string> generate_label<architecture_t::x86_64_linux>(const std::string& target) {
  519. return {
  520. marshal(target)+":\n"
  521. };
  522. }
  523. template<>
  524. std::vector<std::string> generate_goto<architecture_t::x86_64_linux>(const std::string& target) {
  525. return {
  526. " jmp "+marshal(target)+"\n"
  527. };
  528. }
  529. template<>
  530. std::vector<std::string> generate_return<architecture_t::x86_64_linux>() {
  531. return {
  532. " // Return to caller\n",
  533. " addq $-8, %r10\n",
  534. " pushq (%r10)\n",
  535. " retq\n"
  536. };
  537. }
  538. template<>
  539. std::vector<std::string> generate_enter<architecture_t::x86_64_linux>() {
  540. return {
  541. " // Prepare the function stack\n",
  542. " popq (%r10)\n"
  543. " addq $8, %r10\n",
  544. };
  545. }
  546. template<>
  547. std::vector<std::string> initialize_stack<architecture_t::x86_64_linux>() {
  548. std::vector<std::string> operations = {
  549. "code:\n",
  550. " .skip 1000000\n",
  551. ".text\n",
  552. " .globl _start\n",
  553. "initialize_callstack:\n",
  554. " movq $9, %rax\n",
  555. " movq $0, %rdi\n",
  556. " movq $8192, %rsi\n",
  557. " movq $3, %rdx\n",
  558. " movq $34, %r10\n",
  559. " movq $-1, %r8\n",
  560. " movq $0, %r9\n",
  561. " syscall\n",
  562. " movq %rax, %r10\n",
  563. " retq\n",
  564. "_start:\n",
  565. " call initialize_callstack\n"
  566. };
  567. for(const auto& op : generate_call("main")) {
  568. operations.push_back(op);
  569. }
  570. for(const auto& op : std::vector<std::string>{
  571. " movq $0, %rdi\n",
  572. " movq $60, %rax\n",
  573. " syscall\n"
  574. }
  575. ) {
  576. operations.push_back(op);
  577. }
  578. return operations;
  579. }
  580. }