Publishes the internal ELF image to be ready for execution. This method can only be when the image is not published (its default state) and will panic if called when already published. This will parse the ELF image from the original `MmapVec` and do everything necessary to get it ready for execution, including: Change page protections from read/write to read/execute. Register unwinding informati
(&mut self)
| 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 | } |
no test coverage detected