Add an external relocation at the given offset.
(
&mut self,
offset: CodeOffset,
kind: Reloc,
target: &T,
addend: Addend,
)
| 1683 | |
| 1684 | /// Add an external relocation at the given offset. |
| 1685 | pub fn add_reloc_at_offset<T: Into<RelocTarget> + Clone>( |
| 1686 | &mut self, |
| 1687 | offset: CodeOffset, |
| 1688 | kind: Reloc, |
| 1689 | target: &T, |
| 1690 | addend: Addend, |
| 1691 | ) { |
| 1692 | let target: RelocTarget = target.clone().into(); |
| 1693 | // FIXME(#3277): This should use `I::LabelUse::from_reloc` to optionally |
| 1694 | // generate a label-use statement to track whether an island is possibly |
| 1695 | // needed to escape this function to actually get to the external name. |
| 1696 | // This is most likely to come up on AArch64 where calls between |
| 1697 | // functions use a 26-bit signed offset which gives +/- 64MB. This means |
| 1698 | // that if a function is 128MB in size and there's a call in the middle |
| 1699 | // it's impossible to reach the actual target. Also, while it's |
| 1700 | // technically possible to jump to the start of a function and then jump |
| 1701 | // further, island insertion below always inserts islands after |
| 1702 | // previously appended code so for Cranelift's own implementation this |
| 1703 | // is also a problem for 64MB functions on AArch64 which start with a |
| 1704 | // call instruction, those won't be able to escape. |
| 1705 | // |
| 1706 | // Ideally what needs to happen here is that a `LabelUse` is |
| 1707 | // transparently generated (or call-sites of this function are audited |
| 1708 | // to generate a `LabelUse` instead) and tracked internally. The actual |
| 1709 | // relocation would then change over time if and when a veneer is |
| 1710 | // inserted, where the relocation here would be patched by this |
| 1711 | // `MachBuffer` to jump to the veneer. The problem, though, is that all |
| 1712 | // this still needs to end up, in the case of a singular function, |
| 1713 | // generating a final relocation pointing either to this particular |
| 1714 | // relocation or to the veneer inserted. Additionally |
| 1715 | // `MachBuffer` needs the concept of a label which will never be |
| 1716 | // resolved, so `emit_island` doesn't trip over not actually ever |
| 1717 | // knowing what some labels are. Currently the loop in |
| 1718 | // `finish_emission_maybe_forcing_veneers` would otherwise infinitely |
| 1719 | // loop. |
| 1720 | // |
| 1721 | // For now this means that because relocs aren't tracked at all that |
| 1722 | // AArch64 functions have a rough size limits of 64MB. For now that's |
| 1723 | // somewhat reasonable and the failure mode is a panic in `MachBuffer` |
| 1724 | // when a relocation can't otherwise be resolved later, so it shouldn't |
| 1725 | // actually result in any memory unsafety or anything like that. |
| 1726 | self.relocs.push(MachReloc { |
| 1727 | offset, |
| 1728 | kind, |
| 1729 | target, |
| 1730 | addend, |
| 1731 | }); |
| 1732 | } |
| 1733 | |
| 1734 | /// Add an external relocation at the current offset. |
| 1735 | pub fn add_reloc<T: Into<RelocTarget> + Clone>( |
no test coverage detected