This function appends a nonstandard section to the object which is only used during `CodeMemory::publish`. This will generate a `.eh_frame` section, but not one that can be naively loaded. The goal of this section is that we can create the section once here and never again does it need to change. To describe dynamically loaded functions though each individual FDE needs to talk about the function'
(
&self,
compiler: &dyn Compiler,
obj: &mut Object<'_>,
section_id: SectionId,
text_section_size: u64,
)
| 512 | /// such as being purely read-only instead of read/execute like the code |
| 513 | /// bits. |
| 514 | fn write_systemv_unwind_info( |
| 515 | &self, |
| 516 | compiler: &dyn Compiler, |
| 517 | obj: &mut Object<'_>, |
| 518 | section_id: SectionId, |
| 519 | text_section_size: u64, |
| 520 | ) { |
| 521 | let mut cie = match compiler.create_systemv_cie() { |
| 522 | Some(cie) => cie, |
| 523 | None => return, |
| 524 | }; |
| 525 | let mut table = FrameTable::default(); |
| 526 | cie.fde_address_encoding = gimli::constants::DW_EH_PE_pcrel; |
| 527 | let cie_id = table.add_cie(cie); |
| 528 | |
| 529 | for (text_section_off, unwind_info) in self.systemv_unwind_info.iter() { |
| 530 | let backwards_off = text_section_size - text_section_off; |
| 531 | let actual_offset = -i64::try_from(backwards_off).unwrap(); |
| 532 | // Note that gimli wants an unsigned 64-bit integer here, but |
| 533 | // unwinders just use this constant for a relative addition with the |
| 534 | // address of the FDE, which means that the sign doesn't actually |
| 535 | // matter. |
| 536 | let fde = unwind_info.to_fde(Address::Constant(actual_offset.cast_unsigned())); |
| 537 | table.add_fde(cie_id, fde); |
| 538 | } |
| 539 | let endian = match compiler.triple().endianness().unwrap() { |
| 540 | target_lexicon::Endianness::Little => RunTimeEndian::Little, |
| 541 | target_lexicon::Endianness::Big => RunTimeEndian::Big, |
| 542 | }; |
| 543 | let mut eh_frame = EhFrame(MyVec(EndianVec::new(endian))); |
| 544 | table.write_eh_frame(&mut eh_frame).unwrap(); |
| 545 | |
| 546 | // Some unwinding implementations expect a terminating "empty" length so |
| 547 | // a 0 is written at the end of the table for those implementations. |
| 548 | let mut endian_vec = (eh_frame.0).0; |
| 549 | endian_vec.write_u32(0).unwrap(); |
| 550 | obj.append_section_data(section_id, endian_vec.slice(), 1); |
| 551 | |
| 552 | use gimli::constants; |
| 553 | use gimli::write::Error; |
| 554 | |
| 555 | struct MyVec(EndianVec<RunTimeEndian>); |
| 556 | |
| 557 | impl Writer for MyVec { |
| 558 | type Endian = RunTimeEndian; |
| 559 | |
| 560 | fn endian(&self) -> RunTimeEndian { |
| 561 | self.0.endian() |
| 562 | } |
| 563 | |
| 564 | fn len(&self) -> usize { |
| 565 | self.0.len() |
| 566 | } |
| 567 | |
| 568 | fn write(&mut self, buf: &[u8]) -> Result<(), Error> { |
| 569 | self.0.write(buf) |
| 570 | } |
| 571 |
no test coverage detected