Brainfuck compiler for linux x86_64 written in nasm x86_64
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.

bfc.asm 18KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  1. ; bfc : a brainfuck compiler & interpreter
  2. ; Copyright (C) 2018 Weber Yann
  3. ;
  4. ; This program is free software; you can redistribute it and/or modify
  5. ; it under the terms of the GNU General Public License as published by
  6. ; the Free Software Foundation; either version 3 of the License, or
  7. ; any later version.
  8. ;
  9. ; This program is distributed in the hope that it will be useful,
  10. ; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. ; GNU General Public License for more details.
  13. ;
  14. ; You should have received a copy of the GNU General Public License
  15. ; along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. ;
  17. ; A brainfuck compiler & interpreter :
  18. ; Build : nasm -felf64 bfc.asm && ld -s -melf_x86_64 bfc.o -o bfc
  19. ;
  20. ; ./bfc [-h] [-e [-o a.out]] FILE.bf
  21. ; Options :
  22. ; -h print usage and exit
  23. ; -e tell bfc to produce a elf file
  24. ; -o with -e indicate the file to create
  25. ; FILE.bf the brainfuck source file to compile
  26. [bits 64]
  27. %use smartalign
  28. ALIGNMODE k8
  29. %define lbl_incresize 0x2e
  30. %define lbl_decresize 0x50
  31. %define MAP_INC_SIZE 0x1000
  32. %define MAP_INC_MASK 0x0FFF
  33. %define BFMEM_INIT_SZ MAP_INC_SIZE
  34. %define ELF_CODE_OFFSET 0x00400080
  35. section .data
  36. bf_start:
  37. jmp .start
  38. .mremap:
  39. ; Resize the mmap
  40. ; rbx is resize min size
  41. ; rdi is map ptr offset
  42. ; r14 is map_len
  43. ; r15 is map_addr
  44. ; Returns :
  45. ; r15 new map_addr
  46. ; r14 new map_len
  47. ; rdi map ptr offset
  48. ; rsi map ptr
  49. push rdi
  50. ; set min resize
  51. xor rdx, rdx
  52. .loop_min_remap:
  53. add rdx, MAP_INC_SIZE
  54. cmp rdx, rbx
  55. jl .loop_min_remap
  56. add r14, rdx ; newlen
  57. mov rax, 0x19 ; mremap
  58. mov rdi, r15 ; addr
  59. mov rsi, r14 ; oldlen
  60. jc .erremap ; overflow, too much mem !!!!
  61. mov rdx, r14 ; newlen
  62. xor r10, r10 ; maymove
  63. xor r11, r11
  64. syscall
  65. cmp rax, 0
  66. jle .erremap
  67. mov r15, rax
  68. ; restore rsi & rdi
  69. pop rdi
  70. mov rsi, r15
  71. add rsi, rdi
  72. ret
  73. .erremap:
  74. mov rax, 0x3c
  75. mov rdi, 0x2
  76. syscall
  77. align 8
  78. .lbl_incresize: equ $ - bf_start
  79. .incresize:
  80. ; Resize the map on ptr increment
  81. ; rbx is increment count
  82. ; rdi is map ptr offset
  83. ; r14 is map_len
  84. ; r15 is map_addr
  85. call .mremap
  86. ret
  87. align 8
  88. .lbl_decresize: equ $ - bf_start
  89. .decresize:
  90. ; Resize the map on ptr decrement
  91. ; rbx is decrement count
  92. ; rdi is map ptr offset
  93. ; r14 is map_len
  94. ; r15 is map_addr
  95. ; Note : data has to be shifted
  96. push r14 ; old map len
  97. call .incresize
  98. ; shift datas
  99. pop rcx ; old len
  100. mov rbx, r14 ; new_len
  101. push rsi
  102. push rdi
  103. mov rsi, r15
  104. mov rdi, rsi
  105. add rsi, rcx ; add old_len to map_ptr
  106. add rdi, rbx ; add new_len to map_ptr
  107. sub rbx, rcx ; new_len - old_len : resize
  108. std ; set DF to dec rsi & rdi
  109. .decresize_shift:
  110. movsb
  111. loop .decresize_shift
  112. ; set first map bytes to 0
  113. mov rdi, r15
  114. add rdi, rbx
  115. dec rdi
  116. mov rcx, rbx
  117. .decresize_zeros:
  118. mov byte [rdi], 0x0
  119. dec rdi
  120. loop .decresize_zeros
  121. pop rdi
  122. pop rsi
  123. ; update map_ptr & offset given the shift
  124. add rdi, rbx
  125. add rsi, rbx
  126. ret
  127. .errmap:
  128. mov rax, 0x3c
  129. mov rdi, 0x1
  130. syscall
  131. .start:
  132. ;map init
  133. mov rax, 0x9 ;mmap
  134. xor rdi, rdi
  135. mov rsi, BFMEM_INIT_SZ ;len
  136. mov r14, rsi
  137. mov rdx, (0x1|0x2) ;PROT_READ | PROT_WRITE
  138. mov r10, (0x2 | 0x20) ;flags MAP_PRIVATE | MAP_ANONYMOUS
  139. mov r8, -1 ;fd
  140. xor r9, r9
  141. syscall
  142. cmp rax, 0
  143. jle .errmap
  144. ; Sets BF runtime :
  145. ; r14 is map len
  146. mov r15, rax ; r15 is map addr
  147. mov rdi, (BFMEM_INIT_SZ / 2) ; rdi is ptr idx
  148. mov rsi, r15
  149. add rsi, rdi ; rsi is bf ptr
  150. align 8
  151. bf_start_sz: equ $ - bf_start
  152. ; In piece of code the first instruction has to be a mov of
  153. ; a quadword in a register. This operation will be updated
  154. ; to "pass" a parameter
  155. ; rsi is map_ptr
  156. ; rdi is map ptr offset
  157. ; r14 is map_len
  158. ; r15 is map_addr
  159. bf_decptr:
  160. ; dec map ptr
  161. ; rbx is dec count
  162. mov rbx, strict qword 0x1
  163. push rbx
  164. cmp rdi, rbx
  165. jge .end
  166. mov rax, ELF_CODE_OFFSET + bf_start.lbl_decresize
  167. call rax
  168. ;call (ELF_CODE_OFFSET + bf_start.lbl_decresize)
  169. .end:
  170. pop rbx
  171. sub rsi, rbx
  172. sub rdi, rbx
  173. bf_decptr_sz: equ $ - bf_decptr
  174. bf_incptr:
  175. mov rbx, strict qword 0x1
  176. push rbx
  177. add rbx, rdi
  178. cmp rdi, r14
  179. jge .end
  180. mov rbx, [rsp]
  181. mov rax, ELF_CODE_OFFSET + bf_start.lbl_incresize
  182. call rax
  183. ;call (ELF_CODE_OFFSET + bf_start.lbl_incresize)
  184. .end:
  185. pop rbx
  186. add rsi, rbx
  187. add rdi, rbx
  188. bf_incptr_sz: equ $ - bf_incptr
  189. bf_incval:
  190. mov rbx, strict qword 0x1
  191. mov al,[rsi]
  192. add al, bl
  193. mov [rsi], al
  194. bf_incval_sz: equ $ - bf_incval
  195. bf_decval:
  196. mov rbx, strict qword 0x1
  197. mov al, [rsi]
  198. sub al, bl
  199. mov [rsi], al
  200. bf_decval_sz: equ $ - bf_decval
  201. bf_readval:
  202. mov rdx, strict qword 0x1
  203. push rdi
  204. push rsi
  205. xor rax, rax ; read
  206. xor rdi, rdi ; stdin
  207. syscall
  208. test rax, rax
  209. jnz .end
  210. mov byte [rsi], 0
  211. .end:
  212. pop rsi
  213. pop rdi
  214. bf_readval_sz: equ $ - bf_readval
  215. bf_writeval:
  216. mov rcx, strict qword 0x1
  217. push rdi
  218. push rsi
  219. .loop_write:
  220. push rcx
  221. mov rax, 1 ; write
  222. mov rdi, rax ; stdout
  223. mov rsi, [rsp+8]
  224. mov rdx, 1 ; 1 chr
  225. syscall
  226. pop rcx
  227. loop .loop_write
  228. pop rsi
  229. pop rdi
  230. bf_writeval_sz: equ $ - bf_writeval
  231. bf_loopstart:
  232. mov rbx, strict qword 0x1
  233. mov dl, [rsi]
  234. cmp dl, 0
  235. jnz .end
  236. jmp rbx
  237. .end:
  238. bf_loopstart_sz: equ $ - bf_loopstart
  239. bf_loopend:
  240. mov rbx, strict qword 0x1
  241. mov dl, [rsi]
  242. cmp dl, 0
  243. jz .end
  244. jmp rbx
  245. .end:
  246. bf_loopend_sz: equ $ - bf_loopend
  247. bf_exit:
  248. mov rax, 0x3c
  249. xor rdi, rdi
  250. syscall
  251. bf_exit_sz: equ $ - bf_exit
  252. elf_head: dw 0x457f, 0x464c, 0x0102, 0x0001,
  253. times 4 dw 0x0
  254. ; 0x10
  255. dw 0x0002, 0x003e, 0x0001, 0x0000
  256. dw 0x080, 0x040, 0x0, 0x0
  257. ; 0x20
  258. dw 0x0040
  259. times 3 dw 0x0
  260. elf_section_head_offset : times 8 db 0xFF ; 0x28
  261. ; 0x30
  262. dw 0x0, 0x0, 0x40, 0x38, 0x1, 0x40, 0x3, 0x2
  263. ; 0x40 section header
  264. dw 0x1, 0x0, 0x5 ; load in memory with RX perm
  265. times 5 dw 0x0
  266. ; 0x50
  267. dw 0x0, 0x40, 0, 0, 0, 0x40, 0, 0 ; load at 0x40000
  268. ; 0x60
  269. elf_prog_sz: times 16 db 0xFF ; 0x60 & 0x 68
  270. ; 0x70
  271. dw 0x0, 0x20
  272. times 6 dw 0x0
  273. elf_head_sz: equ $ - elf_head
  274. elf_shstrtab: db ".shstrtab", 0x0, ".text", 0x0
  275. align 8
  276. elf_shstrtab_sz: equ $ - elf_shstrtab
  277. elf_section_headers: times 8 dq 0x0 ; head0
  278. ; head 1
  279. dw 0xb, 0, 0x1, 0, 0x6, 0, 0, 0
  280. dw 0x80, 0x40, 0, 0, 0x80, 0, 0, 0
  281. elf_section_text_sz: times 8 db 0xFF
  282. dq 0x0
  283. dw 0x10
  284. times 7 dw 0x0
  285. ; head2
  286. dw 0x1, 0, 0x3 , 0, 0, 0, 0, 0
  287. dq 0x0
  288. elf_section_strtab_off: times 8 db 0xFF
  289. dw 0x11
  290. times 7 dw 0x0
  291. dw 0x1
  292. times 7 dw 0x0
  293. elf_section_headers_sz: equ $ - elf_section_headers
  294. default_output: db "a.out", 0x0
  295. miss_open: db "Missing opening '[' matching closing ']'"
  296. miss_open_sz: equ $ - miss_open
  297. chr_list : db ": ", 0xA, 0x0
  298. read_error: db "Error reading file "
  299. read_error_sz: equ $ - read_error
  300. usage_err: db "Usage : [-e [-o a.out]] FILE.BF"
  301. usage_err_sz: equ $ - usage_err
  302. open_err: db "Error opening file", 0xa
  303. open_err_sz: equ $ - open_err
  304. section .text
  305. global _start
  306. _start:
  307. ; using heap to store arguments
  308. %define bf_source [r13]
  309. %define elf_file [r13+0x8]
  310. %define elf_out [r13+0x11]
  311. %define heap_size 0x12
  312. mov rax, 0xc
  313. xor rdi, rdi
  314. syscall
  315. mov rdi, rax
  316. mov r13, rax ; heap start
  317. add rdi, heap_size
  318. mov rax, 0xc
  319. syscall
  320. ;argument parsing
  321. mov rcx, [rsp] ; argc
  322. cmp rcx, 2
  323. jl .badarg
  324. je .init_1arg
  325. cmp rcx, 5
  326. jg .badarg
  327. mov rsi, rsp
  328. add rsi, 8 ; argv[0]
  329. dec rcx
  330. .argloop:
  331. add rsi, 8
  332. mov rdi, [rsi]
  333. mov al, [rdi]
  334. cmp al, 0x2d ; '-'
  335. jne .filearg
  336. mov al, [rdi+2]
  337. test al, al
  338. jnz .filearg
  339. ; arg is '-X' testing X
  340. mov al, [rdi+1]
  341. cmp al, 0x68 ; '-h'
  342. je .badarg
  343. cmp al, 0x65 ; '-e'
  344. je .elfout_arg
  345. cmp al, 0x6f ; '-o'
  346. jne .badarg
  347. ; -o storing file
  348. test rcx, rcx
  349. jz .badarg ; no more args
  350. dec rcx
  351. add rsi, 8
  352. mov rdi, [rsi]
  353. mov elf_file, rdi
  354. loop .argloop
  355. jmp .init
  356. .elfout_arg:
  357. mov al, 0x1
  358. mov elf_out, al
  359. mov rax, elf_file
  360. test rax, rax
  361. jz .default_out
  362. .elfout_arg_end:
  363. loop .argloop
  364. jmp .init
  365. .default_out:
  366. mov rax, default_output
  367. mov elf_file, rax
  368. jmp .elfout_arg_end
  369. .filearg:
  370. mov rax, bf_source
  371. cmp rax, 0
  372. .br3:
  373. jnz .badarg ; file allready given
  374. mov bf_source, rdi
  375. loop .argloop
  376. jmp .init
  377. .init_1arg:
  378. mov rax, [rsp+16]
  379. mov bf_source, rax
  380. .init:
  381. ; code map init
  382. ; rsi map size
  383. mov rsi, 0x10
  384. call initmap
  385. mov rax, 0x2 ; open
  386. mov rdi, bf_source ; from heap
  387. test rdi, rdi
  388. jz .badarg
  389. xor rsi, rsi ; O_RDONLY
  390. xor rdx, rdx ; no mode
  391. syscall
  392. cmp rax, 0
  393. jl .err_open
  394. push rax ; fd
  395. push r13 ; heap
  396. call compile_bf
  397. pop r13 ; heap
  398. pop rdi ; fd
  399. sub rax, r15
  400. push rax ; map len
  401. mov rax, 0x3 ; close
  402. syscall
  403. mov al, elf_out
  404. test al, al
  405. jnz .write_elf
  406. .code_jmp:
  407. ; restore heap
  408. mov rax, 0xc
  409. mov rdi, r13
  410. syscall
  411. ; set code map perm
  412. mov rax, 0xA ; mprotect
  413. mov rdi, r15
  414. mov rsi, r14
  415. mov rdx, 0x4 | 0x1 ; PROT_EXEC | PROT_READ
  416. syscall
  417. push r15
  418. jmp r15 ; end... jumping in bf code map
  419. .write_elf: ; writing elf file
  420. mov rax, [rsp] ; map len
  421. mov [elf_section_text_sz], rax
  422. add rax, elf_head_sz ; elf head + map_ptr
  423. mov [elf_head + 0x60], rax
  424. mov [elf_head + 0x68], rax
  425. mov [elf_section_strtab_off], rax
  426. add rax, elf_shstrtab_sz ; section head offset
  427. xor r14, r14 ; store align padding for section header
  428. xor rbx, rbx
  429. mov bl, al
  430. and bl, 0x0F
  431. test bl, bl
  432. jz .aligned_section
  433. mov r14, 0x10
  434. sub r14, rbx
  435. and al, 0xF0
  436. add rax, 0x10
  437. .aligned_section:
  438. mov [elf_head + 0x28], rax
  439. mov rax, 0x2
  440. mov rdi, elf_file
  441. mov rsi, 0x40 | 0x200 | 0x1 ; O_CREAT | O_TRUNC | O_WRONLY
  442. mov rdx, 755o ; perm
  443. syscall
  444. cmp rax, 0
  445. jl .err_open
  446. push rax ; fd
  447. mov rax, 1
  448. mov rdi, [rsp]
  449. mov rsi, elf_head
  450. mov rdx, elf_head_sz
  451. syscall
  452. mov rax, 1
  453. mov rdi, [rsp]
  454. mov rsi, r15 ; map_addr
  455. mov rdx, [rsp+8] ; map len
  456. syscall
  457. mov rax, 1
  458. mov rdi, [rsp]
  459. mov rsi, elf_shstrtab
  460. mov rdx, elf_shstrtab_sz
  461. syscall
  462. .padloop:
  463. test r14, r14
  464. jz .end_padloop
  465. mov rax, 1
  466. mov rdi, [rsp]
  467. mov rsi, elf_section_headers ; 0x0
  468. mov rdx, 1
  469. syscall
  470. dec r14
  471. jmp .padloop
  472. .end_padloop:
  473. mov rax, 1
  474. mov rdi, [rsp]
  475. mov rsi, elf_section_headers
  476. mov rdx, elf_section_headers_sz
  477. syscall
  478. pop rdi ; fd
  479. mov rax, 0x3 ; close
  480. syscall
  481. pop rax ; map_len
  482. mov rax, 0x3c ; exit
  483. xor rdi, rdi
  484. syscall
  485. .err_open:
  486. mov rax, 1 ; write
  487. mov rdi, 2 ; stderr
  488. mov rsi, open_err
  489. mov rdx, open_err_sz
  490. syscall
  491. .badarg:
  492. mov rax, 1 ;write
  493. mov rdi, 2 ; stderr
  494. mov rsi, usage_err
  495. mov rdx, 8 ; "Usage : "
  496. syscall
  497. mov rsi, [rsp+8] ; argv[0]
  498. xor rdx, rdx
  499. xor rcx, rcx
  500. .argv0len:
  501. inc rsi
  502. inc rdx
  503. mov cl, [rsi]
  504. test cl, cl
  505. jnz .argv0len
  506. mov rax, 1
  507. mov rdi, 2
  508. mov rsi, [rsp+8] ; argv[0]
  509. syscall
  510. mov rax, 1 ;write
  511. mov rdi, 2 ; stderr
  512. mov rsi, usage_err + 7
  513. mov rdx, usage_err_sz - 7 ; usage opts
  514. syscall
  515. mov rax, 1
  516. mov rdi, 2
  517. mov rsi, chr_list + 2 ; \n
  518. mov rdx, 1
  519. syscall
  520. mov rax, 0x3c ; exit
  521. mov rdi, 1
  522. syscall
  523. %undef heap_size
  524. %undef elf_file
  525. %undef bf_source
  526. ; Init a writable memory map
  527. ; len in rsi
  528. ; ret : r14 map size
  529. ; r15 map addr
  530. initmap:
  531. mov r14, rsi
  532. mov rax, 0x9 ;mmap
  533. xor rdi, rdi ;addr
  534. ; rsi is len
  535. mov rdx, (0x1|0x2) ;PROT_READ | PROT_WRITE
  536. mov r10, (0x2 | 0x20) ;flags MAP_PRIVATE | MAP_ANONYMOUS
  537. mov r8, -1 ;fd
  538. xor r9, r9
  539. syscall
  540. cmp rax, 0
  541. jle .err
  542. mov r15, rax
  543. ret
  544. .err:
  545. mov rax, 0x3c
  546. mov rdi, 0x2
  547. syscall
  548. ; resize the memory map
  549. ; addr in r15 (0 if init)
  550. ; len in r14
  551. ; inc size in bytes in r10
  552. mremap:
  553. mov rax, 0x19 ;mremap
  554. mov rdi, r15 ;addr
  555. mov rsi, r14 ;oldlen
  556. mov rdx, rsi
  557. add rdx, MAP_INC_SIZE ; newlen
  558. xor r10, r10 ; MAYMOVE
  559. xor r11, r11
  560. syscall
  561. cmp rax, 0
  562. jle .err
  563. mov r15, rax
  564. add r14, MAP_INC_SIZE
  565. ret
  566. .err:
  567. mov rax, 0x3c
  568. mov rdi, 0x3
  569. syscall
  570. ; JIT brainfuck compiler. Read bf code from fd and write
  571. ; machine code in a dedicated anon map with PROT_READ | PROT_EXEC
  572. ; Using heap to read file
  573. ; args :
  574. ; rax source fd
  575. ; r14 map size
  576. ; r15 map addr
  577. ; ret :
  578. ; rax map ptr
  579. ; r15 map addr
  580. ; r14 map size
  581. compile_bf:
  582. ; Allocating growing heap to store various datas
  583. ; heap start will be stored in r13
  584. %define fd [r13]
  585. %define map_ptr [r13+0x8]
  586. %define base_rsp [r13+0x10]
  587. %define chr_repeat [r13+0x18]
  588. %define line_count [r13+0x20]
  589. %define chr_count [r13+0x28]
  590. %define chr_buff_off 0x30
  591. %define chr_buff [r13+chr_buff_off]
  592. %define prev_chr_off 0x31
  593. %define prev_chr [r13+prev_chr_off]
  594. %define heap_size 0x32
  595. push rax ; source fd
  596. mov rax, 0xc ; brk
  597. xor rdi, rdi
  598. syscall
  599. push rax ; heap start
  600. mov rdi, rax
  601. add rdi, heap_size ; new heap addr
  602. mov rax, 0xc ; brk
  603. syscall
  604. pop rdi ; heap start
  605. mov r13, rdi
  606. pop rax ; source fd
  607. mov fd, rax
  608. ; init heap
  609. mov byte prev_chr, 0
  610. mov qword chr_count, 0
  611. mov qword line_count, 0
  612. mov qword chr_repeat, 1
  613. mov base_rsp, rsp ; save rsp in heap
  614. ; copy code map header
  615. mov rdi, r15
  616. mov rsi, bf_start
  617. mov rdx, bf_start_sz
  618. call code_cpy
  619. mov map_ptr, rax ; new map ptr
  620. ; read first char in prev_chr
  621. xor rax, rax ;read
  622. mov rdi, fd ; fd
  623. mov rsi, r13
  624. add rsi, prev_chr_off ; chr_prev
  625. mov rdx, 1 ; read 1 byte
  626. syscall
  627. cmp rax, 0
  628. jle .read_error
  629. .readloop:
  630. xor rax, rax ;read
  631. mov rdi, fd ; fd
  632. mov rsi, r13
  633. add rsi, chr_buff_off ; buff byte
  634. mov rdx, 1 ; read 1 byte
  635. syscall
  636. cmp rax, 0
  637. je .endread
  638. jl .read_error ; error
  639. mov rax, chr_count ; chr counter
  640. inc rax
  641. mov chr_count, rax
  642. mov al, chr_buff
  643. ; arg for loop is not a repeat counter
  644. cmp al, 0x5b ; '['
  645. je .cmpchar
  646. cmp al, 0x5d ; '['
  647. je .cmpchar
  648. cmp al, prev_chr
  649. je .incnum ; same instruction, incrementing counter
  650. .cmpchar:
  651. mov rdi, map_ptr ; prepare to copy in code map
  652. ; compare previous char and store current in prev
  653. ; note : chr_repeat has to be reset by .nxtinstr
  654. ; after jump
  655. xchg prev_chr, al
  656. cmp al, 0x3c ; '<'
  657. je .lptr
  658. cmp al, 0x3e ; '>'
  659. je .rptr
  660. cmp al, 0x2b ; '+'
  661. je .incval
  662. cmp al, 0x2d ; '-'
  663. je .decval
  664. cmp al, 0x2e ; '.'
  665. je .wrval
  666. cmp al, 0x2c ; ','
  667. je .rdval
  668. cmp al, 0x5b ; '['
  669. je .loopstart
  670. cmp al, 0x5d ; ']'
  671. je .loopend
  672. cmp al, 0x0a ; '\n'
  673. je .line
  674. ; chr is not an instruction, printing them
  675. ; on stderr
  676. mov chr_buff, al
  677. mov rcx, chr_repeat
  678. .errchr:
  679. push rcx
  680. mov rax, 1 ; write
  681. mov rdi, 2 ; stderr
  682. mov rsi, r13
  683. add rsi, chr_buff_off ; heap buff
  684. mov rdx, rax ; sz 1
  685. syscall
  686. pop rcx
  687. loop .errchr
  688. jmp .nxtinstr
  689. .line: ; increment line counter in heap
  690. mov rax, line_count
  691. add rax, chr_repeat
  692. mov line_count, rax
  693. mov rcx, chr_repeat
  694. jmp .errchr ; print the newline
  695. ; following ref copy assume rdi to be map_ptr
  696. .incval:
  697. mov rsi, bf_incval
  698. mov rdx, bf_incval_sz
  699. push rdx
  700. jmp .callcpy
  701. .decval:
  702. mov rsi, bf_decval
  703. mov rdx, bf_decval_sz
  704. push rdx
  705. jmp .callcpy
  706. .lptr:
  707. mov rsi, bf_decptr
  708. mov rdx, bf_decptr_sz
  709. push rdx
  710. jmp .callcpy
  711. .rptr:
  712. mov rsi, bf_incptr
  713. mov rdx, bf_incptr_sz
  714. push rdx
  715. jmp .callcpy
  716. .wrval:
  717. mov rsi, bf_writeval
  718. mov rdx, bf_writeval_sz
  719. push rdx
  720. jmp .callcpy
  721. .rdval:
  722. mov rsi, bf_readval
  723. mov rdx, bf_readval_sz
  724. push rdx
  725. jmp .callcpy
  726. .loopstart:
  727. mov rbx, map_ptr
  728. sub rbx, r15
  729. push rbx ; loop offset from map start
  730. ;push qword map_ptr ; ret addr
  731. mov rsi, bf_loopstart
  732. mov rdx, bf_loopstart_sz
  733. push rdx
  734. jmp .callcpy
  735. .loopend:
  736. cmp rsp, base_rsp
  737. je .loop_err_miss_open
  738. mov rsi, bf_loopend
  739. mov rdx, bf_loopend_sz
  740. push rdx
  741. call code_cpy
  742. mov map_ptr, rax ; rax is map_ptr
  743. mov rdi, rax
  744. pop rdx ; bf_loopend_sz
  745. lea rdi, [rax + 2]
  746. sub rdi, rdx ; arg addr for loop_end : map_ptr - loopend_sz
  747. pop rbx ; loop_start code offset
  748. lea rax, [rbx+ELF_CODE_OFFSET] ; jmp to loop_start in loop_end
  749. mov [rdi], rax
  750. .br1:
  751. mov rax, map_ptr
  752. sub rax, r15 ; map_ptr - map_addr : map_offset of loop_end nxt instr
  753. lea rdi, [rbx + r15 + 2] ; arg addr for loop_start in map
  754. lea rax, [rax + ELF_CODE_OFFSET]
  755. .br2:
  756. mov [rdi], rax
  757. .br3:
  758. jmp .nxtinstr
  759. .callcpy:
  760. call code_cpy
  761. mov map_ptr, rax
  762. ; set the 1st instr rgs in the mapping
  763. ; and reinit chr_repeat
  764. pop rdx
  765. sub rax, rdx
  766. add rax, 2 ; arg addr in code map
  767. mov rbx, chr_repeat
  768. mov [rax], rbx
  769. .nxtinstr:
  770. ; reinit chr_repeat
  771. mov qword chr_repeat, 1
  772. jmp .readloop
  773. .incnum:
  774. ; same instruction found incrementing
  775. ; chr_repeat
  776. mov rbx, chr_repeat
  777. inc rbx
  778. jc .incoverflow
  779. mov chr_repeat, rbx
  780. jmp .readloop
  781. .incoverflow:
  782. dec rbx
  783. mov chr_repeat, rbx
  784. jmp .cmpchar
  785. jmp .readloop
  786. .loop_err_miss_open:
  787. ; miss_open_err
  788. mov rax, 1
  789. mov rdi, 2 ; stderr
  790. mov rsi, miss_open
  791. mov rdx, miss_open_sz
  792. syscall
  793. jmp .exit_error
  794. .read_error:
  795. xor rax, rax
  796. inc rax ; write
  797. mov rsi, 2 ; stderr
  798. mov rdi, read_error
  799. mov rdx, read_error_sz
  800. syscall
  801. jmp .exit_error
  802. .exit_error:
  803. mov rax, 1
  804. mov rdi, 2
  805. mov rsi, chr_list + 2
  806. mov rdx, 1
  807. syscall
  808. mov rax, 0x3c
  809. mov rdi, 0x11
  810. syscall
  811. .endread: ; EOF reached
  812. ; fake \0 read to process prev_chr
  813. mov byte chr_buff, 0
  814. mov bl, prev_chr
  815. test bl, bl
  816. jnz .cmpchar
  817. ; prevchar is 0 copying exit in code map
  818. .end_compile:
  819. mov rdi, map_ptr
  820. mov rsi, bf_exit
  821. mov rdx, bf_exit_sz
  822. call code_cpy
  823. mov map_ptr, rax
  824. ; restoring stack
  825. mov rsp, base_rsp
  826. push qword map_ptr
  827. ; restore heap
  828. mov rax, 0xc ; brk
  829. mov rdi, r13
  830. syscall
  831. pop rax ; return map_ptr
  832. ret
  833. %undef fd
  834. %undef map_ptr
  835. %undef base_rsp
  836. %undef chr_buff
  837. %undef prev_chr
  838. %undef heap_size
  839. ; Copy bf code from data to map
  840. ; Use :
  841. ; r15 map start
  842. ; r14 map size
  843. ; rdi map ptr
  844. ; rsi code ptr
  845. ; rdx code size in bytes
  846. ; ret :
  847. ; rax : new map ptr
  848. code_cpy:
  849. push rdx
  850. mov rax, rdi
  851. sub rax, r15 ; used len in map
  852. push rax
  853. mov rcx, rdx
  854. cmp rax, r14 ; rax is future len (after copy)
  855. jle .copy
  856. ; resize
  857. push rsi ; save code_ptr
  858. call mremap
  859. pop rsi ; new code_ptr
  860. .copy:
  861. mov rdi, r15
  862. pop rax
  863. add rdi, rax ; new map ptr
  864. pop rcx ; size in words to write
  865. cld ; clear DF
  866. .copyloop:
  867. movsb
  868. loop .copyloop
  869. mov rax, rdi
  870. .ret:
  871. ret