compile.rs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. use std::i64;
  2. use super::{ir, optimize};
  3. use std::io::{Write, Read};
  4. use std::mem;
  5. use super::ir::{ConstVisitor, Instruction};
  6. #[cfg(target_os = "windows")]
  7. use winapi::um::memoryapi::VirtualAlloc;
  8. #[cfg(target_os = "windows")]
  9. use winapi::um::winnt::{MEM_COMMIT, PAGE_EXECUTE_READWRITE};
  10. use dynasmrt::{DynasmApi, DynasmLabelApi};
  11. pub enum Storation {
  12. Register(&'static str),
  13. Stack(i64),
  14. }
  15. pub fn compile_cfg<'a>(cfg: Vec<optimize::DfInstr<'a>>) -> Box<fn (*mut u8) -> ()> {
  16. Box::new(|_| {})
  17. }
  18. pub fn compile(instrs: &Vec<ir::Instruction>) -> Vec<u8> {
  19. let mut cg = CodeGenerator::new();
  20. cg.initialize();
  21. let entry = cg.buffer.offset();
  22. cg.visit_instructions(instrs);
  23. cg.buffer.commit();
  24. cg.finalize();
  25. let buf = cg.buffer.finalize().unwrap();
  26. //let ret = buf.to_vec();
  27. //println!("{:02x?}", ret);
  28. let function: extern "C" fn(memory: *mut u8) -> bool = unsafe {
  29. //mem::transmute(cg.get_callable())
  30. mem::transmute(buf.ptr(entry))
  31. };
  32. //let mut data: Vec<u8> = Vec::with_capacity(100000);
  33. unsafe {
  34. //function(&mut *data.into_boxed_slice().as_mut_ptr() as *mut u8);
  35. function(std::alloc::alloc_zeroed(std::alloc::Layout::new::<[u8; 100000]>()));
  36. }
  37. //cg.into_vec()
  38. //ret
  39. vec![]
  40. }
  41. pub struct CodeGenerator {
  42. pub buffer: dynasmrt::x64::Assembler
  43. }
  44. impl CodeGenerator {
  45. pub fn new() -> Self {
  46. CodeGenerator {
  47. buffer: dynasmrt::x64::Assembler::new().unwrap()
  48. }
  49. }
  50. pub fn initialize(&mut self) {
  51. dynasm!(self.buffer
  52. ; xor rsi, rsi
  53. );
  54. }
  55. pub fn finalize(&mut self) {
  56. dynasm!(self.buffer
  57. ; ret
  58. );
  59. }
  60. #[cfg(target_os = "windows")]
  61. pub fn get_callable(self) -> *const u8 {
  62. let data = self.buffer.finalize().unwrap().to_vec();
  63. println!("asm buffer of size {}", data.len());
  64. let ex = unsafe { VirtualAlloc(0 as _, data.len(), MEM_COMMIT, PAGE_EXECUTE_READWRITE) };
  65. unsafe {
  66. std::ptr::copy_nonoverlapping(data.as_ptr(), ex as _, data.len());
  67. }
  68. ex as _
  69. }
  70. #[cfg(not(target_os = "windows"))]
  71. pub fn get_callable(self) {
  72. }
  73. }
  74. impl ir::ConstVisitor for CodeGenerator {
  75. type Ret = ();
  76. fn visit_nop(&mut self, nop: &Instruction) {
  77. }
  78. fn visit_add(&mut self, add: &'_ Instruction) {
  79. if let Instruction::Add{ offset, value } = add {
  80. dynasm!(self.buffer
  81. ; add BYTE [rdi + *offset as i32], *value as i8
  82. );
  83. }
  84. }
  85. fn visit_set(&mut self, set: &'_ Instruction) {
  86. if let Instruction::Set{ offset, value } = set {
  87. dynasm!(self.buffer
  88. ; mov BYTE [rdi + *offset as i32], *value as i8
  89. );
  90. }
  91. }
  92. fn visit_linear_loop(&mut self, l: &Instruction) {
  93. if let Instruction::LinearLoop(factors) = l {
  94. if factors.len() > 1 ||
  95. factors.len() >= 1 && !factors.contains_key(&0) {
  96. dynasm!(self.buffer
  97. ; mov cl, BYTE [rdi]
  98. );
  99. }
  100. for (&offset, &factor) in factors {
  101. if offset == 0 {
  102. continue;
  103. }
  104. if factor == 0 {
  105. }
  106. else if factor == 1 {
  107. dynasm!(self.buffer
  108. ; add BYTE [rdi + offset as i32], cl
  109. );
  110. }
  111. else if factor == -1 {
  112. dynasm!(self.buffer
  113. ; sub BYTE [rdi + offset as i32], cl
  114. );
  115. }
  116. else if factor.count_ones() == 1 {
  117. dynasm!(self.buffer
  118. ; mov bl, cl
  119. ; shl bl, factor.trailing_zeros() as i8
  120. ; add BYTE [rdi + offset as i32], bl
  121. );
  122. }
  123. else if (-factor).count_ones() == 1 {
  124. dynasm!(self.buffer
  125. ; mov bl, cl
  126. ; shl bl, factor.trailing_zeros() as i8
  127. ; sub BYTE [rdi + offset as i32], bl
  128. );
  129. }
  130. else {
  131. dynasm!(self.buffer
  132. ; mov al, factor as i8
  133. ; mul cl
  134. ; add BYTE [rdi + offset as i32], al
  135. );
  136. }
  137. }
  138. dynasm!(self.buffer
  139. ; mov BYTE [rdi], 0
  140. );
  141. }
  142. }
  143. fn visit_move_ptr(&mut self, mp: &Instruction) {
  144. if let Instruction::MovePtr(offset) = mp {
  145. dynasm!(self.buffer
  146. ; lea rdi, [rdi + *offset as i32]
  147. );
  148. }
  149. }
  150. fn visit_loop(&mut self, l: &Instruction) {
  151. if let Instruction::Loop(insts) = l {
  152. let begin = self.buffer.new_dynamic_label();
  153. let end = self.buffer.new_dynamic_label();
  154. dynasm!(self.buffer
  155. ; cmp BYTE [rdi], 0
  156. ; jz => end
  157. ; => begin
  158. );
  159. self.visit_instructions(insts);
  160. dynasm!(self.buffer
  161. ; cmp BYTE [rdi], 0
  162. ; jnz => begin
  163. ; => end
  164. );
  165. }
  166. }
  167. fn visit_read(&mut self, r: &Instruction) {
  168. if let Instruction::Read(offset) = r {
  169. dynasm!(self.buffer
  170. ; push rdi
  171. ; push rsi
  172. ; sub rsp, 24
  173. ; mov rax, QWORD readbyte as _
  174. ; call rax
  175. ; add rsp, 24
  176. ; pop rsi
  177. ; pop rdi
  178. ; mov BYTE [rdi + *offset as i32], al
  179. );
  180. }
  181. }
  182. fn visit_write(&mut self, w: &Instruction) {
  183. if let Instruction::Write(offset) = w {
  184. dynasm!(self.buffer
  185. ; push rdi
  186. ; push rsi
  187. ; sub rsp, 24
  188. ; mov dil, BYTE [rdi + *offset as i32]
  189. ; mov rax, QWORD putbyte as _
  190. ; call rax
  191. ; add rsp, 24
  192. ; pop rsi
  193. ; pop rdi
  194. );
  195. }
  196. }
  197. }
  198. extern "C" fn putbyte(chr: u8) {
  199. //print!("{:?}", chr as char);
  200. std::io::stdout().write(&[chr]);
  201. }
  202. extern "C" fn readbyte() -> u8 {
  203. let mut byte: u8 = 0;
  204. //std::io::stdin().read(&mut [byte]).unwrap();
  205. std::io::stdin().bytes().next().unwrap_or(Ok(0)).unwrap_or(0)
  206. }