xref: /wasmtime-44.0.1/crates/cranelift/src/obj.rs (revision cd53bed8)
1 //! Object file builder.
2 //!
3 //! Creates ELF image based on `Compilation` information. The ELF contains
4 //! functions and trampolines in the ".text" section. It also contains all
5 //! relocation records for the linking stage. If DWARF sections exist, their
6 //! content will be written as well.
7 //!
8 //! The object file has symbols for each function and trampoline, as well as
9 //! symbols that refer to libcalls.
10 //!
11 //! The function symbol names have format "_wasm_function_N", where N is
12 //! `FuncIndex`. The defined wasm function symbols refer to a JIT compiled
13 //! function body, the imported wasm function do not. The trampolines symbol
14 //! names have format "_trampoline_N", where N is `SignatureIndex`.
15 
16 use crate::{CompiledFunction, RelocationTarget};
17 use anyhow::Result;
18 use cranelift_codegen::isa::{
19     unwind::{systemv, UnwindInfo},
20     TargetIsa,
21 };
22 use cranelift_codegen::TextSectionBuilder;
23 use gimli::write::{Address, EhFrame, EndianVec, FrameTable, Writer};
24 use gimli::RunTimeEndian;
25 use object::write::{Object, SectionId, StandardSegment, Symbol, SymbolId, SymbolSection};
26 use object::{Architecture, SectionKind, SymbolFlags, SymbolKind, SymbolScope};
27 use std::convert::TryFrom;
28 use std::ops::Range;
29 use wasmtime_environ::FuncIndex;
30 
31 const TEXT_SECTION_NAME: &[u8] = b".text";
32 
33 /// A helper structure used to assemble the final text section of an exectuable,
34 /// plus unwinding information and other related details.
35 ///
36 /// This builder relies on Cranelift-specific internals but assembles into a
37 /// generic `Object` which will get further appended to in a compiler-agnostic
38 /// fashion later.
39 pub struct ModuleTextBuilder<'a> {
40     /// The target that we're compiling for, used to query target-specific
41     /// information as necessary.
42     isa: &'a dyn TargetIsa,
43 
44     /// The object file that we're generating code into.
45     obj: &'a mut Object<'static>,
46 
47     /// The WebAssembly module we're generating code for.
48     text_section: SectionId,
49 
50     unwind_info: UnwindInfoBuilder<'a>,
51 
52     /// In-progress text section that we're using cranelift's `MachBuffer` to
53     /// build to resolve relocations (calls) between functions.
54     text: Box<dyn TextSectionBuilder>,
55 }
56 
57 impl<'a> ModuleTextBuilder<'a> {
58     /// Creates a new builder for the text section of an executable.
59     ///
60     /// The `.text` section will be appended to the specified `obj` along with
61     /// any unwinding or such information as necessary. The `num_funcs`
62     /// parameter indicates the number of times the `append_func` function will
63     /// be called. The `finish` function will panic if this contract is not met.
64     pub fn new(obj: &'a mut Object<'static>, isa: &'a dyn TargetIsa, num_funcs: usize) -> Self {
65         // Entire code (functions and trampolines) will be placed
66         // in the ".text" section.
67         let text_section = obj.add_section(
68             obj.segment_name(StandardSegment::Text).to_vec(),
69             TEXT_SECTION_NAME.to_vec(),
70             SectionKind::Text,
71         );
72 
73         Self {
74             isa,
75             obj,
76             text_section,
77             unwind_info: Default::default(),
78             text: isa.text_section_builder(num_funcs),
79         }
80     }
81 
82     /// Appends the `func` specified named `name` to this object.
83     ///
84     /// The `resolve_reloc_target` closure is used to resolve a relocation
85     /// target to an adjacent function which has already been added or will be
86     /// added to this object. The argument is the relocation target specified
87     /// within `CompiledFunction` and the return value must be an index where
88     /// the target will be defined by the `n`th call to `append_func`.
89     ///
90     /// Returns the symbol associated with the function as well as the range
91     /// that the function resides within the text section.
92     pub fn append_func(
93         &mut self,
94         name: &str,
95         func: &'a CompiledFunction,
96         resolve_reloc_target: impl Fn(FuncIndex) -> usize,
97     ) -> (SymbolId, Range<u64>) {
98         let body_len = func.body.len() as u64;
99         let off = self.text.append(
100             true,
101             &func.body,
102             self.isa.function_alignment().max(func.alignment),
103         );
104 
105         let symbol_id = self.obj.add_symbol(Symbol {
106             name: name.as_bytes().to_vec(),
107             value: off,
108             size: body_len,
109             kind: SymbolKind::Text,
110             scope: SymbolScope::Compilation,
111             weak: false,
112             section: SymbolSection::Section(self.text_section),
113             flags: SymbolFlags::None,
114         });
115 
116         if let Some(info) = &func.unwind_info {
117             self.unwind_info.push(off, body_len, info);
118         }
119 
120         for r in func.relocations.iter() {
121             match r.reloc_target {
122                 // Relocations against user-defined functions means that this is
123                 // a relocation against a module-local function, typically a
124                 // call between functions. The `text` field is given priority to
125                 // resolve this relocation before we actually emit an object
126                 // file, but if it can't handle it then we pass through the
127                 // relocation.
128                 RelocationTarget::UserFunc(index) => {
129                     let target = resolve_reloc_target(index);
130                     if self
131                         .text
132                         .resolve_reloc(off + u64::from(r.offset), r.reloc, r.addend, target)
133                     {
134                         continue;
135                     }
136 
137                     // At this time it's expected that all relocations are
138                     // handled by `text.resolve_reloc`, and anything that isn't
139                     // handled is a bug in `text.resolve_reloc` or something
140                     // transitively there. If truly necessary, though, then this
141                     // loop could also be updated to forward the relocation to
142                     // the final object file as well.
143                     panic!(
144                         "unresolved relocation could not be procesed against \
145                          {index:?}: {r:?}"
146                     );
147                 }
148 
149                 // At this time it's not expected that any libcall relocations
150                 // are generated. Ideally we don't want relocations against
151                 // libcalls anyway as libcalls should go through indirect
152                 // `VMContext` tables to avoid needing to apply relocations at
153                 // module-load time as well.
154                 RelocationTarget::LibCall(call) => {
155                     unimplemented!("cannot generate relocation against libcall {call:?}");
156                 }
157             };
158         }
159         (symbol_id, off..off + body_len)
160     }
161 
162     /// Forces "veneers" to be used for inter-function calls in the text
163     /// section which means that in-bounds optimized addresses are never used.
164     ///
165     /// This is only useful for debugging cranelift itself and typically this
166     /// option is disabled.
167     pub fn force_veneers(&mut self) {
168         self.text.force_veneers();
169     }
170 
171     /// Appends the specified amount of bytes of padding into the text section.
172     ///
173     /// This is only useful when fuzzing and/or debugging cranelift itself and
174     /// for production scenarios `padding` is 0 and this function does nothing.
175     pub fn append_padding(&mut self, padding: usize) {
176         if padding == 0 {
177             return;
178         }
179         self.text.append(false, &vec![0; padding], 1);
180     }
181 
182     /// Indicates that the text section has been written completely and this
183     /// will finish appending it to the original object.
184     ///
185     /// Note that this will also write out the unwind information sections if
186     /// necessary.
187     pub fn finish(mut self) {
188         // Finish up the text section now that we're done adding functions.
189         let text = self.text.finish();
190         self.obj
191             .section_mut(self.text_section)
192             .set_data(text, self.isa.code_section_alignment());
193 
194         // Append the unwind information for all our functions, if necessary.
195         self.unwind_info
196             .append_section(self.isa, self.obj, self.text_section);
197     }
198 }
199 
200 /// Builder used to create unwind information for a set of functions added to a
201 /// text section.
202 #[derive(Default)]
203 struct UnwindInfoBuilder<'a> {
204     windows_xdata: Vec<u8>,
205     windows_pdata: Vec<RUNTIME_FUNCTION>,
206     systemv_unwind_info: Vec<(u64, &'a systemv::UnwindInfo)>,
207 }
208 
209 // This is a mirror of `RUNTIME_FUNCTION` in the Windows API, but defined here
210 // to ensure everything is always `u32` and to have it available on all
211 // platforms. Note that all of these specifiers here are relative to a "base
212 // address" which we define as the base of where the text section is eventually
213 // loaded.
214 #[allow(non_camel_case_types)]
215 struct RUNTIME_FUNCTION {
216     begin: u32,
217     end: u32,
218     unwind_address: u32,
219 }
220 
221 impl<'a> UnwindInfoBuilder<'a> {
222     /// Pushes the unwind information for a function into this builder.
223     ///
224     /// The function being described must be located at `function_offset` within
225     /// the text section itself, and the function's size is specified by
226     /// `function_len`.
227     ///
228     /// The `info` should come from Cranelift. and is handled here depending on
229     /// its flavor.
230     fn push(&mut self, function_offset: u64, function_len: u64, info: &'a UnwindInfo) {
231         match info {
232             // Windows unwind information is stored in two locations:
233             //
234             // * First is the actual unwinding information which is stored
235             //   in the `.xdata` section. This is where `info`'s emitted
236             //   information will go into.
237             // * Second are pointers to connect all this unwind information,
238             //   stored in the `.pdata` section. The `.pdata` section is an
239             //   array of `RUNTIME_FUNCTION` structures.
240             //
241             // Due to how these will be loaded at runtime the `.pdata` isn't
242             // actually assembled byte-wise here. Instead that's deferred to
243             // happen later during `write_windows_unwind_info` which will apply
244             // a further offset to `unwind_address`.
245             UnwindInfo::WindowsX64(info) => {
246                 let unwind_size = info.emit_size();
247                 let mut unwind_info = vec![0; unwind_size];
248                 info.emit(&mut unwind_info);
249 
250                 // `.xdata` entries are always 4-byte aligned
251                 //
252                 // FIXME: in theory we could "intern" the `unwind_info` value
253                 // here within the `.xdata` section. Most of our unwind
254                 // information for functions is probably pretty similar in which
255                 // case the `.xdata` could be quite small and `.pdata` could
256                 // have multiple functions point to the same unwinding
257                 // information.
258                 while self.windows_xdata.len() % 4 != 0 {
259                     self.windows_xdata.push(0x00);
260                 }
261                 let unwind_address = self.windows_xdata.len();
262                 self.windows_xdata.extend_from_slice(&unwind_info);
263 
264                 // Record a `RUNTIME_FUNCTION` which this will point to.
265                 self.windows_pdata.push(RUNTIME_FUNCTION {
266                     begin: u32::try_from(function_offset).unwrap(),
267                     end: u32::try_from(function_offset + function_len).unwrap(),
268                     unwind_address: u32::try_from(unwind_address).unwrap(),
269                 });
270             }
271 
272             // System-V is different enough that we just record the unwinding
273             // information to get processed at a later time.
274             UnwindInfo::SystemV(info) => {
275                 self.systemv_unwind_info.push((function_offset, info));
276             }
277 
278             _ => panic!("some unwind info isn't handled here"),
279         }
280     }
281 
282     /// Appends the unwind information section, if any, to the `obj` specified.
283     ///
284     /// This function must be called immediately after the text section was
285     /// added to a builder. The unwind information section must trail the text
286     /// section immediately.
287     ///
288     /// The `text_section`'s section identifier is passed into this function.
289     fn append_section(&self, isa: &dyn TargetIsa, obj: &mut Object<'_>, text_section: SectionId) {
290         // This write will align the text section to a page boundary and then
291         // return the offset at that point. This gives us the full size of the
292         // text section at that point, after alignment.
293         let text_section_size =
294             obj.append_section_data(text_section, &[], isa.code_section_alignment());
295 
296         if self.windows_xdata.len() > 0 {
297             assert!(self.systemv_unwind_info.len() == 0);
298             // The `.xdata` section must come first to be just-after the `.text`
299             // section for the reasons documented in `write_windows_unwind_info`
300             // below.
301             let segment = obj.segment_name(StandardSegment::Data).to_vec();
302             let xdata_id = obj.add_section(segment, b".xdata".to_vec(), SectionKind::ReadOnlyData);
303             let segment = obj.segment_name(StandardSegment::Data).to_vec();
304             let pdata_id = obj.add_section(segment, b".pdata".to_vec(), SectionKind::ReadOnlyData);
305             self.write_windows_unwind_info(obj, xdata_id, pdata_id, text_section_size);
306         }
307 
308         if self.systemv_unwind_info.len() > 0 {
309             let segment = obj.segment_name(StandardSegment::Data).to_vec();
310             let section_id =
311                 obj.add_section(segment, b".eh_frame".to_vec(), SectionKind::ReadOnlyData);
312             self.write_systemv_unwind_info(isa, obj, section_id, text_section_size)
313         }
314     }
315 
316     /// This function appends a nonstandard section to the object which is only
317     /// used during `CodeMemory::publish`.
318     ///
319     /// This custom section effectively stores a `[RUNTIME_FUNCTION; N]` into
320     /// the object file itself. This way registration of unwind info can simply
321     /// pass this slice to the OS itself and there's no need to recalculate
322     /// anything on the other end of loading a module from a precompiled object.
323     ///
324     /// Support for reading this is in `crates/jit/src/unwind/winx64.rs`.
325     fn write_windows_unwind_info(
326         &self,
327         obj: &mut Object<'_>,
328         xdata_id: SectionId,
329         pdata_id: SectionId,
330         text_section_size: u64,
331     ) {
332         // Currently the binary format supported here only supports
333         // little-endian for x86_64, or at least that's all where it's tested.
334         // This may need updates for other platforms.
335         assert_eq!(obj.architecture(), Architecture::X86_64);
336 
337         // Append the `.xdata` section, or the actual unwinding information
338         // codes and such which were built as we found unwind information for
339         // functions.
340         obj.append_section_data(xdata_id, &self.windows_xdata, 4);
341 
342         // Next append the `.pdata` section, or the array of `RUNTIME_FUNCTION`
343         // structures stored in the binary.
344         //
345         // This memory will be passed at runtime to `RtlAddFunctionTable` which
346         // takes a "base address" and the entries within `RUNTIME_FUNCTION` are
347         // all relative to this base address. The base address we pass is the
348         // address of the text section itself so all the pointers here must be
349         // text-section-relative. The `begin` and `end` fields for the function
350         // it describes are already text-section-relative, but the
351         // `unwind_address` field needs to be updated here since the value
352         // stored right now is `xdata`-section-relative. We know that the
353         // `xdata` section follows the `.text` section so the
354         // `text_section_size` is added in to calculate the final
355         // `.text`-section-relative address of the unwind information.
356         let mut pdata = Vec::with_capacity(self.windows_pdata.len() * 3 * 4);
357         for info in self.windows_pdata.iter() {
358             pdata.extend_from_slice(&info.begin.to_le_bytes());
359             pdata.extend_from_slice(&info.end.to_le_bytes());
360             let address = text_section_size + u64::from(info.unwind_address);
361             let address = u32::try_from(address).unwrap();
362             pdata.extend_from_slice(&address.to_le_bytes());
363         }
364         obj.append_section_data(pdata_id, &pdata, 4);
365     }
366 
367     /// This function appends a nonstandard section to the object which is only
368     /// used during `CodeMemory::publish`.
369     ///
370     /// This will generate a `.eh_frame` section, but not one that can be
371     /// naively loaded. The goal of this section is that we can create the
372     /// section once here and never again does it need to change. To describe
373     /// dynamically loaded functions though each individual FDE needs to talk
374     /// about the function's absolute address that it's referencing. Naturally
375     /// we don't actually know the function's absolute address when we're
376     /// creating an object here.
377     ///
378     /// To solve this problem the FDE address encoding mode is set to
379     /// `DW_EH_PE_pcrel`. This means that the actual effective address that the
380     /// FDE describes is a relative to the address of the FDE itself. By
381     /// leveraging this relative-ness we can assume that the relative distance
382     /// between the FDE and the function it describes is constant, which should
383     /// allow us to generate an FDE ahead-of-time here.
384     ///
385     /// For now this assumes that all the code of functions will start at a
386     /// page-aligned address when loaded into memory. The eh_frame encoded here
387     /// then assumes that the text section is itself page aligned to its size
388     /// and the eh_frame will follow just after the text section. This means
389     /// that the relative offsets we're using here is the FDE going backwards
390     /// into the text section itself.
391     ///
392     /// Note that the library we're using to create the FDEs, `gimli`, doesn't
393     /// actually encode addresses relative to the FDE itself. Instead the
394     /// addresses are encoded relative to the start of the `.eh_frame` section.
395     /// This makes it much easier for us where we provide the relative offset
396     /// from the start of `.eh_frame` to the function in the text section, which
397     /// given our layout basically means the offset of the function in the text
398     /// section from the end of the text section.
399     ///
400     /// A final note is that the reason we page-align the text section's size is
401     /// so the .eh_frame lives on a separate page from the text section itself.
402     /// This allows `.eh_frame` to have different virtual memory permissions,
403     /// such as being purely read-only instead of read/execute like the code
404     /// bits.
405     fn write_systemv_unwind_info(
406         &self,
407         isa: &dyn TargetIsa,
408         obj: &mut Object<'_>,
409         section_id: SectionId,
410         text_section_size: u64,
411     ) {
412         let mut cie = isa
413             .create_systemv_cie()
414             .expect("must be able to create a CIE for system-v unwind info");
415         let mut table = FrameTable::default();
416         cie.fde_address_encoding = gimli::constants::DW_EH_PE_pcrel;
417         let cie_id = table.add_cie(cie);
418 
419         for (text_section_off, unwind_info) in self.systemv_unwind_info.iter() {
420             let backwards_off = text_section_size - text_section_off;
421             let actual_offset = -i64::try_from(backwards_off).unwrap();
422             // Note that gimli wants an unsigned 64-bit integer here, but
423             // unwinders just use this constant for a relative addition with the
424             // address of the FDE, which means that the sign doesn't actually
425             // matter.
426             let fde = unwind_info.to_fde(Address::Constant(actual_offset as u64));
427             table.add_fde(cie_id, fde);
428         }
429         let endian = match isa.triple().endianness().unwrap() {
430             target_lexicon::Endianness::Little => RunTimeEndian::Little,
431             target_lexicon::Endianness::Big => RunTimeEndian::Big,
432         };
433         let mut eh_frame = EhFrame(MyVec(EndianVec::new(endian)));
434         table.write_eh_frame(&mut eh_frame).unwrap();
435 
436         // Some unwinding implementations expect a terminating "empty" length so
437         // a 0 is written at the end of the table for those implementations.
438         let mut endian_vec = (eh_frame.0).0;
439         endian_vec.write_u32(0).unwrap();
440         obj.append_section_data(section_id, endian_vec.slice(), 1);
441 
442         use gimli::constants;
443         use gimli::write::Error;
444 
445         struct MyVec(EndianVec<RunTimeEndian>);
446 
447         impl Writer for MyVec {
448             type Endian = RunTimeEndian;
449 
450             fn endian(&self) -> RunTimeEndian {
451                 self.0.endian()
452             }
453 
454             fn len(&self) -> usize {
455                 self.0.len()
456             }
457 
458             fn write(&mut self, buf: &[u8]) -> Result<(), Error> {
459                 self.0.write(buf)
460             }
461 
462             fn write_at(&mut self, pos: usize, buf: &[u8]) -> Result<(), Error> {
463                 self.0.write_at(pos, buf)
464             }
465 
466             // FIXME(gimli-rs/gimli#576) this is the definition we want for
467             // `write_eh_pointer` but the default implementation, at the time
468             // of this writing, uses `offset - val` instead of `val - offset`.
469             // A PR has been merged to fix this but until that's published we
470             // can't use it.
471             fn write_eh_pointer(
472                 &mut self,
473                 address: Address,
474                 eh_pe: constants::DwEhPe,
475                 size: u8,
476             ) -> Result<(), Error> {
477                 let val = match address {
478                     Address::Constant(val) => val,
479                     Address::Symbol { .. } => unreachable!(),
480                 };
481                 assert_eq!(eh_pe.application(), constants::DW_EH_PE_pcrel);
482                 let offset = self.len() as u64;
483                 let val = val.wrapping_sub(offset);
484                 self.write_eh_pointer_data(val, eh_pe.format(), size)
485             }
486         }
487     }
488 }
489