1use alloc::vec;
16use alloc::vec::Vec;
17
18#[derive(Clone, Copy)]
21struct InstBuf {
22 out: u128,
23 length: u32, }
25
26impl InstBuf {
27 #[inline(always)]
28 fn new() -> Self {
29 Self { out: 0, length: 0 }
30 }
31
32 #[inline(always)]
33 fn push(&mut self, byte: u8) {
34 self.out |= (byte as u128) << self.length;
35 self.length += 8;
36 }
37
38 #[inline(always)]
39 fn push_u32(&mut self, v: u32) {
40 self.out |= (v as u128) << self.length;
41 self.length += 32;
42 }
43
44 #[inline(always)]
45 fn push_u64(&mut self, v: u64) {
46 self.out |= (v as u128) << self.length;
47 self.length += 64;
48 }
49
50 #[inline(always)]
51 fn push_i32(&mut self, v: i32) {
52 self.push_u32(v as u32);
53 }
54
55 #[inline(always)]
56 fn len(&self) -> usize {
57 (self.length >> 3) as usize
58 }
59}
60
61#[derive(Clone, Copy, Debug, PartialEq, Eq)]
63#[repr(u8)]
64pub enum Reg {
65 RAX = 0,
66 RCX = 1,
67 RDX = 2,
68 RBX = 3,
69 RSP = 4,
70 RBP = 5,
71 RSI = 6,
72 RDI = 7,
73 R8 = 8,
74 R9 = 9,
75 R10 = 10,
76 R11 = 11,
77 R12 = 12,
78 R13 = 13,
79 R14 = 14,
80 R15 = 15,
81}
82
83impl Reg {
84 fn lo(self) -> u8 {
86 (self as u8) & 7
87 }
88 fn hi(self) -> u8 {
90 (self as u8) >> 3
91 }
92 fn needs_rex(self) -> bool {
94 (self as u8) >= 8
95 }
96}
97
98#[derive(Clone, Copy, Debug, PartialEq, Eq)]
100#[repr(u8)]
101pub enum Cc {
102 O = 0,
103 NO = 1,
104 B = 2, AE = 3, E = 4, NE = 5, BE = 6, A = 7, S = 8, NS = 9,
112 P = 10,
113 NP = 11,
114 L = 12, GE = 13, LE = 14, G = 15, }
119
120#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
122pub struct Label(pub u32);
123
124#[derive(Clone, Copy)]
126struct Fixup {
127 offset: usize,
129 label: Label,
131}
132
133pub struct Assembler {
138 code_buf: Vec<u8>,
139 buf: *mut u8,
141 write_pos: usize,
142 capacity: usize,
143 labels: Vec<u32>,
147 labels_len: usize,
150 fixups: Vec<Fixup>,
151 jit_va_base: u64,
156}
157
158const LABEL_UNBOUND: u32 = 0;
162
163impl Default for Assembler {
164 fn default() -> Self {
165 Self::new()
166 }
167}
168
169impl Assembler {
170 pub fn new() -> Self {
171 let mut code = Vec::with_capacity(4096);
172 let buf = code.as_mut_ptr();
173 let capacity = code.capacity();
174 Self {
175 code_buf: code,
176 buf,
177 write_pos: 0,
178 capacity,
179 labels: Vec::new(),
180 labels_len: 0,
181 fixups: Vec::new(),
182 jit_va_base: 0,
183 }
184 }
185
186 pub fn with_capacity(code_capacity: usize, label_capacity: usize) -> Self {
188 let mut code = Vec::with_capacity(code_capacity);
189 let buf = code.as_mut_ptr();
190 let capacity = code.capacity();
191 Self {
192 code_buf: code,
193 buf,
194 write_pos: 0,
195 capacity,
196 labels: vec![0u32; label_capacity],
198 labels_len: 0,
199 fixups: Vec::with_capacity(2048),
200 jit_va_base: 0,
201 }
202 }
203
204 pub fn set_jit_va_base(&mut self, va: u64) {
207 self.jit_va_base = va;
208 }
209
210 #[cold]
214 fn grow(&mut self, additional: usize) {
215 let code = &mut self.code_buf;
216 unsafe {
219 code.set_len(self.write_pos);
220 }
221 code.reserve(additional);
222 self.buf = code.as_mut_ptr();
223 self.capacity = code.capacity();
224 unsafe {
227 code.set_len(0);
228 }
229 }
230
231 #[inline(always)]
233 pub fn ensure_capacity(&mut self, n: usize) {
234 if self.write_pos + n > self.capacity {
235 self.grow(n);
236 }
237 }
238
239 pub fn new_label(&mut self) -> Label {
241 let id = self.labels_len as u32;
242 self.labels_len += 1;
243 if self.labels_len > self.labels.len() {
245 self.labels.push(LABEL_UNBOUND);
246 }
247 Label(id)
248 }
249
250 pub fn labels_len(&self) -> usize {
252 self.labels_len
253 }
254
255 pub fn bulk_create_labels(&mut self, count: usize) {
258 self.labels_len += count;
259 if self.labels_len > self.labels.len() {
261 self.labels.resize(self.labels_len, LABEL_UNBOUND);
262 }
263 }
264
265 pub fn bind_label(&mut self, label: Label) {
267 self.labels[label.0 as usize] = (self.write_pos + 1) as u32; }
269
270 pub fn offset(&self) -> usize {
272 self.write_pos
273 }
274
275 pub fn patch_i32(&mut self, offset: usize, value: i32) {
277 debug_assert!(offset + 4 <= self.write_pos);
278 unsafe {
280 core::ptr::copy_nonoverlapping(value.to_le_bytes().as_ptr(), self.buf.add(offset), 4);
281 }
282 }
283
284 #[inline(always)]
291 fn emit(&mut self, b: u8) {
292 debug_assert!(self.write_pos < self.capacity);
293 unsafe {
296 *self.buf.add(self.write_pos) = b;
297 }
298 self.write_pos += 1;
299 }
300
301 #[inline(always)]
303 fn emit3(&mut self, a: u8, b: u8, c: u8) {
304 debug_assert!(self.write_pos + 3 <= self.capacity);
305 unsafe {
308 let p = self.buf.add(self.write_pos);
309 *p = a;
310 *p.add(1) = b;
311 *p.add(2) = c;
312 }
313 self.write_pos += 3;
314 }
315
316 #[inline(always)]
318 fn flush_instbuf(&mut self, ib: InstBuf) {
319 let len = ib.len();
320 debug_assert!(self.write_pos + len <= self.capacity);
321 unsafe {
326 let p = self.buf.add(self.write_pos);
327 core::ptr::write_unaligned(p as *mut u64, ib.out as u64);
328 core::ptr::write_unaligned(p.add(8) as *mut u64, (ib.out >> 64) as u64);
329 }
330 self.write_pos += len;
331 }
332
333 #[inline(always)]
334 fn emit_u32(&mut self, v: u32) {
335 debug_assert!(self.write_pos + 4 <= self.capacity);
336 unsafe {
339 core::ptr::write_unaligned(self.buf.add(self.write_pos) as *mut u32, v.to_le());
340 }
341 self.write_pos += 4;
342 }
343
344 #[inline(always)]
345 fn emit_i32(&mut self, v: i32) {
346 debug_assert!(self.write_pos + 4 <= self.capacity);
347 unsafe {
350 core::ptr::write_unaligned(
351 self.buf.add(self.write_pos) as *mut u32,
352 v.to_le_bytes().as_ptr().cast::<u32>().read(),
353 );
354 }
355 self.write_pos += 4;
356 }
357
358 fn emit_label_fixup(&mut self, label: Label) {
362 let bound = self.labels[label.0 as usize];
363 if bound != LABEL_UNBOUND {
364 let target = (bound - 1) as i64;
367 let rel = target - (self.write_pos as i64 + 4);
368 self.emit_i32(rel as i32);
369 } else {
370 let offset = self.write_pos;
372 self.fixups.push(Fixup { offset, label });
373 self.emit_u32(0); }
375 }
376
377 fn rex_opt_b(&mut self, rm: Reg) {
380 if rm.needs_rex() {
381 self.emit(0x40 | rm.hi());
382 }
383 }
384
385 #[inline(always)]
388 fn modrm_disp_ib(ib: &mut InstBuf, reg: u8, base: Reg, disp: i32) {
389 let bl = base.lo();
390 let needs_sib = bl == 4;
391
392 if disp == 0 && bl != 5 {
393 if needs_sib {
394 ib.push((reg << 3) | 4);
395 ib.push(0x24);
396 } else {
397 ib.push((reg << 3) | bl);
398 }
399 } else if (-128..=127).contains(&disp) {
400 if needs_sib {
401 ib.push(0x40 | (reg << 3) | 4);
402 ib.push(0x24);
403 } else {
404 ib.push(0x40 | (reg << 3) | bl);
405 }
406 ib.push(disp as u8);
407 } else {
408 if needs_sib {
409 ib.push(0x80 | (reg << 3) | 4);
410 ib.push(0x24);
411 } else {
412 ib.push(0x80 | (reg << 3) | bl);
413 }
414 ib.push_i32(disp);
415 }
416 }
417
418 #[inline(always)]
424 pub fn mov_rr(&mut self, dst: Reg, src: Reg) {
425 if dst == src {
426 return;
427 }
428 self.emit3(
429 0x48 | (src.hi() << 2) | dst.hi(),
430 0x89,
431 0xC0 | (src.lo() << 3) | dst.lo(),
432 );
433 }
434
435 #[inline(always)]
437 pub fn mov_ri64(&mut self, dst: Reg, imm: u64) {
438 let mut ib = InstBuf::new();
439 if imm == 0 {
440 let r = dst.hi();
442 if r != 0 {
443 ib.push(0x40 | (r << 2) | r);
444 }
445 ib.push(0x31);
446 ib.push(0xC0 | (dst.lo() << 3) | dst.lo());
447 } else if imm <= u32::MAX as u64 {
448 if dst.needs_rex() {
450 ib.push(0x40 | dst.hi());
451 }
452 ib.push(0xB8 + dst.lo());
453 ib.push_u32(imm as u32);
454 } else if imm as i64 >= i32::MIN as i64 && imm as i64 <= i32::MAX as i64 {
455 ib.push(0x48 | dst.hi());
457 ib.push(0xC7);
458 ib.push(0xC0 | dst.lo());
459 ib.push_i32(imm as i32);
460 } else {
461 ib.push(0x48 | dst.hi());
463 ib.push(0xB8 + dst.lo());
464 ib.push_u64(imm);
465 }
466 self.flush_instbuf(ib);
467 }
468
469 #[inline(always)]
471 pub fn mov_ri32(&mut self, dst: Reg, imm: u32) {
472 let mut ib = InstBuf::new();
473 if dst.needs_rex() {
474 ib.push(0x40 | dst.hi());
475 }
476 ib.push(0xB8 + dst.lo());
477 ib.push_u32(imm);
478 self.flush_instbuf(ib);
479 }
480
481 #[inline(always)]
483 pub fn mov_load64(&mut self, dst: Reg, base: Reg, disp: i32) {
484 let mut ib = InstBuf::new();
485 ib.push(0x48 | (dst.hi() << 2) | base.hi());
486 ib.push(0x8B);
487 Self::modrm_disp_ib(&mut ib, dst.lo(), base, disp);
488 self.flush_instbuf(ib);
489 }
490
491 pub fn movsxd_load_sib4(&mut self, dst: Reg, base: Reg, index: Reg) {
493 let mut ib = InstBuf::new();
494 ib.push(0x48 | (dst.hi() << 2) | (index.hi() << 1) | base.hi());
495 ib.push(0x63);
496 ib.push((dst.lo() << 3) | 4);
497 ib.push(0x80 | (index.lo() << 3) | base.lo());
498 self.flush_instbuf(ib);
499 }
500
501 #[inline(always)]
503 pub fn mov_store32(&mut self, base: Reg, disp: i32, src: Reg) {
504 let mut ib = InstBuf::new();
505 let r = src.hi();
506 let b = base.hi();
507 if r != 0 || b != 0 {
508 ib.push(0x40 | (r << 2) | b);
509 }
510 ib.push(0x89);
511 Self::modrm_disp_ib(&mut ib, src.lo(), base, disp);
512 self.flush_instbuf(ib);
513 }
514
515 #[inline(always)]
517 pub fn mov_store64(&mut self, base: Reg, disp: i32, src: Reg) {
518 let mut ib = InstBuf::new();
519 ib.push(0x48 | (src.hi() << 2) | base.hi());
520 ib.push(0x89);
521 Self::modrm_disp_ib(&mut ib, src.lo(), base, disp);
522 self.flush_instbuf(ib);
523 }
524
525 fn alu_rr64(&mut self, op: u8, dst: Reg, src: Reg) {
528 let mut ib = InstBuf::new();
529 ib.push(0x48 | (src.hi() << 2) | dst.hi());
530 ib.push(op);
531 ib.push(0xC0 | (src.lo() << 3) | dst.lo());
532 self.flush_instbuf(ib);
533 }
534
535 fn alu_rr32(&mut self, op: u8, dst: Reg, src: Reg) {
536 let r = src.hi();
537 let b = dst.hi();
538 if r != 0 || b != 0 {
539 let mut ib = InstBuf::new();
540 ib.push(0x40 | (r << 2) | b);
541 ib.push(op);
542 ib.push(0xC0 | (src.lo() << 3) | dst.lo());
543 self.flush_instbuf(ib);
544 } else {
545 let mut ib = InstBuf::new();
546 ib.push(op);
547 ib.push(0xC0 | (src.lo() << 3) | dst.lo());
548 self.flush_instbuf(ib);
549 }
550 }
551
552 #[inline(always)]
553 pub fn add_rr(&mut self, dst: Reg, src: Reg) {
554 self.alu_rr64(0x01, dst, src);
555 }
556 #[inline(always)]
557 pub fn sub_rr(&mut self, dst: Reg, src: Reg) {
558 self.alu_rr64(0x29, dst, src);
559 }
560 #[inline(always)]
561 pub fn and_rr(&mut self, dst: Reg, src: Reg) {
562 self.alu_rr64(0x21, dst, src);
563 }
564 #[inline(always)]
565 pub fn or_rr(&mut self, dst: Reg, src: Reg) {
566 self.alu_rr64(0x09, dst, src);
567 }
568 #[inline(always)]
569 pub fn xor_rr(&mut self, dst: Reg, src: Reg) {
570 self.alu_rr64(0x31, dst, src);
571 }
572 #[inline(always)]
573 pub fn cmp_rr(&mut self, a: Reg, b: Reg) {
574 self.alu_rr64(0x39, a, b);
575 }
576 #[inline(always)]
577 pub fn test_rr(&mut self, a: Reg, b: Reg) {
578 self.alu_rr64(0x85, a, b);
579 }
580
581 #[inline(always)]
585 pub fn test_rr32(&mut self, a: Reg, b: Reg) {
586 self.alu_rr32(0x85, a, b);
587 }
588
589 #[inline(always)]
590 pub fn add_rr32(&mut self, dst: Reg, src: Reg) {
591 self.alu_rr32(0x01, dst, src);
592 }
593 #[inline(always)]
594 pub fn sub_rr32(&mut self, dst: Reg, src: Reg) {
595 self.alu_rr32(0x29, dst, src);
596 }
597
598 #[inline(always)]
602 fn alu_ri64(&mut self, ext: u8, dst: Reg, imm: i32) {
603 let mut ib = InstBuf::new();
604 ib.push(0x48 | dst.hi());
605 if (-128..=127).contains(&imm) {
606 ib.push(0x83);
607 ib.push(0xC0 | (ext << 3) | dst.lo());
608 ib.push(imm as u8);
609 } else {
610 ib.push(0x81);
611 ib.push(0xC0 | (ext << 3) | dst.lo());
612 ib.push_i32(imm);
613 }
614 self.flush_instbuf(ib);
615 }
616
617 #[inline(always)]
618 fn alu_ri32(&mut self, ext: u8, dst: Reg, imm: i32) {
619 let mut ib = InstBuf::new();
620 if dst.needs_rex() {
621 ib.push(0x40 | dst.hi());
622 }
623 if (-128..=127).contains(&imm) {
624 ib.push(0x83);
625 ib.push(0xC0 | (ext << 3) | dst.lo());
626 ib.push(imm as u8);
627 } else {
628 ib.push(0x81);
629 ib.push(0xC0 | (ext << 3) | dst.lo());
630 ib.push_i32(imm);
631 }
632 self.flush_instbuf(ib);
633 }
634
635 #[inline(always)]
636 pub fn add_ri(&mut self, dst: Reg, imm: i32) {
637 self.alu_ri64(0, dst, imm);
638 }
639 #[inline(always)]
640 pub fn sub_ri(&mut self, dst: Reg, imm: i32) {
641 self.alu_ri64(5, dst, imm);
642 }
643 #[inline(always)]
644 pub fn and_ri(&mut self, dst: Reg, imm: i32) {
645 self.alu_ri64(4, dst, imm);
646 }
647 #[inline(always)]
648 pub fn or_ri(&mut self, dst: Reg, imm: i32) {
649 self.alu_ri64(1, dst, imm);
650 }
651 #[inline(always)]
652 pub fn xor_ri(&mut self, dst: Reg, imm: i32) {
653 self.alu_ri64(6, dst, imm);
654 }
655 #[inline(always)]
656 pub fn cmp_ri(&mut self, a: Reg, imm: i32) {
657 self.alu_ri64(7, a, imm);
658 }
659
660 #[inline(always)]
661 pub fn add_ri32(&mut self, dst: Reg, imm: i32) {
662 self.alu_ri32(0, dst, imm);
663 }
664 #[inline(always)]
665 pub fn sub_ri32(&mut self, dst: Reg, imm: i32) {
666 self.alu_ri32(5, dst, imm);
667 }
668 #[inline(always)]
669 pub fn cmp_ri32(&mut self, a: Reg, imm: i32) {
670 self.alu_ri32(7, a, imm);
671 }
672
673 fn modrm_baseless(&mut self, reg: u8, idx: Reg) {
687 let r = reg & 7;
688 match idx.lo() {
689 4 => {
690 self.emit((r << 3) | 4); self.emit(0x24); }
694 5 => {
695 self.emit(0x40 | (r << 3) | 5);
697 self.emit(0);
698 }
699 _ => {
700 self.emit((r << 3) | idx.lo());
701 }
702 }
703 }
704
705 pub fn movzx_load8_at_index(&mut self, dst: Reg, idx: Reg) {
707 self.emit(0x48 | (dst.hi() << 2) | idx.hi());
708 self.emit(0x0F);
709 self.emit(0xB6);
710 self.modrm_baseless(dst.lo(), idx);
711 }
712
713 pub fn movzx_load16_at_index(&mut self, dst: Reg, idx: Reg) {
715 let rex = 0x40 | (dst.hi() << 2) | idx.hi();
716 if rex != 0x40 {
717 self.emit(rex);
718 }
719 self.emit(0x0F);
720 self.emit(0xB7);
721 self.modrm_baseless(dst.lo(), idx);
722 }
723
724 pub fn mov_load32_at_index(&mut self, dst: Reg, idx: Reg) {
726 let rex = 0x40 | (dst.hi() << 2) | idx.hi();
727 if rex != 0x40 {
728 self.emit(rex);
729 }
730 self.emit(0x8B);
731 self.modrm_baseless(dst.lo(), idx);
732 }
733
734 pub fn mov_load64_at_index(&mut self, dst: Reg, idx: Reg) {
736 self.emit(0x48 | (dst.hi() << 2) | idx.hi());
737 self.emit(0x8B);
738 self.modrm_baseless(dst.lo(), idx);
739 }
740
741 pub fn mov_store8_at_index(&mut self, idx: Reg, src: Reg) {
743 let rex = 0x40 | (src.hi() << 2) | idx.hi();
747 if rex != 0x40 || src.lo() >= 4 {
748 self.emit(rex);
749 }
750 self.emit(0x88);
751 self.modrm_baseless(src.lo(), idx);
752 }
753
754 pub fn mov_store16_at_index(&mut self, idx: Reg, src: Reg) {
756 self.emit(0x66);
757 let rex = 0x40 | (src.hi() << 2) | idx.hi();
758 if rex != 0x40 {
759 self.emit(rex);
760 }
761 self.emit(0x89);
762 self.modrm_baseless(src.lo(), idx);
763 }
764
765 pub fn mov_store32_at_index(&mut self, idx: Reg, src: Reg) {
767 let rex = 0x40 | (src.hi() << 2) | idx.hi();
768 if rex != 0x40 {
769 self.emit(rex);
770 }
771 self.emit(0x89);
772 self.modrm_baseless(src.lo(), idx);
773 }
774
775 pub fn mov_store64_at_index(&mut self, idx: Reg, src: Reg) {
777 self.emit(0x48 | (src.hi() << 2) | idx.hi());
778 self.emit(0x89);
779 self.modrm_baseless(src.lo(), idx);
780 }
781
782 fn emit_rip_rel_disp32(&mut self, target_va: u64, trailing_bytes: u64) {
802 let post_inst_rip = self
803 .jit_va_base
804 .wrapping_add(self.write_pos as u64)
805 .wrapping_add(4)
806 .wrapping_add(trailing_bytes);
807 let disp = (target_va as i64).wrapping_sub(post_inst_rip as i64);
808 debug_assert!(
809 disp >= i32::MIN as i64 && disp <= i32::MAX as i64,
810 "RIP-relative target 0x{:x} out of range from base 0x{:x} + offset 0x{:x}",
811 target_va,
812 self.jit_va_base,
813 self.write_pos
814 );
815 self.emit_i32(disp as i32);
816 }
817
818 fn modrm_rip_rel(&mut self, reg: u8) {
819 self.emit(((reg & 7) << 3) | 5);
821 }
822
823 pub fn mov_load32_rip_rel(&mut self, dst: Reg, target_va: u64) {
825 if dst.hi() != 0 {
826 self.emit(0x40 | (dst.hi() << 2));
827 }
828 self.emit(0x8B);
829 self.modrm_rip_rel(dst.lo());
830 self.emit_rip_rel_disp32(target_va, 0);
831 }
832
833 pub fn mov_load64_rip_rel(&mut self, dst: Reg, target_va: u64) {
835 self.emit(0x48 | (dst.hi() << 2));
836 self.emit(0x8B);
837 self.modrm_rip_rel(dst.lo());
838 self.emit_rip_rel_disp32(target_va, 0);
839 }
840
841 pub fn mov_store32_rip_rel(&mut self, target_va: u64, src: Reg) {
843 if src.hi() != 0 {
844 self.emit(0x40 | (src.hi() << 2));
845 }
846 self.emit(0x89);
847 self.modrm_rip_rel(src.lo());
848 self.emit_rip_rel_disp32(target_va, 0);
849 }
850
851 pub fn mov_store64_rip_rel(&mut self, target_va: u64, src: Reg) {
853 self.emit(0x48 | (src.hi() << 2));
854 self.emit(0x89);
855 self.modrm_rip_rel(src.lo());
856 self.emit_rip_rel_disp32(target_va, 0);
857 }
858
859 pub fn mov_store32_rip_rel_imm(&mut self, target_va: u64, imm: i32) {
862 self.emit(0xC7);
863 self.modrm_rip_rel(0);
864 self.emit_rip_rel_disp32(target_va, 4);
865 self.emit_i32(imm);
866 }
867
868 pub fn add_r64_mem_rip_rel(&mut self, dst: Reg, target_va: u64) {
870 self.emit(0x48 | (dst.hi() << 2));
871 self.emit(0x03);
872 self.modrm_rip_rel(dst.lo());
873 self.emit_rip_rel_disp32(target_va, 0);
874 }
875
876 pub fn cmp_r64_mem_rip_rel(&mut self, dst: Reg, target_va: u64) {
880 self.emit(0x48 | (dst.hi() << 2));
881 self.emit(0x3B);
882 self.modrm_rip_rel(dst.lo());
883 self.emit_rip_rel_disp32(target_va, 0);
884 }
885
886 pub fn sub_r64_imm32_patchable(&mut self, dst: Reg, imm: i32) {
892 self.emit(0x48 | dst.hi());
895 self.emit(0x81);
896 self.emit(0xE8 | dst.lo()); self.emit_i32(imm);
898 }
899
900 pub fn cmp_r64_imm32_patchable(&mut self, dst: Reg, imm: i32) {
906 self.emit(0x48 | dst.hi());
907 self.emit(0x81);
908 self.emit(0xF8 | dst.lo()); self.emit_i32(imm);
910 }
911
912 pub fn imul_rr(&mut self, dst: Reg, src: Reg) {
916 let mut ib = InstBuf::new();
917 ib.push(0x48 | (dst.hi() << 2) | src.hi());
918 ib.push(0x0F);
919 ib.push(0xAF);
920 ib.push(0xC0 | (dst.lo() << 3) | src.lo());
921 self.flush_instbuf(ib);
922 }
923
924 pub fn imul_rr32(&mut self, dst: Reg, src: Reg) {
926 let mut ib = InstBuf::new();
927 let r = dst.hi();
928 let b = src.hi();
929 if r != 0 || b != 0 {
930 ib.push(0x40 | (r << 2) | b);
931 }
932 ib.push(0x0F);
933 ib.push(0xAF);
934 ib.push(0xC0 | (dst.lo() << 3) | src.lo());
935 self.flush_instbuf(ib);
936 }
937
938 pub fn mul_rdx_rax(&mut self, src: Reg) {
942 self.emit3(0x48 | src.hi(), 0xF7, 0xE0 | src.lo());
943 }
944
945 pub fn imul_rdx_rax(&mut self, src: Reg) {
947 self.emit3(0x48 | src.hi(), 0xF7, 0xE8 | src.lo());
948 }
949
950 pub fn div64(&mut self, src: Reg) {
954 self.emit3(0x48 | src.hi(), 0xF7, 0xF0 | src.lo());
955 }
956
957 pub fn idiv64(&mut self, src: Reg) {
959 self.emit3(0x48 | src.hi(), 0xF7, 0xF8 | src.lo());
960 }
961
962 pub fn div32(&mut self, src: Reg) {
964 if src.needs_rex() {
965 self.emit3(0x41, 0xF7, 0xF0 | src.lo());
966 } else {
967 let mut ib = InstBuf::new();
968 ib.push(0xF7);
969 ib.push(0xF0 | src.lo());
970 self.flush_instbuf(ib);
971 }
972 }
973
974 pub fn idiv32(&mut self, src: Reg) {
976 if src.needs_rex() {
977 self.emit3(0x41, 0xF7, 0xF8 | src.lo());
978 } else {
979 let mut ib = InstBuf::new();
980 ib.push(0xF7);
981 ib.push(0xF8 | src.lo());
982 self.flush_instbuf(ib);
983 }
984 }
985
986 pub fn cqo(&mut self) {
988 self.emit(0x48);
989 self.emit(0x99);
990 }
991
992 pub fn cdq(&mut self) {
994 self.emit(0x99);
995 }
996
997 pub fn neg64(&mut self, dst: Reg) {
1001 self.emit3(0x48 | dst.hi(), 0xF7, 0xD8 | dst.lo());
1002 }
1003
1004 pub fn not64(&mut self, dst: Reg) {
1006 self.emit3(0x48 | dst.hi(), 0xF7, 0xD0 | dst.lo());
1007 }
1008
1009 fn shift_ri64(&mut self, ext: u8, dst: Reg, imm: u8) {
1012 let mut ib = InstBuf::new();
1013 ib.push(0x48 | dst.hi());
1014 ib.push(0xC1);
1015 ib.push(0xC0 | (ext << 3) | dst.lo());
1016 ib.push(imm);
1017 self.flush_instbuf(ib);
1018 }
1019
1020 pub fn shift_cl64(&mut self, ext: u8, dst: Reg) {
1021 let mut ib = InstBuf::new();
1022 ib.push(0x48 | dst.hi());
1023 ib.push(0xD3);
1024 ib.push(0xC0 | (ext << 3) | dst.lo());
1025 self.flush_instbuf(ib);
1026 }
1027
1028 fn shift_ri32(&mut self, ext: u8, dst: Reg, imm: u8) {
1029 let mut ib = InstBuf::new();
1030 if dst.needs_rex() {
1031 ib.push(0x40 | dst.hi());
1032 }
1033 ib.push(0xC1);
1034 ib.push(0xC0 | (ext << 3) | dst.lo());
1035 ib.push(imm);
1036 self.flush_instbuf(ib);
1037 }
1038
1039 pub fn shift_cl32(&mut self, ext: u8, dst: Reg) {
1040 let mut ib = InstBuf::new();
1041 if dst.needs_rex() {
1042 ib.push(0x40 | dst.hi());
1043 }
1044 ib.push(0xD3);
1045 ib.push(0xC0 | (ext << 3) | dst.lo());
1046 self.flush_instbuf(ib);
1047 }
1048
1049 pub fn shl_ri64(&mut self, dst: Reg, imm: u8) {
1050 self.shift_ri64(4, dst, imm);
1051 }
1052 pub fn shr_ri64(&mut self, dst: Reg, imm: u8) {
1053 self.shift_ri64(5, dst, imm);
1054 }
1055 pub fn sar_ri64(&mut self, dst: Reg, imm: u8) {
1056 self.shift_ri64(7, dst, imm);
1057 }
1058 pub fn shl_cl64(&mut self, dst: Reg) {
1059 self.shift_cl64(4, dst);
1060 }
1061 pub fn ror_ri64(&mut self, dst: Reg, imm: u8) {
1062 self.shift_ri64(1, dst, imm);
1063 }
1064
1065 pub fn shl_ri32(&mut self, dst: Reg, imm: u8) {
1066 self.shift_ri32(4, dst, imm);
1067 }
1068 pub fn shr_ri32(&mut self, dst: Reg, imm: u8) {
1069 self.shift_ri32(5, dst, imm);
1070 }
1071 pub fn sar_ri32(&mut self, dst: Reg, imm: u8) {
1072 self.shift_ri32(7, dst, imm);
1073 }
1074 pub fn ror_ri32(&mut self, dst: Reg, imm: u8) {
1075 self.shift_ri32(1, dst, imm);
1076 }
1077
1078 #[inline(always)]
1082 pub fn movsxd(&mut self, dst: Reg, src: Reg) {
1083 let mut ib = InstBuf::new();
1084 ib.push(0x48 | (dst.hi() << 2) | src.hi());
1085 ib.push(0x63);
1086 ib.push(0xC0 | (dst.lo() << 3) | src.lo());
1087 self.flush_instbuf(ib);
1088 }
1089
1090 pub fn movsx_8_64(&mut self, dst: Reg, src: Reg) {
1092 let mut ib = InstBuf::new();
1093 ib.push(0x48 | (dst.hi() << 2) | src.hi());
1094 ib.push(0x0F);
1095 ib.push(0xBE);
1096 ib.push(0xC0 | (dst.lo() << 3) | src.lo());
1097 self.flush_instbuf(ib);
1098 }
1099
1100 pub fn movsx_16_64(&mut self, dst: Reg, src: Reg) {
1102 let mut ib = InstBuf::new();
1103 ib.push(0x48 | (dst.hi() << 2) | src.hi());
1104 ib.push(0x0F);
1105 ib.push(0xBF);
1106 ib.push(0xC0 | (dst.lo() << 3) | src.lo());
1107 self.flush_instbuf(ib);
1108 }
1109
1110 pub fn movzx_16_64(&mut self, dst: Reg, src: Reg) {
1112 let mut ib = InstBuf::new();
1113 let r = dst.hi();
1114 let b = src.hi();
1115 if r != 0 || b != 0 {
1116 ib.push(0x40 | (r << 2) | b);
1117 }
1118 ib.push(0x0F);
1119 ib.push(0xB7);
1120 ib.push(0xC0 | (dst.lo() << 3) | src.lo());
1121 self.flush_instbuf(ib);
1122 }
1123
1124 #[inline(always)]
1126 pub fn movzx_32_64(&mut self, dst: Reg, src: Reg) {
1127 let mut ib = InstBuf::new();
1128 let r = src.hi();
1129 let b = dst.hi();
1130 if r != 0 || b != 0 {
1131 ib.push(0x40 | (r << 2) | b);
1132 }
1133 ib.push(0x89);
1134 ib.push(0xC0 | (src.lo() << 3) | dst.lo());
1135 self.flush_instbuf(ib);
1136 }
1137
1138 #[inline(always)]
1142 pub fn setcc(&mut self, cc: Cc, dst: Reg) {
1143 let mut ib = InstBuf::new();
1144 if dst.needs_rex() || matches!(dst, Reg::RSP | Reg::RBP | Reg::RSI | Reg::RDI) {
1145 ib.push(0x40 | dst.hi());
1146 }
1147 ib.push(0x0F);
1148 ib.push(0x90 + cc as u8);
1149 ib.push(0xC0 | dst.lo());
1150 self.flush_instbuf(ib);
1151 }
1152
1153 #[inline(always)]
1155 pub fn cmovcc(&mut self, cc: Cc, dst: Reg, src: Reg) {
1156 let mut ib = InstBuf::new();
1157 ib.push(0x48 | (dst.hi() << 2) | src.hi());
1158 ib.push(0x0F);
1159 ib.push(0x40 + cc as u8);
1160 ib.push(0xC0 | (dst.lo() << 3) | src.lo());
1161 self.flush_instbuf(ib);
1162 }
1163
1164 pub fn popcnt64(&mut self, dst: Reg, src: Reg) {
1168 let mut ib = InstBuf::new();
1169 ib.push(0xF3);
1170 ib.push(0x48 | (dst.hi() << 2) | src.hi());
1171 ib.push(0x0F);
1172 ib.push(0xB8);
1173 ib.push(0xC0 | (dst.lo() << 3) | src.lo());
1174 self.flush_instbuf(ib);
1175 }
1176
1177 pub fn lzcnt64(&mut self, dst: Reg, src: Reg) {
1179 let mut ib = InstBuf::new();
1180 ib.push(0xF3);
1181 ib.push(0x48 | (dst.hi() << 2) | src.hi());
1182 ib.push(0x0F);
1183 ib.push(0xBD);
1184 ib.push(0xC0 | (dst.lo() << 3) | src.lo());
1185 self.flush_instbuf(ib);
1186 }
1187
1188 pub fn tzcnt64(&mut self, dst: Reg, src: Reg) {
1190 let mut ib = InstBuf::new();
1191 ib.push(0xF3);
1192 ib.push(0x48 | (dst.hi() << 2) | src.hi());
1193 ib.push(0x0F);
1194 ib.push(0xBC);
1195 ib.push(0xC0 | (dst.lo() << 3) | src.lo());
1196 self.flush_instbuf(ib);
1197 }
1198
1199 pub fn popcnt32(&mut self, dst: Reg, src: Reg) {
1201 let mut ib = InstBuf::new();
1202 ib.push(0xF3);
1203 let rex = (dst.hi() << 2) | src.hi();
1204 if rex != 0 {
1205 ib.push(0x40 | rex);
1206 }
1207 ib.push(0x0F);
1208 ib.push(0xB8);
1209 ib.push(0xC0 | (dst.lo() << 3) | src.lo());
1210 self.flush_instbuf(ib);
1211 }
1212
1213 pub fn lzcnt32(&mut self, dst: Reg, src: Reg) {
1215 let mut ib = InstBuf::new();
1216 ib.push(0xF3);
1217 let rex = (dst.hi() << 2) | src.hi();
1218 if rex != 0 {
1219 ib.push(0x40 | rex);
1220 }
1221 ib.push(0x0F);
1222 ib.push(0xBD);
1223 ib.push(0xC0 | (dst.lo() << 3) | src.lo());
1224 self.flush_instbuf(ib);
1225 }
1226
1227 pub fn tzcnt32(&mut self, dst: Reg, src: Reg) {
1229 let mut ib = InstBuf::new();
1230 ib.push(0xF3);
1231 let rex = (dst.hi() << 2) | src.hi();
1232 if rex != 0 {
1233 ib.push(0x40 | rex);
1234 }
1235 ib.push(0x0F);
1236 ib.push(0xBC);
1237 ib.push(0xC0 | (dst.lo() << 3) | src.lo());
1238 self.flush_instbuf(ib);
1239 }
1240
1241 pub fn bswap64(&mut self, dst: Reg) {
1243 self.emit3(0x48 | dst.hi(), 0x0F, 0xC8 + dst.lo());
1244 }
1245
1246 #[inline(always)]
1249 pub fn push(&mut self, reg: Reg) {
1250 self.rex_opt_b(reg);
1251 self.emit(0x50 + reg.lo());
1252 }
1253
1254 #[inline(always)]
1255 pub fn pop(&mut self, reg: Reg) {
1256 self.rex_opt_b(reg);
1257 self.emit(0x58 + reg.lo());
1258 }
1259
1260 #[inline(always)]
1264 pub fn jmp_label(&mut self, label: Label) {
1265 let bound = self.labels[label.0 as usize];
1266 if bound != LABEL_UNBOUND {
1267 let target = (bound - 1) as isize; let rel = target - (self.write_pos as isize + 2);
1270 if rel >= i8::MIN as isize && rel <= i8::MAX as isize {
1271 self.emit(0xEB);
1272 self.emit(rel as u8);
1273 return;
1274 }
1275 }
1276 self.emit(0xE9);
1278 self.emit_label_fixup(label);
1279 }
1280
1281 #[inline(always)]
1283 pub fn jcc_label(&mut self, cc: Cc, label: Label) {
1284 let bound = self.labels[label.0 as usize];
1285 if bound != LABEL_UNBOUND {
1286 let target = (bound - 1) as isize; let rel = target - (self.write_pos as isize + 2);
1289 if rel >= i8::MIN as isize && rel <= i8::MAX as isize {
1290 self.emit(0x70 + cc as u8);
1291 self.emit(rel as u8);
1292 return;
1293 }
1294 }
1295 self.emit(0x0F);
1297 self.emit(0x80 + cc as u8);
1298 self.emit_label_fixup(label);
1299 }
1300
1301 pub fn jmp_reg(&mut self, reg: Reg) {
1303 self.rex_opt_b(reg);
1304 self.emit(0xFF);
1305 self.emit(0xE0 | reg.lo()); }
1307
1308 pub fn ret(&mut self) {
1310 self.emit(0xC3);
1311 }
1312
1313 pub fn lea(&mut self, dst: Reg, base: Reg, disp: i32) {
1317 let mut ib = InstBuf::new();
1318 ib.push(0x48 | (dst.hi() << 2) | base.hi());
1319 ib.push(0x8D);
1320 Self::modrm_disp_ib(&mut ib, dst.lo(), base, disp);
1321 self.flush_instbuf(ib);
1322 }
1323
1324 #[inline(always)]
1326 pub fn lea_32(&mut self, dst: Reg, base: Reg, disp: i32) {
1327 let mut ib = InstBuf::new();
1328 let r = dst.hi();
1329 let b = base.hi();
1330 if r != 0 || b != 0 {
1331 ib.push(0x40 | (r << 2) | b);
1332 }
1333 ib.push(0x8D);
1334 Self::modrm_disp_ib(&mut ib, dst.lo(), base, disp);
1335 self.flush_instbuf(ib);
1336 }
1337
1338 #[inline(always)]
1341 pub fn lea_sib_scaled_32(&mut self, dst: Reg, base: Reg, index: Reg, scale_log2: u8) {
1342 debug_assert!(scale_log2 <= 3);
1343 let mut ib = InstBuf::new();
1344 let rex = 0x40 | (dst.hi() << 2) | (index.hi() << 1) | base.hi();
1345 if rex != 0x40 {
1346 ib.push(rex);
1347 }
1348 ib.push(0x8D);
1349 let scale_bits = scale_log2 << 6;
1350 if base.lo() == 5 {
1351 ib.push(0x44 | (dst.lo() << 3));
1352 ib.push(scale_bits | (index.lo() << 3) | base.lo());
1353 ib.push(0x00);
1354 } else {
1355 ib.push((dst.lo() << 3) | 0x04);
1356 ib.push(scale_bits | (index.lo() << 3) | base.lo());
1357 }
1358 self.flush_instbuf(ib);
1359 }
1360
1361 pub fn nop(&mut self) {
1365 self.emit(0x90);
1366 }
1367
1368 pub fn label_offset(&self, label: Label) -> Option<usize> {
1372 let off = self.labels[label.0 as usize];
1373 if off == LABEL_UNBOUND {
1374 None
1375 } else {
1376 Some((off - 1) as usize)
1377 }
1378 }
1379
1380 #[inline]
1385 pub fn fixups_len(&self) -> usize {
1386 self.fixups.len()
1387 }
1388
1389 pub fn redirect_fixup(&mut self, idx: usize, new_label: Label) {
1393 self.fixups[idx].label = new_label;
1394 }
1395
1396 #[cfg(test)]
1398 pub fn sync_len(&mut self) {
1399 let code = &mut self.code_buf;
1400 unsafe {
1402 code.set_len(self.write_pos);
1403 }
1404 }
1405
1406 fn resolve_fixups(&mut self) {
1408 for fixup in &self.fixups {
1409 let stored = self.labels[fixup.label.0 as usize];
1410 assert!(stored != LABEL_UNBOUND, "unbound label {:?}", fixup.label);
1412 let target = stored - 1; let rel = (target as i64) - (fixup.offset as i64 + 4);
1414 let rel32 = rel as i32;
1415 unsafe {
1417 core::ptr::copy_nonoverlapping(
1418 rel32.to_le_bytes().as_ptr(),
1419 self.buf.add(fixup.offset),
1420 4,
1421 );
1422 }
1423 }
1424 }
1425
1426 pub fn finalize(&mut self) -> Vec<u8> {
1428 self.resolve_fixups();
1429 let code = &mut self.code_buf;
1430 unsafe {
1432 code.set_len(self.write_pos);
1433 }
1434 core::mem::take(code)
1435 }
1436
1437 #[cfg(test)]
1439 pub fn code_bytes(&mut self) -> &[u8] {
1440 self.sync_len();
1441 let v = &self.code_buf;
1442 v.as_slice()
1443 }
1444}
1445
1446#[cfg(test)]
1447mod tests {
1448 use super::*;
1449
1450 #[test]
1451 fn test_mov_ri64_zero() {
1452 let mut asm = Assembler::new();
1453 asm.mov_ri64(Reg::RAX, 0);
1454 assert_eq!(asm.code_bytes(), &[0x31, 0xC0]);
1456 }
1457
1458 #[test]
1459 fn test_mov_ri64_small() {
1460 let mut asm = Assembler::new();
1461 asm.mov_ri64(Reg::RAX, 42);
1462 assert_eq!(asm.code_bytes(), &[0xB8, 0x2A, 0x00, 0x00, 0x00]);
1464 }
1465
1466 #[test]
1467 fn test_label_resolution() {
1468 let mut asm = Assembler::new();
1469 let lbl = asm.new_label();
1470 asm.jmp_label(lbl); asm.nop(); asm.bind_label(lbl); let code = asm.finalize();
1474 assert_eq!(code[0], 0xE9);
1478 let rel = i32::from_le_bytes([code[1], code[2], code[3], code[4]]);
1479 assert_eq!(rel, 1); }
1481
1482 #[test]
1486 fn test_mov_load32_at_rdx() {
1487 let mut asm = Assembler::new();
1488 asm.mov_load32_at_index(Reg::RAX, Reg::RDX);
1489 assert_eq!(asm.code_bytes(), &[0x8B, 0x02]);
1490 }
1491
1492 #[test]
1495 fn test_mov_load64_at_r12_into_r8() {
1496 let mut asm = Assembler::new();
1497 asm.mov_load64_at_index(Reg::R8, Reg::R12);
1498 assert_eq!(asm.code_bytes(), &[0x4D, 0x8B, 0x04, 0x24]);
1503 }
1504
1505 #[test]
1509 fn test_mov_load32_rip_rel() {
1510 let mut asm = Assembler::new();
1511 asm.set_jit_va_base(0x1_0000_0000); asm.mov_load32_rip_rel(Reg::RAX, 0x1_0000_0040); assert_eq!(asm.code_bytes(), &[0x8B, 0x05, 0x3A, 0x00, 0x00, 0x00]);
1517 }
1518
1519 #[test]
1521 fn test_mov_store64_rip_rel_r15() {
1522 let mut asm = Assembler::new();
1523 asm.set_jit_va_base(0x1_0000_0000);
1524 asm.mov_store64_rip_rel(0x1_0000_0080, Reg::R15);
1525 assert_eq!(
1528 asm.code_bytes(),
1529 &[0x4C, 0x89, 0x3D, 0x79, 0x00, 0x00, 0x00]
1530 );
1531 }
1532
1533 #[test]
1535 fn test_mov_store32_at_rdx() {
1536 let mut asm = Assembler::new();
1537 asm.mov_store32_at_index(Reg::RDX, Reg::RAX);
1538 assert_eq!(asm.code_bytes(), &[0x89, 0x02]);
1539 }
1540
1541 #[test]
1543 fn test_mov_store32_at_rdx_from_r11() {
1544 let mut asm = Assembler::new();
1545 asm.mov_store32_at_index(Reg::RDX, Reg::R11);
1546 assert_eq!(asm.code_bytes(), &[0x44, 0x89, 0x1A]);
1547 }
1548
1549 #[test]
1553 fn test_mov_store8_at_rdx_from_sil() {
1554 let mut asm = Assembler::new();
1555 asm.mov_store8_at_index(Reg::RDX, Reg::RSI);
1556 assert_eq!(asm.code_bytes(), &[0x40, 0x88, 0x32]);
1557 }
1558
1559 #[test]
1560 fn test_mov_store8_at_rdx_from_dil() {
1561 let mut asm = Assembler::new();
1562 asm.mov_store8_at_index(Reg::RDX, Reg::RDI);
1563 assert_eq!(asm.code_bytes(), &[0x40, 0x88, 0x3A]);
1564 }
1565
1566 #[test]
1567 fn test_mov_store8_at_rdx_from_bpl() {
1568 let mut asm = Assembler::new();
1569 asm.mov_store8_at_index(Reg::RDX, Reg::RBP);
1570 assert_eq!(asm.code_bytes(), &[0x40, 0x88, 0x2A]);
1571 }
1572
1573 #[test]
1574 fn test_mov_store8_at_rdx_from_spl() {
1575 let mut asm = Assembler::new();
1576 asm.mov_store8_at_index(Reg::RDX, Reg::RSP);
1577 assert_eq!(asm.code_bytes(), &[0x40, 0x88, 0x22]);
1578 }
1579
1580 #[test]
1582 fn test_mov_store8_at_rdx_from_al_no_rex() {
1583 let mut asm = Assembler::new();
1584 asm.mov_store8_at_index(Reg::RDX, Reg::RAX);
1585 assert_eq!(asm.code_bytes(), &[0x88, 0x02]);
1586 }
1587
1588 #[test]
1593 fn test_mov_store32_rip_rel_imm() {
1594 let mut asm = Assembler::new();
1595 asm.set_jit_va_base(0x1_0000_0000);
1596 asm.mov_store32_rip_rel_imm(0x1_0000_0100, 0x123);
1597 assert_eq!(
1599 asm.code_bytes(),
1600 &[0xC7, 0x05, 0xF6, 0x00, 0x00, 0x00, 0x23, 0x01, 0x00, 0x00]
1601 );
1602 }
1603
1604 #[test]
1607 fn test_add_r64_mem_rip_rel() {
1608 let mut asm = Assembler::new();
1609 asm.set_jit_va_base(0x1_0000_0000);
1610 asm.add_r64_mem_rip_rel(Reg::RAX, 0x1_0000_0020);
1611 assert_eq!(
1614 asm.code_bytes(),
1615 &[0x48, 0x03, 0x05, 0x19, 0x00, 0x00, 0x00]
1616 );
1617 }
1618
1619 #[test]
1622 fn test_sub_r64_imm32_patchable_r15() {
1623 let mut asm = Assembler::new();
1624 asm.sub_r64_imm32_patchable(Reg::R15, 0xCAFE_F00D_u32 as i32);
1625 let bytes = asm.code_bytes();
1626 assert_eq!(bytes.len(), 7, "patchable sub must be 7 bytes");
1627 assert_eq!(&bytes[0..3], &[0x49, 0x81, 0xEF]);
1632 assert_eq!(&bytes[3..7], &[0x0D, 0xF0, 0xFE, 0xCA]);
1633 }
1634
1635 #[test]
1636 fn test_push_pop_r15() {
1637 let mut asm = Assembler::new();
1638 asm.push(Reg::R15);
1639 asm.pop(Reg::R15);
1640 assert_eq!(asm.code_bytes(), &[0x41, 0x57, 0x41, 0x5F]);
1642 }
1643}