@@ -35,9 +35,73 @@ fn one_way_jmp(sink: &mut MachBuffer<Inst>, cc: CC, label: MachLabel) {
35
35
let cond_start = sink. cur_offset ( ) ;
36
36
let cond_disp_off = cond_start + 2 ;
37
37
sink. use_label_at_offset ( cond_disp_off, label, LabelUse :: JmpRel32 ) ;
38
- sink. put1 ( 0x0F ) ;
39
- sink. put1 ( 0x80 + cc. get_enc ( ) ) ;
40
- sink. put4 ( 0x0 ) ;
38
+ emit_jcc_no_offset ( sink, cc) ;
39
+ debug_assert_eq ! ( sink. cur_offset( ) , cond_disp_off + 4 ) ;
40
+ }
41
+
42
+ /// Like `one_way_jmp` above emitting a conditional jump, but also using
43
+ /// `MachBuffer::add_cond_branch`.
44
+ fn cond_jmp ( sink : & mut MachBuffer < Inst > , cc : CC , label : MachLabel ) {
45
+ let cond_start = sink. cur_offset ( ) ;
46
+ let cond_disp_off = cond_start + 2 ;
47
+ let cond_end = cond_start + 6 ;
48
+
49
+ sink. use_label_at_offset ( cond_disp_off, label, LabelUse :: JmpRel32 ) ;
50
+ // FIXME: ideally this `inverted` calculation would go through the external
51
+ // assembler, but for now it's left done manually.
52
+ let inverted: [ u8 ; 6 ] = [ 0x0F , 0x80 + ( cc. invert ( ) . get_enc ( ) ) , 0x00 , 0x00 , 0x00 , 0x00 ] ;
53
+ sink. add_cond_branch ( cond_start, cond_end, label, & inverted[ ..] ) ;
54
+
55
+ emit_jcc_no_offset ( sink, cc) ;
56
+
57
+ debug_assert_eq ! ( sink. cur_offset( ) , cond_disp_off + 4 ) ;
58
+ debug_assert_eq ! ( sink. cur_offset( ) , cond_end) ;
59
+ }
60
+
61
+ fn emit_jcc_no_offset ( sink : & mut MachBuffer < Inst > , cc : CC ) {
62
+ // Note that the disassembler matches Capstone which doesn't match the `CC`
63
+ // enum directly as Intel has multiple mnemonics use the same encoding.
64
+ let inst: AsmInst = match cc {
65
+ CC :: Z => asm:: inst:: je_d32:: new ( 0 ) . into ( ) , // jz == je
66
+ CC :: NZ => asm:: inst:: jne_d32:: new ( 0 ) . into ( ) , // jnz == jne
67
+ CC :: B => asm:: inst:: jb_d32:: new ( 0 ) . into ( ) ,
68
+ CC :: NB => asm:: inst:: jae_d32:: new ( 0 ) . into ( ) , // jnb == jae
69
+ CC :: BE => asm:: inst:: jbe_d32:: new ( 0 ) . into ( ) ,
70
+ CC :: NBE => asm:: inst:: ja_d32:: new ( 0 ) . into ( ) , // jnbe == ja
71
+ CC :: L => asm:: inst:: jl_d32:: new ( 0 ) . into ( ) ,
72
+ CC :: LE => asm:: inst:: jle_d32:: new ( 0 ) . into ( ) ,
73
+ CC :: NL => asm:: inst:: jge_d32:: new ( 0 ) . into ( ) , // jnl == jge
74
+ CC :: NLE => asm:: inst:: jg_d32:: new ( 0 ) . into ( ) , // jnle == jg
75
+ CC :: O => asm:: inst:: jo_d32:: new ( 0 ) . into ( ) ,
76
+ CC :: NO => asm:: inst:: jno_d32:: new ( 0 ) . into ( ) ,
77
+ CC :: P => asm:: inst:: jp_d32:: new ( 0 ) . into ( ) ,
78
+ CC :: NP => asm:: inst:: jnp_d32:: new ( 0 ) . into ( ) ,
79
+ CC :: S => asm:: inst:: js_d32:: new ( 0 ) . into ( ) ,
80
+ CC :: NS => asm:: inst:: jns_d32:: new ( 0 ) . into ( ) ,
81
+ } ;
82
+ inst. encode ( & mut external:: AsmCodeSink {
83
+ sink,
84
+ incoming_arg_offset : 0 ,
85
+ slot_offset : 0 ,
86
+ } ) ;
87
+ }
88
+
89
+ /// Emits an unconditional branch.
90
+ fn uncond_jmp ( sink : & mut MachBuffer < Inst > , label : MachLabel ) {
91
+ let uncond_start = sink. cur_offset ( ) ;
92
+ let uncond_disp_off = uncond_start + 1 ;
93
+ let uncond_end = uncond_start + 5 ;
94
+
95
+ sink. use_label_at_offset ( uncond_disp_off, label, LabelUse :: JmpRel32 ) ;
96
+ sink. add_uncond_branch ( uncond_start, uncond_end, label) ;
97
+
98
+ asm:: inst:: jmp_d32:: new ( 0 ) . encode ( & mut external:: AsmCodeSink {
99
+ sink,
100
+ incoming_arg_offset : 0 ,
101
+ slot_offset : 0 ,
102
+ } ) ;
103
+ debug_assert_eq ! ( sink. cur_offset( ) , uncond_disp_off + 4 ) ;
104
+ debug_assert_eq ! ( sink. cur_offset( ) , uncond_end) ;
41
105
}
42
106
43
107
/// Emits a relocation, attaching the current source location as well.
@@ -427,11 +491,11 @@ pub(crate) fn emit(
427
491
// Note: this is not `Inst::Jmp { .. }.emit(..)` because we have
428
492
// different metadata in this case: we don't have a label for the
429
493
// target, but rather a function relocation.
430
- sink. put1 ( 0xE9 ) ;
494
+ asm:: inst:: jmp_d32:: new ( 0 ) . emit ( sink, info, state) ;
495
+ let offset = sink. cur_offset ( ) ;
431
496
// The addend adjusts for the difference between the end of the instruction and the
432
497
// beginning of the immediate field.
433
- emit_reloc ( sink, Reloc :: X86CallPCRel4 , & call_info. dest , -4 ) ;
434
- sink. put4 ( 0 ) ;
498
+ sink. add_reloc_at_offset ( offset - 4 , Reloc :: X86CallPCRel4 , & call_info. dest , -4 ) ;
435
499
sink. add_call_site ( & [ ] ) ;
436
500
}
437
501
@@ -595,62 +659,17 @@ pub(crate) fn emit(
595
659
sink. bind_label ( resume, state. ctrl_plane_mut ( ) ) ;
596
660
}
597
661
598
- Inst :: JmpKnown { dst } => {
599
- let br_start = sink. cur_offset ( ) ;
600
- let br_disp_off = br_start + 1 ;
601
- let br_end = br_start + 5 ;
662
+ Inst :: JmpKnown { dst } => uncond_jmp ( sink, * dst) ,
602
663
603
- sink. use_label_at_offset ( br_disp_off, * dst, LabelUse :: JmpRel32 ) ;
604
- sink. add_uncond_branch ( br_start, br_end, * dst) ;
605
-
606
- sink. put1 ( 0xE9 ) ;
607
- // Placeholder for the label value.
608
- sink. put4 ( 0x0 ) ;
609
- }
610
-
611
- Inst :: WinchJmpIf { cc, taken } => {
612
- let cond_start = sink. cur_offset ( ) ;
613
- let cond_disp_off = cond_start + 2 ;
614
-
615
- sink. use_label_at_offset ( cond_disp_off, * taken, LabelUse :: JmpRel32 ) ;
616
- // Since this is not a terminator, don't enroll in the branch inversion mechanism.
617
-
618
- sink. put1 ( 0x0F ) ;
619
- sink. put1 ( 0x80 + cc. get_enc ( ) ) ;
620
- // Placeholder for the label value.
621
- sink. put4 ( 0x0 ) ;
622
- }
664
+ Inst :: WinchJmpIf { cc, taken } => one_way_jmp ( sink, * cc, * taken) ,
623
665
624
666
Inst :: JmpCond {
625
667
cc,
626
668
taken,
627
669
not_taken,
628
670
} => {
629
- // If taken.
630
- let cond_start = sink. cur_offset ( ) ;
631
- let cond_disp_off = cond_start + 2 ;
632
- let cond_end = cond_start + 6 ;
633
-
634
- sink. use_label_at_offset ( cond_disp_off, * taken, LabelUse :: JmpRel32 ) ;
635
- let inverted: [ u8 ; 6 ] = [ 0x0F , 0x80 + ( cc. invert ( ) . get_enc ( ) ) , 0x00 , 0x00 , 0x00 , 0x00 ] ;
636
- sink. add_cond_branch ( cond_start, cond_end, * taken, & inverted[ ..] ) ;
637
-
638
- sink. put1 ( 0x0F ) ;
639
- sink. put1 ( 0x80 + cc. get_enc ( ) ) ;
640
- // Placeholder for the label value.
641
- sink. put4 ( 0x0 ) ;
642
-
643
- // If not taken.
644
- let uncond_start = sink. cur_offset ( ) ;
645
- let uncond_disp_off = uncond_start + 1 ;
646
- let uncond_end = uncond_start + 5 ;
647
-
648
- sink. use_label_at_offset ( uncond_disp_off, * not_taken, LabelUse :: JmpRel32 ) ;
649
- sink. add_uncond_branch ( uncond_start, uncond_end, * not_taken) ;
650
-
651
- sink. put1 ( 0xE9 ) ;
652
- // Placeholder for the label value.
653
- sink. put4 ( 0x0 ) ;
671
+ cond_jmp ( sink, * cc, * taken) ;
672
+ uncond_jmp ( sink, * not_taken) ;
654
673
}
655
674
656
675
Inst :: JmpCondOr {
@@ -671,56 +690,9 @@ pub(crate) fn emit(
671
690
// not_taken and that one block is the fallthrough block,
672
691
// all three branches can disappear.
673
692
674
- // jcc1 taken
675
- let cond_1_start = sink. cur_offset ( ) ;
676
- let cond_1_disp_off = cond_1_start + 2 ;
677
- let cond_1_end = cond_1_start + 6 ;
678
-
679
- sink. use_label_at_offset ( cond_1_disp_off, * taken, LabelUse :: JmpRel32 ) ;
680
- let inverted: [ u8 ; 6 ] = [
681
- 0x0F ,
682
- 0x80 + ( cc1. invert ( ) . get_enc ( ) ) ,
683
- 0x00 ,
684
- 0x00 ,
685
- 0x00 ,
686
- 0x00 ,
687
- ] ;
688
- sink. add_cond_branch ( cond_1_start, cond_1_end, * taken, & inverted[ ..] ) ;
689
-
690
- sink. put1 ( 0x0F ) ;
691
- sink. put1 ( 0x80 + cc1. get_enc ( ) ) ;
692
- sink. put4 ( 0x0 ) ;
693
-
694
- // jcc2 taken
695
- let cond_2_start = sink. cur_offset ( ) ;
696
- let cond_2_disp_off = cond_2_start + 2 ;
697
- let cond_2_end = cond_2_start + 6 ;
698
-
699
- sink. use_label_at_offset ( cond_2_disp_off, * taken, LabelUse :: JmpRel32 ) ;
700
- let inverted: [ u8 ; 6 ] = [
701
- 0x0F ,
702
- 0x80 + ( cc2. invert ( ) . get_enc ( ) ) ,
703
- 0x00 ,
704
- 0x00 ,
705
- 0x00 ,
706
- 0x00 ,
707
- ] ;
708
- sink. add_cond_branch ( cond_2_start, cond_2_end, * taken, & inverted[ ..] ) ;
709
-
710
- sink. put1 ( 0x0F ) ;
711
- sink. put1 ( 0x80 + cc2. get_enc ( ) ) ;
712
- sink. put4 ( 0x0 ) ;
713
-
714
- // jmp not_taken
715
- let uncond_start = sink. cur_offset ( ) ;
716
- let uncond_disp_off = uncond_start + 1 ;
717
- let uncond_end = uncond_start + 5 ;
718
-
719
- sink. use_label_at_offset ( uncond_disp_off, * not_taken, LabelUse :: JmpRel32 ) ;
720
- sink. add_uncond_branch ( uncond_start, uncond_end, * not_taken) ;
721
-
722
- sink. put1 ( 0xE9 ) ;
723
- sink. put4 ( 0x0 ) ;
693
+ cond_jmp ( sink, * cc1, * taken) ;
694
+ cond_jmp ( sink, * cc2, * taken) ;
695
+ uncond_jmp ( sink, * not_taken) ;
724
696
}
725
697
726
698
& Inst :: JmpTableSeq {
0 commit comments