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