1 //! Memory management for executable code. 2 3 use crate::Engine; 4 use crate::prelude::*; 5 use crate::runtime::vm::MmapVec; 6 use alloc::sync::Arc; 7 use core::ops::Range; 8 use object::read::elf::SectionTable; 9 use object::{LittleEndian, SectionIndex, U32Bytes}; 10 use object::{ 11 elf::{FileHeader64, SectionHeader64}, 12 endian::Endianness, 13 read::elf::{FileHeader as _, SectionHeader as _}, 14 }; 15 use wasmtime_environ::StaticModuleIndex; 16 use wasmtime_environ::{Trap, lookup_trap_code, obj}; 17 use wasmtime_unwinder::ExceptionTable; 18 19 /// Management of executable memory within a `MmapVec` 20 /// 21 /// This type consumes ownership of a region of memory and will manage the 22 /// executable permissions of the contained JIT code as necessary. 23 pub struct CodeMemory { 24 mmap: MmapVec, 25 #[cfg(has_host_compiler_backend)] 26 unwind_registration: Option<crate::runtime::vm::UnwindRegistration>, 27 #[cfg(feature = "debug-builtins")] 28 debug_registration: Option<crate::runtime::vm::GdbJitImageRegistration>, 29 published: bool, 30 registered: bool, 31 enable_branch_protection: bool, 32 needs_executable: bool, 33 #[cfg(feature = "debug-builtins")] 34 has_native_debug_info: bool, 35 custom_code_memory: Option<Arc<dyn CustomCodeMemory>>, 36 37 // Ranges within `self.mmap` of where the particular sections lie. 38 text: Range<usize>, 39 unwind: Range<usize>, 40 trap_data: Range<usize>, 41 wasm_data: Range<usize>, 42 address_map_data: Range<usize>, 43 stack_map_data: Range<usize>, 44 exception_data: Range<usize>, 45 frame_tables_data: Range<usize>, 46 func_name_data: Range<usize>, 47 info_data: Range<usize>, 48 wasm_dwarf: Range<usize>, 49 wasm_bytecode: Range<usize>, 50 wasm_bytecode_ends: Range<usize>, 51 } 52 53 impl Drop for CodeMemory { 54 fn drop(&mut self) { 55 // If there is a custom code memory handler, restore the 56 // original (non-executable) state of the memory. 57 // 58 // We do this rather than invoking `unpublish()` because we 59 // want to skip the mprotect() if we natively own the mmap and 60 // are going to munmap soon anyway. 61 if let Some(mem) = self.custom_code_memory.as_ref() { 62 if self.published && self.needs_executable { 63 let text = self.text(); 64 mem.unpublish_executable(text.as_ptr(), text.len()) 65 .expect("Executable memory unpublish failed"); 66 } 67 } 68 69 // Drop the registrations before `self.mmap` since they (implicitly) refer to it. 70 #[cfg(has_host_compiler_backend)] 71 let _ = self.unwind_registration.take(); 72 #[cfg(feature = "debug-builtins")] 73 let _ = self.debug_registration.take(); 74 } 75 } 76 77 fn _assert() { 78 fn _assert_send_sync<T: Send + Sync>() {} 79 _assert_send_sync::<CodeMemory>(); 80 } 81 82 /// Interface implemented by an embedder to provide custom 83 /// implementations of code-memory protection and execute permissions. 84 pub trait CustomCodeMemory: Send + Sync { 85 /// The minimal alignment granularity for an address region that 86 /// can be made executable. 87 /// 88 /// Wasmtime does not assume the system page size for this because 89 /// custom code-memory protection can be used when all other uses 90 /// of virtual memory are disabled. 91 fn required_alignment(&self) -> usize; 92 93 /// Publish a region of memory as executable. 94 /// 95 /// This should update permissions from the default RW 96 /// (readable/writable but not executable) to RX 97 /// (readable/executable but not writable), enforcing W^X 98 /// discipline. 99 /// 100 /// If the platform requires any data/instruction coherence 101 /// action, that should be performed as part of this hook as well. 102 /// 103 /// `ptr` and `ptr.offset(len)` are guaranteed to be aligned as 104 /// per `required_alignment()`. 105 fn publish_executable(&self, ptr: *const u8, len: usize) -> crate::Result<()>; 106 107 /// Unpublish a region of memory. 108 /// 109 /// This should perform the opposite effect of `make_executable`, 110 /// switching a range of memory back from RX (readable/executable) 111 /// to RW (readable/writable). It is guaranteed that no code is 112 /// running anymore from this region. 113 /// 114 /// `ptr` and `ptr.offset(len)` are guaranteed to be aligned as 115 /// per `required_alignment()`. 116 fn unpublish_executable(&self, ptr: *const u8, len: usize) -> crate::Result<()>; 117 } 118 119 impl CodeMemory { 120 /// Creates a new `CodeMemory` by taking ownership of the provided 121 /// `MmapVec`. 122 /// 123 /// The returned `CodeMemory` manages the internal `MmapVec` and the 124 /// `publish` method is used to actually make the memory executable. 125 pub fn new(engine: &Engine, mmap: MmapVec) -> Result<Self> { 126 let mmap_data = &*mmap; 127 let header = FileHeader64::<Endianness>::parse(mmap_data) 128 .map_err(obj::ObjectCrateErrorWrapper) 129 .context("failed to parse precompiled artifact as an ELF")?; 130 let endian = header 131 .endian() 132 .context("failed to parse header endianness")?; 133 134 let section_headers = header 135 .section_headers(endian, mmap_data) 136 .context("failed to parse section headers")?; 137 let strings = header 138 .section_strings(endian, mmap_data, section_headers) 139 .context("failed to parse strings table")?; 140 let sections = header 141 .sections(endian, mmap_data) 142 .context("failed to parse sections table")?; 143 144 let mut text = 0..0; 145 let mut unwind = 0..0; 146 let mut enable_branch_protection = None; 147 let mut needs_executable = true; 148 #[cfg(feature = "debug-builtins")] 149 let mut has_native_debug_info = false; 150 let mut trap_data = 0..0; 151 let mut exception_data = 0..0; 152 let mut frame_tables_data = 0..0; 153 let mut wasm_data = 0..0; 154 let mut address_map_data = 0..0; 155 let mut stack_map_data = 0..0; 156 let mut func_name_data = 0..0; 157 let mut info_data = 0..0; 158 let mut wasm_dwarf = 0..0; 159 let mut wasm_bytecode = 0..0; 160 let mut wasm_bytecode_ends = 0..0; 161 for section_header in sections.iter() { 162 let data = section_header 163 .data(endian, mmap_data) 164 .map_err(obj::ObjectCrateErrorWrapper)?; 165 let name = section_name(endian, strings, section_header)?; 166 let range = subslice_range(data, &mmap); 167 168 // Double-check that sections are all aligned properly. 169 let section_align = usize::try_from(section_header.sh_addralign(endian))?; 170 if section_align != 0 && data.len() != 0 { 171 let section_offset = data.as_ptr().addr() - mmap.as_ptr().addr(); 172 ensure!( 173 section_offset % section_align == 0, 174 "section {name:?} isn't aligned to {section_align:#x}", 175 ); 176 } 177 178 // Check that we don't have any relocations, which would make 179 // loading precompiled Wasm modules slower and also force them to 180 // get paged into memory from disk. 181 // 182 // We avoid using things like Cranelift's `floor`, `ceil`, 183 // etc... operators in the Wasm-to-CLIF translator specifically to 184 // avoid having to do any relocations here. This also ensures that 185 // all builtins use the same trampoline mechanism. 186 // 187 // We do, however, allow relocations in `.debug_*` DWARF sections. 188 if let Some(target_section) = reloc_section_target(§ions, section_header, endian)? { 189 let target_name = section_name(endian, strings, target_section)?; 190 ensure!( 191 target_name.starts_with(".debug_"), 192 "section {target_name:?} has unexpected relocations \ 193 (defined in section {name:?})", 194 ); 195 } 196 197 match name { 198 obj::ELF_WASM_BTI => match data.len() { 199 1 => enable_branch_protection = Some(data[0] != 0), 200 _ => bail!("invalid {name:?} section"), 201 }, 202 ".text" => { 203 text = range; 204 205 if section_header.sh_flags(endian) & obj::SH_WASMTIME_NOT_EXECUTED != 0 { 206 needs_executable = false; 207 } 208 } 209 #[cfg(has_host_compiler_backend)] 210 crate::runtime::vm::UnwindRegistration::SECTION_NAME => unwind = range, 211 obj::ELF_WASM_DATA => wasm_data = range, 212 obj::ELF_WASMTIME_ADDRMAP => address_map_data = range, 213 obj::ELF_WASMTIME_STACK_MAP => stack_map_data = range, 214 obj::ELF_WASMTIME_TRAPS => trap_data = range, 215 obj::ELF_WASMTIME_EXCEPTIONS => exception_data = range, 216 obj::ELF_WASMTIME_FRAMES => frame_tables_data = range, 217 obj::ELF_NAME_DATA => func_name_data = range, 218 obj::ELF_WASMTIME_INFO => info_data = range, 219 obj::ELF_WASMTIME_DWARF => wasm_dwarf = range, 220 obj::ELF_WASMTIME_WASM_BYTECODE => wasm_bytecode = range, 221 obj::ELF_WASMTIME_WASM_BYTECODE_ENDS => wasm_bytecode_ends = range, 222 223 #[cfg(feature = "debug-builtins")] 224 ".debug_info" => has_native_debug_info = true, 225 226 // These sections are expected, but we do not need to retain any 227 // info about them. 228 "" | ".symtab" | ".strtab" | ".shstrtab" | ".xdata" | obj::ELF_WASM_ENGINE => { 229 log::debug!("ignoring section {name:?}") 230 } 231 _ if name.starts_with(".debug_") || name.starts_with(".rela.debug_") => { 232 log::debug!("ignoring debug section {name:?}") 233 } 234 235 _ => bail!("unexpected section {name:?} in Wasm compilation artifact"), 236 } 237 } 238 239 // Silence unused `mut` warning. 240 #[cfg(not(has_host_compiler_backend))] 241 let _ = &mut unwind; 242 243 // Ensure that the exception table is well-formed. This parser 244 // construction is cheap: it reads the header and validates 245 // ranges but nothing else. We do this only in debug-assertion 246 // builds because we otherwise require for safety that the 247 // compiled artifact is as-produced-by this version of 248 // Wasmtime, and we should always produce a correct exception 249 // table (i.e., we are not expecting untrusted data here). 250 if cfg!(debug_assertions) { 251 let _ = ExceptionTable::parse(&mmap[exception_data.clone()])?; 252 } 253 254 Ok(Self { 255 mmap, 256 #[cfg(has_host_compiler_backend)] 257 unwind_registration: None, 258 #[cfg(feature = "debug-builtins")] 259 debug_registration: None, 260 published: false, 261 registered: false, 262 enable_branch_protection: enable_branch_protection 263 .ok_or_else(|| format_err!("missing `{}` section", obj::ELF_WASM_BTI))?, 264 needs_executable, 265 #[cfg(feature = "debug-builtins")] 266 has_native_debug_info, 267 custom_code_memory: engine.custom_code_memory().cloned(), 268 text, 269 unwind, 270 trap_data, 271 address_map_data, 272 stack_map_data, 273 exception_data, 274 frame_tables_data, 275 func_name_data, 276 wasm_dwarf, 277 info_data, 278 wasm_data, 279 wasm_bytecode, 280 wasm_bytecode_ends, 281 }) 282 } 283 284 /// Returns a reference to the underlying `MmapVec` this memory owns. 285 #[inline] 286 pub fn mmap(&self) -> &MmapVec { 287 &self.mmap 288 } 289 290 /// Returns the contents of the text section of the ELF executable this 291 /// represents. 292 #[inline] 293 pub fn text(&self) -> &[u8] { 294 &self.mmap[self.text.clone()] 295 } 296 297 /// Returns the contents of the `ELF_WASMTIME_DWARF` section. 298 #[inline] 299 pub fn wasm_dwarf(&self) -> &[u8] { 300 &self.mmap[self.wasm_dwarf.clone()] 301 } 302 303 /// Returns the data in the `ELF_NAME_DATA` section. 304 #[inline] 305 pub fn func_name_data(&self) -> &[u8] { 306 &self.mmap[self.func_name_data.clone()] 307 } 308 309 /// Returns the concatenated list of all data associated with this wasm 310 /// module. 311 /// 312 /// This is used for initialization of memories and all data ranges stored 313 /// in a `Module` are relative to the slice returned here. 314 #[inline] 315 pub fn wasm_data(&self) -> &[u8] { 316 &self.mmap[self.wasm_data.clone()] 317 } 318 319 /// Returns the encoded address map section used to pass to 320 /// `wasmtime_environ::lookup_file_pos`. 321 #[inline] 322 pub fn address_map_data(&self) -> &[u8] { 323 &self.mmap[self.address_map_data.clone()] 324 } 325 326 /// Returns the encoded stack map section used to pass to 327 /// `wasmtime_environ::StackMap::lookup`. 328 pub fn stack_map_data(&self) -> &[u8] { 329 &self.mmap[self.stack_map_data.clone()] 330 } 331 332 /// Returns the encoded exception-tables section to pass to 333 /// `wasmtime_unwinder::ExceptionTable::parse`. 334 pub fn exception_tables(&self) -> &[u8] { 335 &self.mmap[self.exception_data.clone()] 336 } 337 338 /// Returns the encoded frame-tables section to pass to 339 /// `wasmtime_environ::FrameTable::parse`. 340 pub fn frame_tables(&self) -> &[u8] { 341 &self.mmap[self.frame_tables_data.clone()] 342 } 343 344 /// Returns the concatenated Wasm bytecode section, or an empty slice if 345 /// the artifact was not compiled with `guest-debug` enabled. 346 pub fn wasm_bytecode(&self) -> &[u8] { 347 &self.mmap[self.wasm_bytecode.clone()] 348 } 349 350 /// Returns the Wasm bytecode section end-offset array. 351 pub fn wasm_bytecode_ends(&self) -> &[u8] { 352 &self.mmap[self.wasm_bytecode_ends.clone()] 353 } 354 355 /// Returns the contents of the `ELF_WASMTIME_INFO` section, or an empty 356 /// slice if it wasn't found. 357 #[inline] 358 pub fn wasmtime_info(&self) -> &[u8] { 359 &self.mmap[self.info_data.clone()] 360 } 361 362 /// Returns the contents of the `ELF_WASMTIME_TRAPS` section, or an empty 363 /// slice if it wasn't found. 364 #[inline] 365 pub fn trap_data(&self) -> &[u8] { 366 &self.mmap[self.trap_data.clone()] 367 } 368 369 /// Returns the Wasm bytecode section end-offset for a given core 370 /// module, or `None` if no bytecode is present. 371 /// 372 /// # Panics 373 /// 374 /// Panics if index is out-of-range. 375 fn wasm_bytecode_end_for_module(&self, index: StaticModuleIndex) -> Option<usize> { 376 if self.wasm_bytecode_ends().is_empty() { 377 return None; 378 } 379 let ends = self.wasm_bytecode_ends(); 380 let count = ends.len() / core::mem::size_of::<u32>(); 381 let (ends, _) = object::slice_from_bytes::<U32Bytes<LittleEndian>>(ends, count) 382 .expect("Invalid alignment of `ends` section"); 383 let index = usize::try_from(index.as_u32()).unwrap(); 384 Some(usize::try_from(ends[index].get(LittleEndian)).unwrap()) 385 } 386 387 /// Returns the Wasm bytecode for the a core module in this 388 /// artifact, or `None` if bytecode was not preserved. 389 pub(crate) fn wasm_bytecode_for_module(&self, index: StaticModuleIndex) -> Option<&[u8]> { 390 let start = if index.as_u32() == 0 { 391 0 392 } else { 393 self.wasm_bytecode_end_for_module(StaticModuleIndex::from_u32(index.as_u32() - 1))? 394 }; 395 let end = self.wasm_bytecode_end_for_module(index)?; 396 Some(&self.wasm_bytecode()[start..end]) 397 } 398 399 /// Publishes the internal ELF image to be ready for execution. 400 /// 401 /// This method can only be when the image is not published (its 402 /// default state) and will panic if called when already 403 /// published. This will parse the ELF image from the original 404 /// `MmapVec` and do everything necessary to get it ready for 405 /// execution, including: 406 /// 407 /// * Change page protections from read/write to read/execute. 408 /// * Register unwinding information with the OS 409 /// * Register this image with the debugger if native DWARF is present 410 /// 411 /// After this function executes all JIT code should be ready to execute. 412 /// 413 /// The action may be reversed by calling [`Self::unpublish`], as long 414 /// as that method's safety requirements are upheld. 415 pub fn publish(&mut self) -> Result<()> { 416 assert!(!self.published); 417 self.published = true; 418 419 if self.text().is_empty() { 420 return Ok(()); 421 } 422 423 // The unsafety here comes from a few things: 424 // 425 // * We're actually updating some page protections to executable memory. 426 // 427 // * We're registering unwinding information which relies on the 428 // correctness of the information in the first place. This applies to 429 // both the actual unwinding tables as well as the validity of the 430 // pointers we pass in itself. 431 unsafe { 432 // Next freeze the contents of this image by making all of the 433 // memory readonly. Nothing after this point should ever be modified 434 // so commit everything. For a compiled-in-memory image this will 435 // mean IPIs to evict writable mappings from other cores. For 436 // loaded-from-disk images this shouldn't result in IPIs so long as 437 // there weren't any relocations because nothing should have 438 // otherwise written to the image at any point either. 439 // 440 // Note that if virtual memory is disabled this is skipped because 441 // we aren't able to make it readonly, but this is just a 442 // defense-in-depth measure and isn't required for correctness. 443 #[cfg(has_virtual_memory)] 444 if self.mmap.supports_virtual_memory() { 445 self.mmap.make_readonly(0..self.mmap.len())?; 446 } 447 448 // Switch the executable portion from readonly to read/execute. 449 if self.needs_executable { 450 if !self.custom_publish()? { 451 if !self.mmap.supports_virtual_memory() { 452 bail!("this target requires virtual memory to be enabled"); 453 } 454 #[cfg(has_virtual_memory)] 455 self.mmap 456 .make_executable(self.text.clone(), self.enable_branch_protection) 457 .context("unable to make memory executable")?; 458 } 459 } 460 461 if !self.registered { 462 // With all our memory set up use the platform-specific 463 // `UnwindRegistration` implementation to inform the general 464 // runtime that there's unwinding information available for all 465 // our just-published JIT functions. 466 self.register_unwind_info()?; 467 468 #[cfg(feature = "debug-builtins")] 469 self.register_debug_image()?; 470 self.registered = true; 471 } 472 } 473 474 Ok(()) 475 } 476 477 fn custom_publish(&mut self) -> Result<bool> { 478 if let Some(mem) = self.custom_code_memory.as_ref() { 479 let text = self.text(); 480 // The text section should be aligned to 481 // `custom_code_memory.required_alignment()` due to a 482 // combination of two invariants: 483 // 484 // - MmapVec aligns its start address, even in owned-Vec mode; and 485 // - The text segment inside the ELF image will be aligned according 486 // to the platform's requirements. 487 let text_addr = text.as_ptr() as usize; 488 assert_eq!(text_addr & (mem.required_alignment() - 1), 0); 489 490 // The custom code memory handler will ensure the 491 // memory is executable and also handle icache 492 // coherence. 493 mem.publish_executable(text.as_ptr(), text.len())?; 494 Ok(true) 495 } else { 496 Ok(false) 497 } 498 } 499 500 /// "Unpublish" code memory (transition it from executable to read/writable). 501 /// 502 /// This may be used to edit the code image, as long as the 503 /// overall size of the memory remains the same. Note the hazards 504 /// inherent in editing code that may have been executed: any 505 /// stack frames with PC still active in this code must be 506 /// suspended (e.g., called into a hostcall that is then invoking 507 /// this method, or async-yielded) and any active PC values must 508 /// point to valid instructions. Thus this is mostly useful for 509 /// patching in-place at particular sites, such as by the use of 510 /// Cranelift's `patchable_call` instruction. 511 /// 512 /// If this fails, then the memory remains executable. 513 pub fn unpublish(&mut self) -> Result<()> { 514 assert!(self.published); 515 self.published = false; 516 517 if self.text().is_empty() { 518 return Ok(()); 519 } 520 521 if self.custom_unpublish()? { 522 return Ok(()); 523 } 524 525 if !self.mmap.supports_virtual_memory() { 526 bail!("this target requires virtual memory to be enabled"); 527 } 528 529 // SAFETY: we are guaranteed by our own safety conditions that 530 // we have exclusive access to this code and can change its 531 // permissions (removing the execute bit) without causing 532 // problems. 533 #[cfg(has_virtual_memory)] 534 unsafe { 535 self.mmap.make_readwrite(0..self.mmap.len())?; 536 } 537 538 // Note that we do *not* unregister: we expect unpublish 539 // to be used for temporary edits, so we want the 540 // registration to "stick" after the initial publish and 541 // not toggle in subsequent unpublish/publish cycles. 542 543 Ok(()) 544 } 545 546 fn custom_unpublish(&mut self) -> Result<bool> { 547 if let Some(mem) = self.custom_code_memory.as_ref() { 548 let text = self.text(); 549 mem.unpublish_executable(text.as_ptr(), text.len())?; 550 Ok(true) 551 } else { 552 Ok(false) 553 } 554 } 555 556 /// Return a mutable borrow to the code, suitable for editing. 557 /// 558 /// Must not be published. 559 /// 560 /// # Panics 561 /// 562 /// This method panics if the code has been published (and not 563 /// subsequently unpublished). 564 pub fn text_mut(&mut self) -> &mut [u8] { 565 assert!(!self.published); 566 // SAFETY: we assert !published, which means we either have 567 // not yet applied readonly + execute permissinos, or we have 568 // undone that and flipped back to read-write via unpublish. 569 unsafe { &mut self.mmap.as_mut_slice()[self.text.clone()] } 570 } 571 572 unsafe fn register_unwind_info(&mut self) -> Result<()> { 573 if self.unwind.len() == 0 { 574 return Ok(()); 575 } 576 #[cfg(has_host_compiler_backend)] 577 { 578 let text = self.text(); 579 let unwind_info = &self.mmap[self.unwind.clone()]; 580 let registration = unsafe { 581 crate::runtime::vm::UnwindRegistration::new( 582 text.as_ptr(), 583 unwind_info.as_ptr(), 584 unwind_info.len(), 585 ) 586 .context("failed to create unwind info registration")? 587 }; 588 self.unwind_registration = Some(registration); 589 return Ok(()); 590 } 591 #[cfg(not(has_host_compiler_backend))] 592 { 593 bail!("should not have unwind info for non-native backend") 594 } 595 } 596 597 #[cfg(feature = "debug-builtins")] 598 fn register_debug_image(&mut self) -> Result<()> { 599 if !self.has_native_debug_info { 600 return Ok(()); 601 } 602 603 // TODO-DebugInfo: we're copying the whole image here, which is pretty wasteful. 604 // Use the existing memory by teaching code here about relocations in DWARF sections 605 // and anything else necessary that is done in "create_gdbjit_image" right now. 606 let image = self.mmap().to_vec(); 607 let text: &[u8] = self.text(); 608 let bytes = crate::native_debug::create_gdbjit_image(image, (text.as_ptr(), text.len()))?; 609 let reg = crate::runtime::vm::GdbJitImageRegistration::register(bytes); 610 self.debug_registration = Some(reg); 611 Ok(()) 612 } 613 614 /// Looks up the given offset within this module's text section and returns 615 /// the trap code associated with that instruction, if there is one. 616 pub fn lookup_trap_code(&self, text_offset: usize) -> Option<Trap> { 617 lookup_trap_code(self.trap_data(), text_offset) 618 } 619 620 /// Get the raw address range of this CodeMemory. 621 pub(crate) fn raw_addr_range(&self) -> Range<usize> { 622 let start = self.text().as_ptr().addr(); 623 let end = start + self.text().len(); 624 start..end 625 } 626 627 /// Create a "deep clone": a separate CodeMemory for the same code 628 /// that can be patched or mutated independently. Also returns a 629 /// "metadata and location" handle that can be registered with the 630 /// global module registry and used for trap metadata lookups. 631 #[cfg(feature = "debug")] 632 pub(crate) fn deep_clone(self: &Arc<Self>, engine: &Engine) -> Result<CodeMemory> { 633 let mmap = self.mmap.deep_clone()?; 634 Self::new(engine, mmap) 635 } 636 } 637 638 fn section_name<'a>( 639 endian: Endianness, 640 strings: object::StringTable<'a>, 641 section_header: &SectionHeader64<Endianness>, 642 ) -> Result<&'a str> { 643 let name = section_header 644 .name(endian, strings) 645 .map_err(obj::ObjectCrateErrorWrapper)?; 646 Ok(str::from_utf8(name).context("invalid section name in Wasm compilation artifact")?) 647 } 648 649 fn is_reloc_section(section_header: &SectionHeader64<Endianness>, endian: Endianness) -> bool { 650 let sh_type = section_header.sh_type(endian); 651 matches!( 652 sh_type, 653 object::elf::SHT_REL | object::elf::SHT_RELA | object::elf::SHT_CREL 654 ) 655 } 656 657 fn reloc_section_target<'a>( 658 sections: &'a SectionTable<'a, FileHeader64<Endianness>, &'a [u8]>, 659 section: &'a SectionHeader64<Endianness>, 660 endian: Endianness, 661 ) -> Result<Option<&'a SectionHeader64<Endianness>>> { 662 if !is_reloc_section(§ion, endian) { 663 return Ok(None); 664 } 665 666 let sh_info = section.info_link(endian); 667 668 // Dynamic relocation. 669 if sh_info == SectionIndex(0) { 670 return Ok(None); 671 } 672 673 ensure!( 674 sh_info.0 < sections.len(), 675 "invalid ELF `sh_info` for relocation section", 676 ); 677 678 Ok(Some(sections.section(sh_info)?)) 679 } 680 681 /// Returns the range of `inner` within `outer`, such that `outer[range]` is the 682 /// same as `inner`. 683 /// 684 /// This method requires that `inner` is a sub-slice of `outer`, and if that 685 /// isn't true then this method will panic. 686 fn subslice_range(inner: &[u8], outer: &[u8]) -> Range<usize> { 687 if inner.len() == 0 { 688 return 0..0; 689 } 690 691 assert!(outer.as_ptr() <= inner.as_ptr()); 692 assert!((&inner[inner.len() - 1] as *const _) <= (&outer[outer.len() - 1] as *const _)); 693 694 let start = inner.as_ptr() as usize - outer.as_ptr() as usize; 695 start..start + inner.len() 696 } 697