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::binemit::Reloc; 19 use cranelift_codegen::isa::unwind::{systemv, UnwindInfo}; 20 use cranelift_codegen::TextSectionBuilder; 21 use cranelift_control::ControlPlane; 22 use gimli::write::{Address, EhFrame, EndianVec, FrameTable, Writer}; 23 use gimli::RunTimeEndian; 24 use object::write::{Object, SectionId, StandardSegment, Symbol, SymbolId, SymbolSection}; 25 use object::{Architecture, SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope}; 26 use std::collections::HashMap; 27 use std::ops::Range; 28 use wasmtime_environ::obj::{self, LibCall}; 29 use wasmtime_environ::{Compiler, TripleExt, Unsigned}; 30 31 const TEXT_SECTION_NAME: &[u8] = b".text"; 32 33 fn text_align(compiler: &dyn Compiler) -> u64 { 34 // text pages will not be made executable with pulley, so the section 35 // doesn't need to be padded out to page alignment boundaries. 36 if compiler.triple().is_pulley() { 37 0x1 38 } else { 39 compiler.page_size_align() 40 } 41 } 42 43 /// A helper structure used to assemble the final text section of an executable, 44 /// plus unwinding information and other related details. 45 /// 46 /// This builder relies on Cranelift-specific internals but assembles into a 47 /// generic `Object` which will get further appended to in a compiler-agnostic 48 /// fashion later. 49 pub struct ModuleTextBuilder<'a> { 50 /// The target that we're compiling for, used to query target-specific 51 /// information as necessary. 52 compiler: &'a dyn Compiler, 53 54 /// The object file that we're generating code into. 55 obj: &'a mut Object<'static>, 56 57 /// The WebAssembly module we're generating code for. 58 text_section: SectionId, 59 60 unwind_info: UnwindInfoBuilder<'a>, 61 62 /// In-progress text section that we're using cranelift's `MachBuffer` to 63 /// build to resolve relocations (calls) between functions. 64 text: Box<dyn TextSectionBuilder>, 65 66 /// Symbols defined in the object for libcalls that relocations are applied 67 /// against. 68 /// 69 /// Note that this isn't typically used. It's only used for SSE-disabled 70 /// builds without SIMD on x86_64 right now. 71 libcall_symbols: HashMap<LibCall, SymbolId>, 72 73 ctrl_plane: ControlPlane, 74 } 75 76 impl<'a> ModuleTextBuilder<'a> { 77 /// Creates a new builder for the text section of an executable. 78 /// 79 /// The `.text` section will be appended to the specified `obj` along with 80 /// any unwinding or such information as necessary. The `num_funcs` 81 /// parameter indicates the number of times the `append_func` function will 82 /// be called. The `finish` function will panic if this contract is not met. 83 pub fn new( 84 obj: &'a mut Object<'static>, 85 compiler: &'a dyn Compiler, 86 text: Box<dyn TextSectionBuilder>, 87 ) -> Self { 88 // Entire code (functions and trampolines) will be placed 89 // in the ".text" section. 90 let text_section = obj.add_section( 91 obj.segment_name(StandardSegment::Text).to_vec(), 92 TEXT_SECTION_NAME.to_vec(), 93 SectionKind::Text, 94 ); 95 96 // If this target is Pulley then flag the text section as not needing the 97 // executable bit in virtual memory which means that the runtime won't 98 // try to call `Mmap::make_executable`, which makes Pulley more 99 // portable. 100 if compiler.triple().is_pulley() { 101 let section = obj.section_mut(text_section); 102 assert!(matches!(section.flags, SectionFlags::None)); 103 section.flags = SectionFlags::Elf { 104 sh_flags: obj::SH_WASMTIME_NOT_EXECUTED, 105 }; 106 } 107 108 Self { 109 compiler, 110 obj, 111 text_section, 112 unwind_info: Default::default(), 113 text, 114 libcall_symbols: HashMap::default(), 115 ctrl_plane: ControlPlane::default(), 116 } 117 } 118 119 /// Appends the `func` specified named `name` to this object. 120 /// 121 /// The `resolve_reloc_target` closure is used to resolve a relocation 122 /// target to an adjacent function which has already been added or will be 123 /// added to this object. The argument is the relocation target specified 124 /// within `CompiledFunction` and the return value must be an index where 125 /// the target will be defined by the `n`th call to `append_func`. 126 /// 127 /// Returns the symbol associated with the function as well as the range 128 /// that the function resides within the text section. 129 pub fn append_func( 130 &mut self, 131 name: &str, 132 compiled_func: &'a CompiledFunction, 133 resolve_reloc_target: impl Fn(wasmtime_environ::RelocationTarget) -> usize, 134 ) -> (SymbolId, Range<u64>) { 135 let body = compiled_func.buffer.data(); 136 let alignment = compiled_func.alignment; 137 let body_len = body.len() as u64; 138 let off = self 139 .text 140 .append(true, &body, alignment, &mut self.ctrl_plane); 141 142 let symbol_id = self.obj.add_symbol(Symbol { 143 name: name.as_bytes().to_vec(), 144 value: off, 145 size: body_len, 146 kind: SymbolKind::Text, 147 scope: SymbolScope::Compilation, 148 weak: false, 149 section: SymbolSection::Section(self.text_section), 150 flags: SymbolFlags::None, 151 }); 152 153 if let Some(info) = compiled_func.unwind_info() { 154 self.unwind_info.push(off, body_len, info); 155 } 156 157 for r in compiled_func.relocations() { 158 let reloc_offset = off + u64::from(r.offset); 159 match r.reloc_target { 160 // Relocations against user-defined functions means that this is 161 // a relocation against a module-local function, typically a 162 // call between functions. The `text` field is given priority to 163 // resolve this relocation before we actually emit an object 164 // file, but if it can't handle it then we pass through the 165 // relocation. 166 RelocationTarget::Wasm(_) | RelocationTarget::Builtin(_) => { 167 let target = resolve_reloc_target(r.reloc_target); 168 if self 169 .text 170 .resolve_reloc(reloc_offset, r.reloc, r.addend, target) 171 { 172 continue; 173 } 174 175 // At this time it's expected that all relocations are 176 // handled by `text.resolve_reloc`, and anything that isn't 177 // handled is a bug in `text.resolve_reloc` or something 178 // transitively there. If truly necessary, though, then this 179 // loop could also be updated to forward the relocation to 180 // the final object file as well. 181 panic!( 182 "unresolved relocation could not be processed against \ 183 {:?}: {r:?}", 184 r.reloc_target, 185 ); 186 } 187 188 // Relocations against libcalls are not common at this time and 189 // are only used in non-default configurations that disable wasm 190 // SIMD, disable SSE features, and for wasm modules that still 191 // use floating point operations. 192 // 193 // Currently these relocations are all expected to be absolute 194 // 8-byte relocations so that's asserted here and then encoded 195 // directly into the object as a normal object relocation. This 196 // is processed at module load time to resolve the relocations. 197 RelocationTarget::HostLibcall(call) => { 198 let symbol = *self.libcall_symbols.entry(call).or_insert_with(|| { 199 self.obj.add_symbol(Symbol { 200 name: call.symbol().as_bytes().to_vec(), 201 value: 0, 202 size: 0, 203 kind: SymbolKind::Text, 204 scope: SymbolScope::Linkage, 205 weak: false, 206 section: SymbolSection::Undefined, 207 flags: SymbolFlags::None, 208 }) 209 }); 210 let flags = match r.reloc { 211 Reloc::Abs8 => object::RelocationFlags::Generic { 212 encoding: object::RelocationEncoding::Generic, 213 kind: object::RelocationKind::Absolute, 214 size: 64, 215 }, 216 other => unimplemented!("unimplemented relocation kind {other:?}"), 217 }; 218 self.obj 219 .add_relocation( 220 self.text_section, 221 object::write::Relocation { 222 symbol, 223 flags, 224 offset: reloc_offset, 225 addend: r.addend, 226 }, 227 ) 228 .unwrap(); 229 } 230 231 // This relocation is used to fill in which hostcall id is 232 // desired within the `call_indirect_host` opcode of Pulley 233 // itself. The relocation target is the start of the instruction 234 // and the goal is to insert the static signature number, `n`, 235 // into the instruction. 236 // 237 // At this time the instruction looks like: 238 // 239 // +------+------+------+------+ 240 // | OP | OP_EXTENDED | N | 241 // +------+------+------+------+ 242 // 243 // This 4-byte encoding has `OP` indicating this is an "extended 244 // opcode" where `OP_EXTENDED` is a 16-bit extended opcode. 245 // The `N` byte is the index of the signature being called and 246 // is what's b eing filled in. 247 // 248 // See the `test_call_indirect_host_width` in 249 // `pulley/tests/all.rs` for this guarantee as well. 250 RelocationTarget::PulleyHostcall(n) => { 251 #[cfg(feature = "pulley")] 252 { 253 use pulley_interpreter::encode::Encode; 254 assert_eq!(pulley_interpreter::CallIndirectHost::WIDTH, 4); 255 } 256 let byte = u8::try_from(n).unwrap(); 257 self.text.write(reloc_offset + 3, &[byte]); 258 } 259 }; 260 } 261 (symbol_id, off..off + body_len) 262 } 263 264 /// Forces "veneers" to be used for inter-function calls in the text 265 /// section which means that in-bounds optimized addresses are never used. 266 /// 267 /// This is only useful for debugging cranelift itself and typically this 268 /// option is disabled. 269 pub fn force_veneers(&mut self) { 270 self.text.force_veneers(); 271 } 272 273 /// Appends the specified amount of bytes of padding into the text section. 274 /// 275 /// This is only useful when fuzzing and/or debugging cranelift itself and 276 /// for production scenarios `padding` is 0 and this function does nothing. 277 pub fn append_padding(&mut self, padding: usize) { 278 if padding == 0 { 279 return; 280 } 281 self.text 282 .append(false, &vec![0; padding], 1, &mut self.ctrl_plane); 283 } 284 285 /// Indicates that the text section has been written completely and this 286 /// will finish appending it to the original object. 287 /// 288 /// Note that this will also write out the unwind information sections if 289 /// necessary. 290 pub fn finish(mut self) { 291 // Finish up the text section now that we're done adding functions. 292 let text = self.text.finish(&mut self.ctrl_plane); 293 self.obj 294 .section_mut(self.text_section) 295 .set_data(text, text_align(self.compiler)); 296 297 // Append the unwind information for all our functions, if necessary. 298 self.unwind_info 299 .append_section(self.compiler, self.obj, self.text_section); 300 } 301 } 302 303 /// Builder used to create unwind information for a set of functions added to a 304 /// text section. 305 #[derive(Default)] 306 struct UnwindInfoBuilder<'a> { 307 windows_xdata: Vec<u8>, 308 windows_pdata: Vec<RUNTIME_FUNCTION>, 309 systemv_unwind_info: Vec<(u64, &'a systemv::UnwindInfo)>, 310 } 311 312 // This is a mirror of `RUNTIME_FUNCTION` in the Windows API, but defined here 313 // to ensure everything is always `u32` and to have it available on all 314 // platforms. Note that all of these specifiers here are relative to a "base 315 // address" which we define as the base of where the text section is eventually 316 // loaded. 317 #[expect(non_camel_case_types, reason = "matching Windows style, not Rust")] 318 struct RUNTIME_FUNCTION { 319 begin: u32, 320 end: u32, 321 unwind_address: u32, 322 } 323 324 impl<'a> UnwindInfoBuilder<'a> { 325 /// Pushes the unwind information for a function into this builder. 326 /// 327 /// The function being described must be located at `function_offset` within 328 /// the text section itself, and the function's size is specified by 329 /// `function_len`. 330 /// 331 /// The `info` should come from Cranelift. and is handled here depending on 332 /// its flavor. 333 fn push(&mut self, function_offset: u64, function_len: u64, info: &'a UnwindInfo) { 334 match info { 335 // Windows unwind information is stored in two locations: 336 // 337 // * First is the actual unwinding information which is stored 338 // in the `.xdata` section. This is where `info`'s emitted 339 // information will go into. 340 // * Second are pointers to connect all this unwind information, 341 // stored in the `.pdata` section. The `.pdata` section is an 342 // array of `RUNTIME_FUNCTION` structures. 343 // 344 // Due to how these will be loaded at runtime the `.pdata` isn't 345 // actually assembled byte-wise here. Instead that's deferred to 346 // happen later during `write_windows_unwind_info` which will apply 347 // a further offset to `unwind_address`. 348 // 349 // FIXME: in theory we could "intern" the `unwind_info` value 350 // here within the `.xdata` section. Most of our unwind 351 // information for functions is probably pretty similar in which 352 // case the `.xdata` could be quite small and `.pdata` could 353 // have multiple functions point to the same unwinding 354 // information. 355 UnwindInfo::WindowsX64(info) => { 356 let unwind_size = info.emit_size(); 357 let mut unwind_info = vec![0; unwind_size]; 358 info.emit(&mut unwind_info); 359 360 // `.xdata` entries are always 4-byte aligned 361 while self.windows_xdata.len() % 4 != 0 { 362 self.windows_xdata.push(0x00); 363 } 364 let unwind_address = self.windows_xdata.len(); 365 self.windows_xdata.extend_from_slice(&unwind_info); 366 367 // Record a `RUNTIME_FUNCTION` which this will point to. 368 self.windows_pdata.push(RUNTIME_FUNCTION { 369 begin: u32::try_from(function_offset).unwrap(), 370 end: u32::try_from(function_offset + function_len).unwrap(), 371 unwind_address: u32::try_from(unwind_address).unwrap(), 372 }); 373 } 374 375 // See https://learn.microsoft.com/en-us/cpp/build/arm64-exception-handling 376 UnwindInfo::WindowsArm64(info) => { 377 let code_words = info.code_words(); 378 let mut unwind_codes = vec![0; (code_words * 4) as usize]; 379 info.emit(&mut unwind_codes); 380 381 // `.xdata` entries are always 4-byte aligned 382 while self.windows_xdata.len() % 4 != 0 { 383 self.windows_xdata.push(0x00); 384 } 385 386 // First word: 387 // 0-17: Function Length 388 // 18-19: Version (must be 0) 389 // 20: X bit (is exception data present?) 390 // 21: E bit (has single packed epilogue?) 391 // 22-26: Epilogue count 392 // 27-31: Code words count 393 let requires_extended_counts = code_words > (1 << 5); 394 let encoded_function_len = function_len / 4; 395 assert!(encoded_function_len < (1 << 18), "function too large"); 396 let mut word1 = u32::try_from(encoded_function_len).unwrap(); 397 if !requires_extended_counts { 398 word1 |= u32::from(code_words) << 27; 399 } 400 let unwind_address = self.windows_xdata.len(); 401 self.windows_xdata.extend_from_slice(&word1.to_le_bytes()); 402 403 if requires_extended_counts { 404 // Extended counts word: 405 // 0-15: Epilogue count 406 // 16-23: Code words count 407 let extended_counts_word = (code_words as u32) << 16; 408 self.windows_xdata 409 .extend_from_slice(&extended_counts_word.to_le_bytes()); 410 } 411 412 // Skip epilogue information: Per comment on [`UnwindInst`], we 413 // do not emit information about epilogues. 414 415 // Emit the unwind codes. 416 self.windows_xdata.extend_from_slice(&unwind_codes); 417 418 // Record a `RUNTIME_FUNCTION` which this will point to. 419 // NOTE: `end` is not used, so leave it as 0. 420 self.windows_pdata.push(RUNTIME_FUNCTION { 421 begin: u32::try_from(function_offset).unwrap(), 422 end: 0, 423 unwind_address: u32::try_from(unwind_address).unwrap(), 424 }); 425 } 426 427 // System-V is different enough that we just record the unwinding 428 // information to get processed at a later time. 429 UnwindInfo::SystemV(info) => { 430 self.systemv_unwind_info.push((function_offset, info)); 431 } 432 433 _ => panic!("some unwind info isn't handled here"), 434 } 435 } 436 437 /// Appends the unwind information section, if any, to the `obj` specified. 438 /// 439 /// This function must be called immediately after the text section was 440 /// added to a builder. The unwind information section must trail the text 441 /// section immediately. 442 /// 443 /// The `text_section`'s section identifier is passed into this function. 444 fn append_section( 445 &self, 446 compiler: &dyn Compiler, 447 obj: &mut Object<'_>, 448 text_section: SectionId, 449 ) { 450 // This write will align the text section to a page boundary and then 451 // return the offset at that point. This gives us the full size of the 452 // text section at that point, after alignment. 453 let text_section_size = obj.append_section_data(text_section, &[], text_align(compiler)); 454 455 if self.windows_xdata.len() > 0 { 456 assert!(self.systemv_unwind_info.len() == 0); 457 // The `.xdata` section must come first to be just-after the `.text` 458 // section for the reasons documented in `write_windows_unwind_info` 459 // below. 460 let segment = obj.segment_name(StandardSegment::Data).to_vec(); 461 let xdata_id = obj.add_section(segment, b".xdata".to_vec(), SectionKind::ReadOnlyData); 462 let segment = obj.segment_name(StandardSegment::Data).to_vec(); 463 let pdata_id = obj.add_section(segment, b".pdata".to_vec(), SectionKind::ReadOnlyData); 464 self.write_windows_unwind_info(obj, xdata_id, pdata_id, text_section_size); 465 } 466 467 if self.systemv_unwind_info.len() > 0 { 468 let segment = obj.segment_name(StandardSegment::Data).to_vec(); 469 let section_id = 470 obj.add_section(segment, b".eh_frame".to_vec(), SectionKind::ReadOnlyData); 471 self.write_systemv_unwind_info(compiler, obj, section_id, text_section_size) 472 } 473 } 474 475 /// This function appends a nonstandard section to the object which is only 476 /// used during `CodeMemory::publish`. 477 /// 478 /// This custom section effectively stores a `[RUNTIME_FUNCTION; N]` into 479 /// the object file itself. This way registration of unwind info can simply 480 /// pass this slice to the OS itself and there's no need to recalculate 481 /// anything on the other end of loading a module from a precompiled object. 482 /// 483 /// Support for reading this is in `crates/jit/src/unwind/winx64.rs`. 484 fn write_windows_unwind_info( 485 &self, 486 obj: &mut Object<'_>, 487 xdata_id: SectionId, 488 pdata_id: SectionId, 489 text_section_size: u64, 490 ) { 491 // Append the `.xdata` section, or the actual unwinding information 492 // codes and such which were built as we found unwind information for 493 // functions. 494 obj.append_section_data(xdata_id, &self.windows_xdata, 4); 495 496 // Next append the `.pdata` section, or the array of `RUNTIME_FUNCTION` 497 // structures stored in the binary. 498 // 499 // This memory will be passed at runtime to `RtlAddFunctionTable` which 500 // takes a "base address" and the entries within `RUNTIME_FUNCTION` are 501 // all relative to this base address. The base address we pass is the 502 // address of the text section itself so all the pointers here must be 503 // text-section-relative. The `begin` and `end` fields for the function 504 // it describes are already text-section-relative, but the 505 // `unwind_address` field needs to be updated here since the value 506 // stored right now is `xdata`-section-relative. We know that the 507 // `xdata` section follows the `.text` section so the 508 // `text_section_size` is added in to calculate the final 509 // `.text`-section-relative address of the unwind information. 510 let xdata_rva = |address| { 511 let address = u64::from(address); 512 let address = address + text_section_size; 513 u32::try_from(address).unwrap() 514 }; 515 let pdata = match obj.architecture() { 516 Architecture::X86_64 => { 517 let mut pdata = Vec::with_capacity(self.windows_pdata.len() * 3 * 4); 518 for info in self.windows_pdata.iter() { 519 pdata.extend_from_slice(&info.begin.to_le_bytes()); 520 pdata.extend_from_slice(&info.end.to_le_bytes()); 521 pdata.extend_from_slice(&xdata_rva(info.unwind_address).to_le_bytes()); 522 } 523 pdata 524 } 525 526 Architecture::Aarch64 => { 527 // Windows Arm64 .pdata also supports packed unwind data, but 528 // we're not currently using that. 529 let mut pdata = Vec::with_capacity(self.windows_pdata.len() * 2 * 4); 530 for info in self.windows_pdata.iter() { 531 pdata.extend_from_slice(&info.begin.to_le_bytes()); 532 pdata.extend_from_slice(&xdata_rva(info.unwind_address).to_le_bytes()); 533 } 534 pdata 535 } 536 537 _ => unimplemented!("unsupported architecture for windows unwind info"), 538 }; 539 obj.append_section_data(pdata_id, &pdata, 4); 540 } 541 542 /// This function appends a nonstandard section to the object which is only 543 /// used during `CodeMemory::publish`. 544 /// 545 /// This will generate a `.eh_frame` section, but not one that can be 546 /// naively loaded. The goal of this section is that we can create the 547 /// section once here and never again does it need to change. To describe 548 /// dynamically loaded functions though each individual FDE needs to talk 549 /// about the function's absolute address that it's referencing. Naturally 550 /// we don't actually know the function's absolute address when we're 551 /// creating an object here. 552 /// 553 /// To solve this problem the FDE address encoding mode is set to 554 /// `DW_EH_PE_pcrel`. This means that the actual effective address that the 555 /// FDE describes is a relative to the address of the FDE itself. By 556 /// leveraging this relative-ness we can assume that the relative distance 557 /// between the FDE and the function it describes is constant, which should 558 /// allow us to generate an FDE ahead-of-time here. 559 /// 560 /// For now this assumes that all the code of functions will start at a 561 /// page-aligned address when loaded into memory. The eh_frame encoded here 562 /// then assumes that the text section is itself page aligned to its size 563 /// and the eh_frame will follow just after the text section. This means 564 /// that the relative offsets we're using here is the FDE going backwards 565 /// into the text section itself. 566 /// 567 /// Note that the library we're using to create the FDEs, `gimli`, doesn't 568 /// actually encode addresses relative to the FDE itself. Instead the 569 /// addresses are encoded relative to the start of the `.eh_frame` section. 570 /// This makes it much easier for us where we provide the relative offset 571 /// from the start of `.eh_frame` to the function in the text section, which 572 /// given our layout basically means the offset of the function in the text 573 /// section from the end of the text section. 574 /// 575 /// A final note is that the reason we page-align the text section's size is 576 /// so the .eh_frame lives on a separate page from the text section itself. 577 /// This allows `.eh_frame` to have different virtual memory permissions, 578 /// such as being purely read-only instead of read/execute like the code 579 /// bits. 580 fn write_systemv_unwind_info( 581 &self, 582 compiler: &dyn Compiler, 583 obj: &mut Object<'_>, 584 section_id: SectionId, 585 text_section_size: u64, 586 ) { 587 let mut cie = match compiler.create_systemv_cie() { 588 Some(cie) => cie, 589 None => return, 590 }; 591 let mut table = FrameTable::default(); 592 cie.fde_address_encoding = gimli::constants::DW_EH_PE_pcrel; 593 let cie_id = table.add_cie(cie); 594 595 for (text_section_off, unwind_info) in self.systemv_unwind_info.iter() { 596 let backwards_off = text_section_size - text_section_off; 597 let actual_offset = -i64::try_from(backwards_off).unwrap(); 598 // Note that gimli wants an unsigned 64-bit integer here, but 599 // unwinders just use this constant for a relative addition with the 600 // address of the FDE, which means that the sign doesn't actually 601 // matter. 602 let fde = unwind_info.to_fde(Address::Constant(actual_offset.unsigned())); 603 table.add_fde(cie_id, fde); 604 } 605 let endian = match compiler.triple().endianness().unwrap() { 606 target_lexicon::Endianness::Little => RunTimeEndian::Little, 607 target_lexicon::Endianness::Big => RunTimeEndian::Big, 608 }; 609 let mut eh_frame = EhFrame(MyVec(EndianVec::new(endian))); 610 table.write_eh_frame(&mut eh_frame).unwrap(); 611 612 // Some unwinding implementations expect a terminating "empty" length so 613 // a 0 is written at the end of the table for those implementations. 614 let mut endian_vec = (eh_frame.0).0; 615 endian_vec.write_u32(0).unwrap(); 616 obj.append_section_data(section_id, endian_vec.slice(), 1); 617 618 use gimli::constants; 619 use gimli::write::Error; 620 621 struct MyVec(EndianVec<RunTimeEndian>); 622 623 impl Writer for MyVec { 624 type Endian = RunTimeEndian; 625 626 fn endian(&self) -> RunTimeEndian { 627 self.0.endian() 628 } 629 630 fn len(&self) -> usize { 631 self.0.len() 632 } 633 634 fn write(&mut self, buf: &[u8]) -> Result<(), Error> { 635 self.0.write(buf) 636 } 637 638 fn write_at(&mut self, pos: usize, buf: &[u8]) -> Result<(), Error> { 639 self.0.write_at(pos, buf) 640 } 641 642 // FIXME(gimli-rs/gimli#576) this is the definition we want for 643 // `write_eh_pointer` but the default implementation, at the time 644 // of this writing, uses `offset - val` instead of `val - offset`. 645 // A PR has been merged to fix this but until that's published we 646 // can't use it. 647 fn write_eh_pointer( 648 &mut self, 649 address: Address, 650 eh_pe: constants::DwEhPe, 651 size: u8, 652 ) -> Result<(), Error> { 653 let val = match address { 654 Address::Constant(val) => val, 655 Address::Symbol { .. } => unreachable!(), 656 }; 657 assert_eq!(eh_pe.application(), constants::DW_EH_PE_pcrel); 658 let offset = self.len() as u64; 659 let val = val.wrapping_sub(offset); 660 self.write_eh_pointer_data(val, eh_pe.format(), size) 661 } 662 } 663 } 664 } 665