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 stack_map;
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::stack_map::StackMap;
18 use crate::ir::entities::Value;
19 use crate::ir::{
20     ConstantOffset, ExternalName, Function, Inst, JumpTable, Opcode, SourceLoc, TrapCode,
21 };
22 use crate::isa::TargetIsa;
23 pub use crate::regalloc::RegDiversions;
24 use core::fmt;
25 #[cfg(feature = "enable-serde")]
26 use serde::{Deserialize, Serialize};
27 
28 /// Offset in bytes from the beginning of the function.
29 ///
30 /// Cranelift can be used as a cross compiler, so we don't want to use a type like `usize` which
31 /// depends on the *host* platform, not the *target* platform.
32 pub type CodeOffset = u32;
33 
34 /// Addend to add to the symbol value.
35 pub type Addend = i64;
36 
37 /// Relocation kinds for every ISA
38 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
39 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
40 pub enum Reloc {
41     /// absolute 4-byte
42     Abs4,
43     /// absolute 8-byte
44     Abs8,
45     /// x86 PC-relative 4-byte
46     X86PCRel4,
47     /// x86 PC-relative 4-byte offset to trailing rodata
48     X86PCRelRodata4,
49     /// x86 call to PC-relative 4-byte
50     X86CallPCRel4,
51     /// x86 call to PLT-relative 4-byte
52     X86CallPLTRel4,
53     /// x86 GOT PC-relative 4-byte
54     X86GOTPCRel4,
55     /// Arm32 call target
56     Arm32Call,
57     /// Arm64 call target. Encoded as bottom 26 bits of instruction. This
58     /// value is sign-extended, multiplied by 4, and added to the PC of
59     /// the call instruction to form the destination address.
60     Arm64Call,
61     /// RISC-V call target
62     RiscvCall,
63     /// s390x PC-relative 4-byte offset
64     S390xPCRel32Dbl,
65 
66     /// Elf x86_64 32 bit signed PC relative offset to two GOT entries for GD symbol.
67     ElfX86_64TlsGd,
68 
69     /// Mach-O x86_64 32 bit signed PC relative offset to a `__thread_vars` entry.
70     MachOX86_64Tlv,
71 
72     /// AArch64 TLS GD
73     /// Set an ADRP immediate field to the top 21 bits of the final address. Checks for overflow.
74     /// This is equivalent to `R_AARCH64_TLSGD_ADR_PAGE21` in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#relocations-for-thread-local-storage)
75     Aarch64TlsGdAdrPage21,
76 
77     /// AArch64 TLS GD
78     /// Set the add immediate field to the low 12 bits of the final address. Does not check for overflow.
79     /// This is equivalent to `R_AARCH64_TLSGD_ADD_LO12_NC` in the [aaelf64](https://github.com/ARM-software/abi-aa/blob/2bcab1e3b22d55170c563c3c7940134089176746/aaelf64/aaelf64.rst#relocations-for-thread-local-storage)
80     Aarch64TlsGdAddLo12Nc,
81 }
82 
83 impl fmt::Display for Reloc {
84     /// Display trait implementation drops the arch, since its used in contexts where the arch is
85     /// already unambiguous, e.g. clif syntax with isa specified. In other contexts, use Debug.
86     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87         match *self {
88             Self::Abs4 => write!(f, "Abs4"),
89             Self::Abs8 => write!(f, "Abs8"),
90             Self::S390xPCRel32Dbl => write!(f, "PCRel32Dbl"),
91             Self::X86PCRel4 => write!(f, "PCRel4"),
92             Self::X86PCRelRodata4 => write!(f, "PCRelRodata4"),
93             Self::X86CallPCRel4 => write!(f, "CallPCRel4"),
94             Self::X86CallPLTRel4 => write!(f, "CallPLTRel4"),
95             Self::X86GOTPCRel4 => write!(f, "GOTPCRel4"),
96             Self::Arm32Call | Self::Arm64Call | Self::RiscvCall => write!(f, "Call"),
97 
98             Self::ElfX86_64TlsGd => write!(f, "ElfX86_64TlsGd"),
99             Self::MachOX86_64Tlv => write!(f, "MachOX86_64Tlv"),
100             Self::Aarch64TlsGdAdrPage21 => write!(f, "Aarch64TlsGdAdrPage21"),
101             Self::Aarch64TlsGdAddLo12Nc => write!(f, "Aarch64TlsGdAddLo12Nc"),
102         }
103     }
104 }
105 
106 /// Container for information about a vector of compiled code and its supporting read-only data.
107 ///
108 /// The code starts at offset 0 and is followed optionally by relocatable jump tables and copyable
109 /// (raw binary) read-only data.  Any padding between sections is always part of the section that
110 /// precedes the boundary between the sections.
111 #[derive(PartialEq)]
112 pub struct CodeInfo {
113     /// Number of bytes of machine code (the code starts at offset 0).
114     pub code_size: CodeOffset,
115 
116     /// Number of bytes of jumptables.
117     pub jumptables_size: CodeOffset,
118 
119     /// Number of bytes of rodata.
120     pub rodata_size: CodeOffset,
121 
122     /// Number of bytes in total.
123     pub total_size: CodeOffset,
124 }
125 
126 impl CodeInfo {
127     /// Offset of any relocatable jump tables, or equal to rodata if there are no jump tables.
128     pub fn jumptables(&self) -> CodeOffset {
129         self.code_size
130     }
131 
132     /// Offset of any copyable read-only data, or equal to total_size if there are no rodata.
133     pub fn rodata(&self) -> CodeOffset {
134         self.code_size + self.jumptables_size
135     }
136 }
137 
138 /// Abstract interface for adding bytes to the code segment.
139 ///
140 /// A `CodeSink` will receive all of the machine code for a function. It also accepts relocations
141 /// which are locations in the code section that need to be fixed up when linking.
142 pub trait CodeSink {
143     /// Get the current position.
144     fn offset(&self) -> CodeOffset;
145 
146     /// Add 1 byte to the code section.
147     fn put1(&mut self, _: u8);
148 
149     /// Add 2 bytes to the code section.
150     fn put2(&mut self, _: u16);
151 
152     /// Add 4 bytes to the code section.
153     fn put4(&mut self, _: u32);
154 
155     /// Add 8 bytes to the code section.
156     fn put8(&mut self, _: u64);
157 
158     /// Add a relocation referencing an external symbol plus the addend at the current offset.
159     fn reloc_external(&mut self, _: SourceLoc, _: Reloc, _: &ExternalName, _: Addend);
160 
161     /// Add a relocation referencing a constant.
162     fn reloc_constant(&mut self, _: Reloc, _: ConstantOffset);
163 
164     /// Add a relocation referencing a jump table.
165     fn reloc_jt(&mut self, _: Reloc, _: JumpTable);
166 
167     /// Add trap information for the current offset.
168     fn trap(&mut self, _: TrapCode, _: SourceLoc);
169 
170     /// Machine code output is complete, jump table data may follow.
171     fn begin_jumptables(&mut self);
172 
173     /// Jump table output is complete, raw read-only data may follow.
174     fn begin_rodata(&mut self);
175 
176     /// Read-only data output is complete, we're done.
177     fn end_codegen(&mut self);
178 
179     /// Add a stack map at the current code offset.
180     fn add_stack_map(&mut self, _: &[Value], _: &Function, _: &dyn TargetIsa);
181 
182     /// Add a call site for a call with the given opcode, returning at the current offset.
183     fn add_call_site(&mut self, _: Opcode, _: SourceLoc) {
184         // Default implementation doesn't need to do anything.
185     }
186 }
187 
188 /// Report a bad encoding error.
189 #[cold]
190 pub fn bad_encoding(func: &Function, inst: Inst) -> ! {
191     panic!(
192         "Bad encoding {} for {}",
193         func.encodings[inst],
194         func.dfg.display_inst(inst, None)
195     );
196 }
197 
198 /// Emit a function to `sink`, given an instruction emitter function.
199 ///
200 /// This function is called from the `TargetIsa::emit_function()` implementations with the
201 /// appropriate instruction emitter.
202 pub fn emit_function<CS, EI>(func: &Function, emit_inst: EI, sink: &mut CS, isa: &dyn TargetIsa)
203 where
204     CS: CodeSink,
205     EI: Fn(&Function, Inst, &mut RegDiversions, &mut CS, &dyn TargetIsa),
206 {
207     let mut divert = RegDiversions::new();
208     for block in func.layout.blocks() {
209         divert.at_block(&func.entry_diversions, block);
210         debug_assert_eq!(func.offsets[block], sink.offset());
211         for inst in func.layout.block_insts(block) {
212             emit_inst(func, inst, &mut divert, sink, isa);
213         }
214     }
215 
216     sink.begin_jumptables();
217 
218     // Output jump tables.
219     for (jt, jt_data) in func.jump_tables.iter() {
220         let jt_offset = func.jt_offsets[jt];
221         for block in jt_data.iter() {
222             let rel_offset: i32 = func.offsets[*block] as i32 - jt_offset as i32;
223             sink.put4(rel_offset as u32)
224         }
225     }
226 
227     sink.begin_rodata();
228 
229     // Output constants.
230     for (_, constant_data) in func.dfg.constants.iter() {
231         for byte in constant_data.iter() {
232             sink.put1(*byte)
233         }
234     }
235 
236     sink.end_codegen();
237 }
238