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 73 impl fmt::Display for Reloc { 74 /// Display trait implementation drops the arch, since its used in contexts where the arch is 75 /// already unambiguous, e.g. clif syntax with isa specified. In other contexts, use Debug. 76 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 77 match *self { 78 Self::Abs4 => write!(f, "Abs4"), 79 Self::Abs8 => write!(f, "Abs8"), 80 Self::S390xPCRel32Dbl => write!(f, "PCRel32Dbl"), 81 Self::X86PCRel4 => write!(f, "PCRel4"), 82 Self::X86PCRelRodata4 => write!(f, "PCRelRodata4"), 83 Self::X86CallPCRel4 => write!(f, "CallPCRel4"), 84 Self::X86CallPLTRel4 => write!(f, "CallPLTRel4"), 85 Self::X86GOTPCRel4 => write!(f, "GOTPCRel4"), 86 Self::Arm32Call | Self::Arm64Call | Self::RiscvCall => write!(f, "Call"), 87 88 Self::ElfX86_64TlsGd => write!(f, "ElfX86_64TlsGd"), 89 Self::MachOX86_64Tlv => write!(f, "MachOX86_64Tlv"), 90 } 91 } 92 } 93 94 /// Container for information about a vector of compiled code and its supporting read-only data. 95 /// 96 /// The code starts at offset 0 and is followed optionally by relocatable jump tables and copyable 97 /// (raw binary) read-only data. Any padding between sections is always part of the section that 98 /// precedes the boundary between the sections. 99 #[derive(PartialEq)] 100 pub struct CodeInfo { 101 /// Number of bytes of machine code (the code starts at offset 0). 102 pub code_size: CodeOffset, 103 104 /// Number of bytes of jumptables. 105 pub jumptables_size: CodeOffset, 106 107 /// Number of bytes of rodata. 108 pub rodata_size: CodeOffset, 109 110 /// Number of bytes in total. 111 pub total_size: CodeOffset, 112 } 113 114 impl CodeInfo { 115 /// Offset of any relocatable jump tables, or equal to rodata if there are no jump tables. 116 pub fn jumptables(&self) -> CodeOffset { 117 self.code_size 118 } 119 120 /// Offset of any copyable read-only data, or equal to total_size if there are no rodata. 121 pub fn rodata(&self) -> CodeOffset { 122 self.code_size + self.jumptables_size 123 } 124 } 125 126 /// Abstract interface for adding bytes to the code segment. 127 /// 128 /// A `CodeSink` will receive all of the machine code for a function. It also accepts relocations 129 /// which are locations in the code section that need to be fixed up when linking. 130 pub trait CodeSink { 131 /// Get the current position. 132 fn offset(&self) -> CodeOffset; 133 134 /// Add 1 byte to the code section. 135 fn put1(&mut self, _: u8); 136 137 /// Add 2 bytes to the code section. 138 fn put2(&mut self, _: u16); 139 140 /// Add 4 bytes to the code section. 141 fn put4(&mut self, _: u32); 142 143 /// Add 8 bytes to the code section. 144 fn put8(&mut self, _: u64); 145 146 /// Add a relocation referencing an external symbol plus the addend at the current offset. 147 fn reloc_external(&mut self, _: SourceLoc, _: Reloc, _: &ExternalName, _: Addend); 148 149 /// Add a relocation referencing a constant. 150 fn reloc_constant(&mut self, _: Reloc, _: ConstantOffset); 151 152 /// Add a relocation referencing a jump table. 153 fn reloc_jt(&mut self, _: Reloc, _: JumpTable); 154 155 /// Add trap information for the current offset. 156 fn trap(&mut self, _: TrapCode, _: SourceLoc); 157 158 /// Machine code output is complete, jump table data may follow. 159 fn begin_jumptables(&mut self); 160 161 /// Jump table output is complete, raw read-only data may follow. 162 fn begin_rodata(&mut self); 163 164 /// Read-only data output is complete, we're done. 165 fn end_codegen(&mut self); 166 167 /// Add a stack map at the current code offset. 168 fn add_stack_map(&mut self, _: &[Value], _: &Function, _: &dyn TargetIsa); 169 170 /// Add a call site for a call with the given opcode, returning at the current offset. 171 fn add_call_site(&mut self, _: Opcode, _: SourceLoc) { 172 // Default implementation doesn't need to do anything. 173 } 174 } 175 176 /// Report a bad encoding error. 177 #[cold] 178 pub fn bad_encoding(func: &Function, inst: Inst) -> ! { 179 panic!( 180 "Bad encoding {} for {}", 181 func.encodings[inst], 182 func.dfg.display_inst(inst, None) 183 ); 184 } 185 186 /// Emit a function to `sink`, given an instruction emitter function. 187 /// 188 /// This function is called from the `TargetIsa::emit_function()` implementations with the 189 /// appropriate instruction emitter. 190 pub fn emit_function<CS, EI>(func: &Function, emit_inst: EI, sink: &mut CS, isa: &dyn TargetIsa) 191 where 192 CS: CodeSink, 193 EI: Fn(&Function, Inst, &mut RegDiversions, &mut CS, &dyn TargetIsa), 194 { 195 let mut divert = RegDiversions::new(); 196 for block in func.layout.blocks() { 197 divert.at_block(&func.entry_diversions, block); 198 debug_assert_eq!(func.offsets[block], sink.offset()); 199 for inst in func.layout.block_insts(block) { 200 emit_inst(func, inst, &mut divert, sink, isa); 201 } 202 } 203 204 sink.begin_jumptables(); 205 206 // Output jump tables. 207 for (jt, jt_data) in func.jump_tables.iter() { 208 let jt_offset = func.jt_offsets[jt]; 209 for block in jt_data.iter() { 210 let rel_offset: i32 = func.offsets[*block] as i32 - jt_offset as i32; 211 sink.put4(rel_offset as u32) 212 } 213 } 214 215 sink.begin_rodata(); 216 217 // Output constants. 218 for (_, constant_data) in func.dfg.constants.iter() { 219 for byte in constant_data.iter() { 220 sink.put1(*byte) 221 } 222 } 223 224 sink.end_codegen(); 225 } 226