Fast IFS using RPN notation
python
c
x86-64
nasm
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.

rpn_jit.c 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. /*
  2. * Copyright (C) 2020 Weber Yann
  3. *
  4. * This file is part of pyrpn.
  5. *
  6. * pyrpn is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * any later version.
  10. *
  11. * pyrpn is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with pyrpn. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "rpn_jit.h"
  20. int rpn_expr_init(rpn_expr_t* expr, const unsigned char stack_sz,
  21. const size_t args_count)
  22. {
  23. #ifdef DEBUG
  24. if(!expr)
  25. {
  26. dprintf(2, "Error, NULL ptr given as expression to rpn_expr_init");
  27. errno = EINVAL;
  28. return -1;
  29. }
  30. #endif
  31. bzero(expr, sizeof(rpn_expr_t));
  32. expr->stack_sz = stack_sz;
  33. expr->args_count = args_count;
  34. expr->state = RPN_SOURCE;
  35. memset(expr->err_reason, (int)'\0', 128);
  36. expr->stack = malloc(sizeof(unsigned long) * stack_sz);
  37. if(!expr->stack)
  38. {
  39. snprintf(expr->err_reason, 128,
  40. "Unable to malloc stack : %s", strerror(errno));
  41. expr->state = RPN_ERROR;
  42. return -1;
  43. }
  44. bzero(expr->stack, sizeof(unsigned long) * stack_sz);
  45. if(_rpn_expr_init_map(expr) < 0)
  46. {
  47. snprintf(expr->err_reason, 128,
  48. "Unable to init code map : %s", strerror(errno));
  49. free(expr->expr);
  50. expr->state = RPN_ERROR;
  51. return -1;
  52. }
  53. return 0;
  54. }
  55. int rpn_expr_reinit(rpn_expr_t* expr)
  56. {
  57. #ifdef DEBUG
  58. if(!expr)
  59. {
  60. dprintf(2, "Error, NULL ptr given as expression to rpn_expr_compile");
  61. errno = EINVAL;
  62. return -1;
  63. }
  64. #endif
  65. if(_rpn_expr_reset_map(expr) < 0)
  66. {
  67. snprintf(expr->err_reason, 128,
  68. "Unable to re-init code map : %s", strerror(errno));
  69. expr->state = RPN_ERROR;
  70. return -1;
  71. }
  72. bzero(expr->stack, sizeof(unsigned long) * expr->stack_sz);
  73. if(_rpn_expr_init_map(expr) < 0)
  74. {
  75. snprintf(expr->err_reason, 128,
  76. "Unable to re-init code map : %s", strerror(errno));
  77. free(expr->expr);
  78. expr->state = RPN_ERROR;
  79. return -1;
  80. }
  81. return 0;
  82. }
  83. int rpn_expr_recompile(rpn_expr_t *expr, const char *code)
  84. {
  85. if(rpn_expr_reinit(expr) < 0)
  86. {
  87. return -1;
  88. }
  89. return rpn_expr_compile(expr, code);
  90. }
  91. int rpn_expr_tokens_updated(rpn_expr_t* expr)
  92. {
  93. if(rpn_expr_reinit(expr) < 0)
  94. {
  95. return -1;
  96. }
  97. if(_rpn_expr_compile_tokens(expr) < 0)
  98. {
  99. expr->state = RPN_ERROR;
  100. return -1;
  101. }
  102. if(expr->expr)
  103. {
  104. free(expr->expr);
  105. }
  106. expr->expr = rpn_tokenized_expr(&expr->toks, 0);
  107. expr->state = RPN_READY;
  108. return 0;
  109. }
  110. int rpn_expr_compile(rpn_expr_t *expr, const char *code)
  111. {
  112. #ifdef DEBUG
  113. if(!expr)
  114. {
  115. dprintf(2, "Error, NULL ptr given as expression to rpn_expr_compile");
  116. errno = EINVAL;
  117. return -1;
  118. }
  119. #endif
  120. expr->expr = strdup(code);
  121. if(!expr->expr)
  122. {
  123. snprintf(expr->err_reason, 128,
  124. "Unable to strdup expression : %s", strerror(errno));
  125. expr->state = RPN_ERROR;
  126. return -1;
  127. }
  128. return _rpn_expr_compile_expr(expr);
  129. }
  130. int rpn_expr_untokenize(rpn_expr_t *expr, const rpn_tokenized_t *tokens, char long_op)
  131. {
  132. int err;
  133. size_t i;
  134. errno = 0;
  135. #ifdef DEBUG
  136. if(!expr)
  137. {
  138. dprintf(2, "Error, NULL ptr given as expression to rpn_expr_untokenize");
  139. err = EINVAL;
  140. goto ret_err;
  141. }
  142. if(tokens->argc != expr->args_count)
  143. {
  144. /* even if it should work with tokens->argc < expr->args_count */
  145. snprintf(expr->err_reason, 128,
  146. "Expression argc differ from tokenized version");
  147. err = EINVAL;
  148. goto ret_err;
  149. }
  150. #endif
  151. if(!(expr->expr = rpn_tokenized_expr(tokens, long_op)))
  152. {
  153. err = errno;
  154. snprintf(expr->err_reason, 128,
  155. "Error reading tokenized expression : %s",
  156. strerror(err));
  157. goto ret_err;
  158. }
  159. for(i=0; i<tokens->tokens_sz; i++)
  160. {
  161. if(_rpn_expr_token_copy(expr, &(tokens->tokens[i])) < 0)
  162. {
  163. err = errno;
  164. if(errno == EUCLEAN)
  165. {
  166. dprintf(2,
  167. "Fatal error, unknown token type : %d.\nMemory corruption ?\n",
  168. tokens->tokens[i].type);
  169. exit(1);
  170. }
  171. snprintf(expr->err_reason, 128,
  172. "Untokenize error : %s",
  173. strerror(err));
  174. goto ret_err;
  175. }
  176. }
  177. if(_rpn_expr_end_map(expr))
  178. {
  179. snprintf(expr->err_reason, 128,
  180. "Error ending code map : %s",
  181. strerror(errno));
  182. expr->state = RPN_ERROR;
  183. return -1;
  184. }
  185. expr->state = RPN_READY;
  186. return 0;
  187. ret_err:
  188. expr->state = RPN_ERROR;
  189. errno = err;
  190. return -1;
  191. }
  192. char* rpn_random(size_t op_sz, size_t args_count)
  193. {
  194. const int BUFF_ALLOC = 4096;
  195. double step;
  196. size_t i, buff_sz, offset, rnd;
  197. char *buff, *cur;
  198. unsigned char op_n;
  199. unsigned long int seed, rnd_val;
  200. int nchr, err;
  201. buff_sz = offset = 0;
  202. buff = NULL;
  203. step = 1.0 / (rpn_op_sz() + (args_count>0?2:1)); // + args and values
  204. if(getrandom(&seed, sizeof(long int), 0) < 0)
  205. {
  206. err=errno;
  207. perror("Fails to get a random number from kernel");
  208. errno=err;
  209. return NULL;
  210. }
  211. srand48(seed);
  212. for(i=0; i<op_sz; i++)
  213. {
  214. if(buff_sz - offset < BUFF_ALLOC / 4)
  215. {
  216. buff_sz += BUFF_ALLOC;
  217. cur = realloc(buff, sizeof(char) * buff_sz);
  218. if(!cur)
  219. {
  220. err=errno;
  221. perror("Error allocating random expression");
  222. errno=err;
  223. return NULL;
  224. }
  225. buff=cur;
  226. }
  227. cur = buff + offset;
  228. *cur = '\0';
  229. op_n = drand48() / step;
  230. if(op_n < rpn_op_sz())
  231. {
  232. cur[0] = rpn_ops[op_n].chr;
  233. cur[1] = ' ';
  234. cur[2] = '\0';
  235. offset += 2;
  236. }
  237. else if(op_n == rpn_op_sz())
  238. {
  239. if(getrandom(&rnd_val, sizeof(long int), 0) < 0)
  240. {
  241. err=errno;
  242. perror("Fails to get a random number for value");
  243. errno=err;
  244. return NULL;
  245. }
  246. // values
  247. if((nchr = sprintf(cur, "0x%lX ", rnd_val)) < 0)
  248. {
  249. err=errno;
  250. perror("Error while sprintf arguments in random generator");
  251. errno=err;
  252. return NULL;
  253. }
  254. offset += nchr;
  255. }
  256. else
  257. {
  258. rnd = drand48() / (1.0 / args_count);
  259. // arguments
  260. if((nchr = sprintf(cur, "A%ld ", rnd)) < 0)
  261. {
  262. err=errno;
  263. perror("Error while sprintf arguments in random generator");
  264. errno=err;
  265. return NULL;
  266. }
  267. offset += nchr;
  268. }
  269. }
  270. if(offset)
  271. {
  272. buff[offset-1] = '\0';
  273. }
  274. return buff;
  275. }
  276. size_t rpn_expr_serialize(rpn_expr_t* expr, void *buf, size_t buf_sz)
  277. {
  278. const size_t total_sz = sizeof(rpn_expr_serial_t) + \
  279. (sizeof(rpn_token_t)*expr->toks.tokens_sz) + \
  280. (sizeof(rpn_value_t)*expr->stack_sz);
  281. if(total_sz < buf_sz || !buf)
  282. {
  283. return total_sz;
  284. }
  285. bzero(buf, total_sz);
  286. rpn_expr_serial_t *ser = buf;
  287. rpn_token_t *tokens = (void*)buf + sizeof(*ser);
  288. rpn_value_t *stack = (void*)(tokens + expr->toks.tokens_sz);
  289. ser->token_sz = expr->toks.tokens_sz;
  290. ser->stack_sz = expr->stack_sz;
  291. ser->argc = expr->toks.argc;
  292. ser->state = expr->state;
  293. memcpy(ser->err_reason, expr->err_reason, sizeof(ser->err_reason));
  294. memcpy(stack, expr->stack, expr->stack_sz);
  295. for(size_t i=0; i < ser->token_sz; i++)
  296. {
  297. tokens[i].type = expr->toks.tokens[i].type;
  298. switch(expr->toks.tokens[i].type)
  299. {
  300. case RPN_arg:
  301. tokens[i].arg_n = expr->toks.tokens[i].arg_n;
  302. break;
  303. case RPN_val:
  304. tokens[i].value = expr->toks.tokens[i].value;
  305. break;
  306. case RPN_op:
  307. tokens[i].op_n = expr->toks.tokens[i].op_n;
  308. break;
  309. default:
  310. // SHOULD NEVER APPEND !
  311. errno = EINVAL;
  312. goto err;
  313. }
  314. }
  315. return total_sz;
  316. err:
  317. return 0;
  318. }
  319. int rpn_expr_deserialize(rpn_expr_t* expr, const void *buf, size_t buf_sz)
  320. {
  321. int err = EINVAL;
  322. const rpn_expr_serial_t *ser = buf;
  323. if(!expr)
  324. {
  325. errno = EINVAL;
  326. return -1;
  327. }
  328. if(buf_sz < sizeof(rpn_expr_serial_t))
  329. {
  330. snprintf(expr->err_reason, 128,
  331. "Given buffer is to small (%ld bytes) to deserialize", buf_sz);
  332. err = EINVAL;
  333. goto err;
  334. }
  335. const size_t total_sz = sizeof(rpn_expr_serial_t) + \
  336. (sizeof(rpn_token_t)*ser->token_sz) + \
  337. (sizeof(rpn_value_t)*ser->stack_sz);
  338. if(buf_sz < total_sz)
  339. {
  340. snprintf(expr->err_reason, 128,
  341. "Expected %ld bytes but %ld given",
  342. total_sz, buf_sz);
  343. err = EINVAL;
  344. goto err;
  345. }
  346. rpn_token_t *tokens = (void*)buf + sizeof(*ser);
  347. rpn_value_t *stack = (void*)(tokens + ser->token_sz);
  348. if(rpn_expr_init(expr, ser->stack_sz, ser->argc) < 0)
  349. {
  350. err = EINVAL;
  351. goto err;
  352. }
  353. expr->state = ser->state;
  354. memcpy(expr->err_reason, ser->err_reason, 128);
  355. memcpy(expr->stack, stack, sizeof(rpn_value_t)*ser->stack_sz);
  356. expr->args_count = expr->toks.argc = ser->argc;
  357. rpn_tokenized_t toks;
  358. toks.argc = ser->argc;
  359. toks.tokens_sz = ser->token_sz;
  360. toks.tokens = malloc(sizeof(rpn_token_t)*ser->token_sz);
  361. if(!toks.tokens)
  362. {
  363. err = errno;
  364. snprintf(expr->err_reason, 128,
  365. "Unable to allocate tokens : %s",
  366. strerror(errno));
  367. goto err_expr;
  368. }
  369. for(size_t i=0; i < ser->token_sz; i++)
  370. {
  371. toks.tokens[i].type = tokens[i].type;
  372. switch(tokens[i].type)
  373. {
  374. case RPN_val:
  375. toks.tokens[i].value = tokens[i].value;
  376. break;
  377. case RPN_arg:
  378. toks.tokens[i].arg_n = tokens[i].arg_n;
  379. break;
  380. case RPN_op:
  381. toks.tokens[i].op_n = tokens[i].op_n;
  382. toks.tokens[i].op = &(rpn_ops[tokens[i].op_n]);
  383. break;
  384. default:
  385. snprintf(expr->err_reason, 128,
  386. "Invalid token type encountered %d", tokens[i].type);
  387. err = EINVAL;
  388. goto err_expr;
  389. }
  390. }
  391. if(rpn_expr_untokenize(expr, &toks, 0) < 0)
  392. {
  393. err = EINVAL;
  394. goto err_expr;
  395. }
  396. expr->toks = toks;
  397. return 0;
  398. err_expr:
  399. rpn_expr_close(expr);
  400. err:
  401. expr->state = RPN_ERROR;
  402. errno = err;
  403. return -1;
  404. }
  405. int _rpn_expr_compile_expr(rpn_expr_t* expr)
  406. {
  407. rpn_tokenizer_t tokenizer;
  408. rpn_token_t *token;
  409. if(expr->state == RPN_ERROR)
  410. {
  411. goto err;
  412. }
  413. if(rpn_tokenizer_start(&tokenizer, &(expr->toks), expr->expr,
  414. expr->args_count) < 0)
  415. {
  416. snprintf(expr->err_reason, 128,
  417. "Error starting tokenizer : %s",
  418. tokenizer.err_reason);
  419. goto err;
  420. }
  421. while((token = rpn_tok(&tokenizer)))
  422. {
  423. if(_rpn_expr_token_copy(expr, token) < 0)
  424. {
  425. if(errno == EUCLEAN)
  426. {
  427. dprintf(2,
  428. "Fatal error, unknown token type : %d chr %ld.\nMemory corruption ?\n",
  429. token->type, tokenizer.chr_no);
  430. exit(1);
  431. }
  432. snprintf(expr->err_reason, 128,
  433. "Compilation error on chr %ld, unable to copy code part : %s",
  434. tokenizer.chr_no, strerror(errno));
  435. goto err;
  436. }
  437. }
  438. if(rpn_tokenizer_error(&tokenizer))
  439. {
  440. snprintf(expr->err_reason, 128,
  441. "Compilation error, chr %ld : %s",
  442. tokenizer.chr_no, tokenizer.err_reason);
  443. goto err;
  444. }
  445. if(_rpn_expr_end_map(expr))
  446. {
  447. snprintf(expr->err_reason, 128,
  448. "Error ending code map : %s",
  449. strerror(errno));
  450. expr->state = RPN_ERROR;
  451. return -1;
  452. }
  453. expr->state = RPN_READY;
  454. return 0;
  455. err:
  456. expr->state = RPN_ERROR;
  457. return -1;
  458. }
  459. int _rpn_expr_compile_tokens(rpn_expr_t* expr)
  460. {
  461. size_t i;
  462. rpn_token_t *token;
  463. for(i=0; i<expr->toks.tokens_sz; i++)
  464. {
  465. token = &(expr->toks.tokens[i]);
  466. if(_rpn_expr_token_copy(expr, token) < 0)
  467. {
  468. if(errno == EUCLEAN)
  469. {
  470. dprintf(2,
  471. "Fatal error, unknown token type : %d\nMemory corruption ?\n",
  472. token->type);
  473. exit(1);
  474. }
  475. snprintf(expr->err_reason, 128,
  476. "Compilation error, unable to copy code part : %s",
  477. strerror(errno));
  478. expr->state = RPN_ERROR;
  479. return -1;
  480. }
  481. }
  482. if(_rpn_expr_end_map(expr))
  483. {
  484. snprintf(expr->err_reason, 128,
  485. "Error ending code map : %s",
  486. strerror(errno));
  487. expr->state = RPN_ERROR;
  488. return -1;
  489. }
  490. expr->state = RPN_READY;
  491. return 0;
  492. }
  493. unsigned long rpn_expr_eval(rpn_expr_t *expr, unsigned long *args)
  494. {
  495. rpn_run_f expr_run;
  496. rpn_value_t res;
  497. if(expr->state == RPN_ERROR)
  498. {
  499. return 0;
  500. }
  501. expr_run = expr->code_map;
  502. res = expr_run(expr->stack_sz, args, expr->stack);
  503. return res;
  504. }
  505. void rpn_expr_close(rpn_expr_t* expr)
  506. {
  507. if(expr->expr)
  508. {
  509. free(expr->expr);
  510. expr->expr = NULL;
  511. }
  512. if(expr->stack)
  513. {
  514. free(expr->stack);
  515. expr->stack = NULL;
  516. }
  517. if(expr->code_map)
  518. {
  519. if(munmap(expr->code_map, expr->code_map_sz))
  520. {
  521. perror("Unable to unmap code_map");
  522. }
  523. expr->code_map = NULL;
  524. }
  525. }
  526. void rpn_expr_reset_stack(rpn_expr_t *expr)
  527. {
  528. bzero(expr->stack, sizeof(unsigned long) * expr->stack_sz);
  529. }
  530. int _rpn_expr_token_copy(rpn_expr_t *expr, rpn_token_t *token)
  531. {
  532. unsigned long int *value;
  533. rpn_op_t local_op;
  534. value = NULL;
  535. switch(token->type)
  536. {
  537. case RPN_op:
  538. local_op = *(token->op);
  539. value = NULL;
  540. break;
  541. case RPN_arg:
  542. if(expr->args_count <= token->arg_n)
  543. {
  544. errno = EINVAL;
  545. return -1;
  546. }
  547. local_op.fun = &rpn_arg;
  548. local_op.fun_sz = &(CODE_SZ(rpn_arg));
  549. value = &(token->arg_n);
  550. break;
  551. case RPN_val:
  552. local_op.fun = &rpn_value;
  553. local_op.fun_sz = &(CODE_SZ(rpn_value));
  554. value = &(token->value);
  555. break;
  556. default:
  557. errno = EUCLEAN;
  558. return -1;
  559. }
  560. if(_rpn_code_part_cpy(expr, local_op.fun, *(local_op.fun_sz),
  561. value))
  562. {
  563. return -1;
  564. }
  565. return 0;
  566. }
  567. int _rpn_code_part_cpy(rpn_expr_t *expr, const void *code_part,
  568. unsigned long code_part_sz, const unsigned long *value)
  569. {
  570. size_t old_sz, code_sz;
  571. void *new_ptr;
  572. //printf("DEBUG _copy : %p %ld %p:%ld\n", code_part, code_part_sz, value, value?*value:0);
  573. code_sz = expr->code_map_ptr - expr->code_map;
  574. if(!expr->code_map_sz)
  575. {
  576. errno = EINVAL;
  577. return -1;
  578. }
  579. if(code_sz + code_part_sz >= expr->code_map_sz)
  580. {
  581. old_sz = expr->code_map_sz;
  582. expr->code_map_sz = (((code_sz + code_part_sz)>>9)+1)<<9;
  583. new_ptr = mremap(expr->code_map, old_sz, expr->code_map_sz,
  584. MREMAP_MAYMOVE);
  585. if(new_ptr == (void*)-1)
  586. {
  587. expr->code_map_sz = 0;
  588. return -1;
  589. }
  590. expr->code_map = new_ptr;
  591. expr->code_map_ptr = expr->code_map + code_sz;
  592. }
  593. memcpy(expr->code_map_ptr, code_part, code_part_sz);
  594. if(value)
  595. {
  596. // set 1st instruction argument
  597. *(unsigned long*)(expr->code_map_ptr + 2) = *value;
  598. }
  599. expr->code_map_ptr += code_part_sz;
  600. return 0;
  601. }
  602. int _rpn_expr_init_map(rpn_expr_t* expr)
  603. {
  604. if(!expr->code_map_sz)
  605. {
  606. expr->code_map_sz = RPN_MAP_CHUNK;
  607. expr->code_map = mmap(NULL, expr->code_map_sz, PROT_READ | PROT_WRITE,
  608. MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  609. if(!expr->code_map)
  610. {
  611. return -1;
  612. }
  613. }
  614. expr->code_map_ptr = expr->code_map;
  615. if(CODE_PART_CPY(expr, rpn_exec))
  616. {
  617. return -1;
  618. }
  619. return 0;
  620. }
  621. int _rpn_expr_end_map(rpn_expr_t *expr)
  622. {
  623. if(CODE_PART_CPY(expr, rpn_exec_ret))
  624. {
  625. return -1;
  626. }
  627. if(mprotect(expr->code_map, expr->code_map_ptr - expr->code_map,
  628. PROT_EXEC))
  629. {
  630. return -1;
  631. }
  632. return 0;
  633. }
  634. int _rpn_expr_reset_map(rpn_expr_t *expr)
  635. {
  636. if(!expr->code_map_sz)
  637. {
  638. return _rpn_expr_init_map(expr);
  639. }
  640. if(mprotect(expr->code_map, expr->code_map_sz,
  641. PROT_READ | PROT_WRITE))
  642. {
  643. return -1;
  644. }
  645. bzero(expr->code_map, expr->code_map_sz);
  646. return 0;
  647. }