Appends the `func` specified named `name` to this object. The `resolve_reloc_target` closure is used to resolve a relocation target to an adjacent function which has already been added or will be added to this object. The argument is the relocation target specified within `CompiledFunction` and the return value must be an index where the target will be defined by the `n`th call to `append_func`.
(
&mut self,
name: &str,
compiled_func: &'a CompiledFunction,
resolve_reloc_target: impl Fn(wasmtime_environ::FuncKey) -> usize,
)
| 117 | /// Returns the symbol associated with the function as well as the range |
| 118 | /// that the function resides within the text section. |
| 119 | pub fn append_func( |
| 120 | &mut self, |
| 121 | name: &str, |
| 122 | compiled_func: &'a CompiledFunction, |
| 123 | resolve_reloc_target: impl Fn(wasmtime_environ::FuncKey) -> usize, |
| 124 | ) -> (SymbolId, Range<u64>) { |
| 125 | let body = compiled_func.buffer.data(); |
| 126 | let alignment = compiled_func.alignment; |
| 127 | let body_len = body.len() as u64; |
| 128 | let off = self |
| 129 | .text |
| 130 | .append(true, &body, alignment, &mut self.ctrl_plane); |
| 131 | |
| 132 | let symbol_id = self.obj.add_symbol(Symbol { |
| 133 | name: name.as_bytes().to_vec(), |
| 134 | value: off, |
| 135 | size: body_len, |
| 136 | kind: SymbolKind::Text, |
| 137 | scope: SymbolScope::Compilation, |
| 138 | weak: false, |
| 139 | section: SymbolSection::Section(self.text_section), |
| 140 | flags: SymbolFlags::None, |
| 141 | }); |
| 142 | |
| 143 | if let Some(info) = compiled_func.unwind_info() { |
| 144 | self.unwind_info.push(off, body_len, info); |
| 145 | } |
| 146 | |
| 147 | for r in compiled_func.relocations() { |
| 148 | let reloc_offset = off + u64::from(r.offset); |
| 149 | |
| 150 | // This relocation is used to fill in which hostcall id is |
| 151 | // desired within the `call_indirect_host` opcode of Pulley |
| 152 | // itself. The relocation target is the start of the instruction |
| 153 | // and the goal is to insert the static signature number, `n`, |
| 154 | // into the instruction. |
| 155 | // |
| 156 | // At this time the instruction looks like: |
| 157 | // |
| 158 | // +------+------+------+------+ |
| 159 | // | OP | OP_EXTENDED | N | |
| 160 | // +------+------+------+------+ |
| 161 | // |
| 162 | // This 4-byte encoding has `OP` indicating this is an "extended |
| 163 | // opcode" where `OP_EXTENDED` is a 16-bit extended opcode. |
| 164 | // The `N` byte is the index of the signature being called and |
| 165 | // is what's b eing filled in. |
| 166 | // |
| 167 | // See the `test_call_indirect_host_width` in |
| 168 | // `pulley/tests/all.rs` for this guarantee as well. |
| 169 | if let FuncKey::PulleyHostCall(host_call) = r.reloc_target { |
| 170 | #[cfg(feature = "pulley")] |
| 171 | { |
| 172 | use pulley_interpreter::encode::Encode; |
| 173 | assert_eq!(pulley_interpreter::CallIndirectHost::WIDTH, 4); |
| 174 | } |
| 175 | let n = host_call.index(); |
| 176 | let byte = u8::try_from(n).unwrap(); |
no test coverage detected