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