You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

599 lines
24 KiB

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