1 //! Binary machine code emission.
2 //!
3 //! The `binemit` module contains code for translating Cranelift's intermediate representation into
4 //! binary machine code.
5 
6 mod memorysink;
7 mod relaxation;
8 mod shrink;
9 mod stackmap;
10 
11 pub use self::memorysink::{
12     MemoryCodeSink, NullRelocSink, NullStackmapSink, NullTrapSink, RelocSink, StackmapSink,
13     TrapSink,
14 };
15 pub use self::relaxation::relax_branches;
16 pub use self::shrink::shrink_instructions;
17 pub use self::stackmap::Stackmap;
18 use crate::ir::entities::Value;
19 use crate::ir::{ConstantOffset, ExternalName, Function, Inst, JumpTable, SourceLoc, TrapCode};
20 use crate::isa::TargetIsa;
21 pub use crate::regalloc::RegDiversions;
22 use core::fmt;
23 #[cfg(feature = "enable-serde")]
24 use serde::{Deserialize, Serialize};
25 
26 /// Offset in bytes from the beginning of the function.
27 ///
28 /// Cranelift can be used as a cross compiler, so we don't want to use a type like `usize` which
29 /// depends on the *host* platform, not the *target* platform.
30 pub type CodeOffset = u32;
31 
32 /// Addend to add to the symbol value.
33 pub type Addend = i64;
34 
35 /// Relocation kinds for every ISA
36 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
37 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
38 pub enum Reloc {
39     /// absolute 4-byte
40     Abs4,
41     /// absolute 8-byte
42     Abs8,
43     /// x86 PC-relative 4-byte
44     X86PCRel4,
45     /// x86 PC-relative 4-byte offset to trailing rodata
46     X86PCRelRodata4,
47     /// x86 call to PC-relative 4-byte
48     X86CallPCRel4,
49     /// x86 call to PLT-relative 4-byte
50     X86CallPLTRel4,
51     /// x86 GOT PC-relative 4-byte
52     X86GOTPCRel4,
53     /// Arm32 call target
54     Arm32Call,
55     /// Arm64 call target
56     Arm64Call,
57     /// RISC-V call target
58     RiscvCall,
59 }
60 
61 impl fmt::Display for Reloc {
62     /// Display trait implementation drops the arch, since its used in contexts where the arch is
63     /// already unambiguous, e.g. clif syntax with isa specified. In other contexts, use Debug.
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result64     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65         match *self {
66             Reloc::Abs4 => write!(f, "Abs4"),
67             Reloc::Abs8 => write!(f, "Abs8"),
68             Reloc::X86PCRel4 => write!(f, "PCRel4"),
69             Reloc::X86PCRelRodata4 => write!(f, "PCRelRodata4"),
70             Reloc::X86CallPCRel4 => write!(f, "CallPCRel4"),
71             Reloc::X86CallPLTRel4 => write!(f, "CallPLTRel4"),
72             Reloc::X86GOTPCRel4 => write!(f, "GOTPCRel4"),
73             Reloc::Arm32Call | Reloc::Arm64Call | Reloc::RiscvCall => write!(f, "Call"),
74         }
75     }
76 }
77 
78 /// Container for information about a vector of compiled code and its supporting read-only data.
79 ///
80 /// The code starts at offset 0 and is followed optionally by relocatable jump tables and copyable
81 /// (raw binary) read-only data.  Any padding between sections is always part of the section that
82 /// precedes the boundary between the sections.
83 #[derive(PartialEq)]
84 pub struct CodeInfo {
85     /// Number of bytes of machine code (the code starts at offset 0).
86     pub code_size: CodeOffset,
87 
88     /// Number of bytes of jumptables.
89     pub jumptables_size: CodeOffset,
90 
91     /// Number of bytes of rodata.
92     pub rodata_size: CodeOffset,
93 
94     /// Number of bytes in total.
95     pub total_size: CodeOffset,
96 }
97 
98 impl CodeInfo {
99     /// Offset of any relocatable jump tables, or equal to rodata if there are no jump tables.
jumptables(&self) -> CodeOffset100     pub fn jumptables(&self) -> CodeOffset {
101         self.code_size
102     }
103 
104     /// Offset of any copyable read-only data, or equal to total_size if there are no rodata.
rodata(&self) -> CodeOffset105     pub fn rodata(&self) -> CodeOffset {
106         self.code_size + self.jumptables_size
107     }
108 }
109 
110 /// Abstract interface for adding bytes to the code segment.
111 ///
112 /// A `CodeSink` will receive all of the machine code for a function. It also accepts relocations
113 /// which are locations in the code section that need to be fixed up when linking.
114 pub trait CodeSink {
115     /// Get the current position.
offset(&self) -> CodeOffset116     fn offset(&self) -> CodeOffset;
117 
118     /// Add 1 byte to the code section.
put1(&mut self, _: u8)119     fn put1(&mut self, _: u8);
120 
121     /// Add 2 bytes to the code section.
put2(&mut self, _: u16)122     fn put2(&mut self, _: u16);
123 
124     /// Add 4 bytes to the code section.
put4(&mut self, _: u32)125     fn put4(&mut self, _: u32);
126 
127     /// Add 8 bytes to the code section.
put8(&mut self, _: u64)128     fn put8(&mut self, _: u64);
129 
130     /// Add a relocation referencing an EBB at the current offset.
reloc_ebb(&mut self, _: Reloc, _: CodeOffset)131     fn reloc_ebb(&mut self, _: Reloc, _: CodeOffset);
132 
133     /// Add a relocation referencing an external symbol plus the addend at the current offset.
reloc_external(&mut self, _: Reloc, _: &ExternalName, _: Addend)134     fn reloc_external(&mut self, _: Reloc, _: &ExternalName, _: Addend);
135 
136     /// Add a relocation referencing a constant.
reloc_constant(&mut self, _: Reloc, _: ConstantOffset)137     fn reloc_constant(&mut self, _: Reloc, _: ConstantOffset);
138 
139     /// Add a relocation referencing a jump table.
reloc_jt(&mut self, _: Reloc, _: JumpTable)140     fn reloc_jt(&mut self, _: Reloc, _: JumpTable);
141 
142     /// Add trap information for the current offset.
trap(&mut self, _: TrapCode, _: SourceLoc)143     fn trap(&mut self, _: TrapCode, _: SourceLoc);
144 
145     /// Machine code output is complete, jump table data may follow.
begin_jumptables(&mut self)146     fn begin_jumptables(&mut self);
147 
148     /// Jump table output is complete, raw read-only data may follow.
begin_rodata(&mut self)149     fn begin_rodata(&mut self);
150 
151     /// Read-only data output is complete, we're done.
end_codegen(&mut self)152     fn end_codegen(&mut self);
153 
154     /// Add a stackmap at the current code offset.
add_stackmap(&mut self, _: &[Value], _: &Function, _: &dyn TargetIsa)155     fn add_stackmap(&mut self, _: &[Value], _: &Function, _: &dyn TargetIsa);
156 }
157 
158 /// Report a bad encoding error.
159 #[cold]
bad_encoding(func: &Function, inst: Inst) -> !160 pub fn bad_encoding(func: &Function, inst: Inst) -> ! {
161     panic!(
162         "Bad encoding {} for {}",
163         func.encodings[inst],
164         func.dfg.display_inst(inst, None)
165     );
166 }
167 
168 /// Emit a function to `sink`, given an instruction emitter function.
169 ///
170 /// This function is called from the `TargetIsa::emit_function()` implementations with the
171 /// appropriate instruction emitter.
emit_function<CS, EI>(func: &Function, emit_inst: EI, sink: &mut CS, isa: &dyn TargetIsa) where CS: CodeSink, EI: Fn(&Function, Inst, &mut RegDiversions, &mut CS, &dyn TargetIsa),172 pub fn emit_function<CS, EI>(func: &Function, emit_inst: EI, sink: &mut CS, isa: &dyn TargetIsa)
173 where
174     CS: CodeSink,
175     EI: Fn(&Function, Inst, &mut RegDiversions, &mut CS, &dyn TargetIsa),
176 {
177     let mut divert = RegDiversions::new();
178     for ebb in func.layout.ebbs() {
179         divert.at_ebb(&func.entry_diversions, ebb);
180         debug_assert_eq!(func.offsets[ebb], sink.offset());
181         for inst in func.layout.ebb_insts(ebb) {
182             emit_inst(func, inst, &mut divert, sink, isa);
183         }
184     }
185 
186     sink.begin_jumptables();
187 
188     // Output jump tables.
189     for (jt, jt_data) in func.jump_tables.iter() {
190         let jt_offset = func.jt_offsets[jt];
191         for ebb in jt_data.iter() {
192             let rel_offset: i32 = func.offsets[*ebb] as i32 - jt_offset as i32;
193             sink.put4(rel_offset as u32)
194         }
195     }
196 
197     sink.begin_rodata();
198 
199     // Output constants.
200     for (_, constant_data) in func.dfg.constants.iter() {
201         for byte in constant_data.iter() {
202             sink.put1(*byte)
203         }
204     }
205 
206     sink.end_codegen();
207 }
208