想要遵循本文中的操作:https://surma.dev/things/c-to-webassemble/但是使用 Rust 并编写一个自定义分配器。
为此,我需要访问 llvm 添加的
__heap_base
变量作为线性内存中堆开始位置的指针。 Rust 有没有办法实现这一点?
我尝试了
的变体extern "C" {
static __heap_base: i32;
}
#[no_mangle]
pub unsafe extern "C" fn main() -> i32 {
__heap_base
}
但它们返回 0 而不是二进制中分配的实际值。
经过一番研究后。答案的一个想法是,您的程序的值与编译器/链接器然后在 wasm 文件中定义的值之间似乎存在差异。原则上不存在一对一的关系。
当你在 C/Rust 中定义变量时,你得到的是变量,而不是变量本身的地址。即:如果定义一个指针,您将获得指针指向的数据的地址,而不是存储该指针的值的地址。
因此,通过指定
static __heap_base: i32
,您要求编译器将 __heap_base 值设置为 i32,而不是堆基指针(这就是 llvm 然后将其写入 wasm i32,无论您为 __heap_base
设置什么类型)。该值的地址是指向 __heap_base
的实际指针
为什么你可以导入
__heap_base
因为堆基指向的值对我来说仍然不太清楚。也许符号总是意味着值,像 *__heap_base
这样的东西只是一个指针,当取消引用时它会给你 __heap_base
(值),并且它在内部被这样对待
链接器符号始终是指针,因此在 Rust 中,
extern static
声明定义了它指向的事物的类型。 i32
很好,但 i8
可能更好,因为这清楚地表明 __heap_base
的 dereferenced值太小而不会被混淆为指针。你想要的是一个指向(Rust 的概念)
__heap_base
的指针。
这是一些适用于我的项目的示例代码:
extern "C" {
/// &__heap_base: the start of the heap
static __heap_base: u8;
}
fn heap_start() -> usize {
// SAFETY: __heap_base is actually const (read-only) from our POV.
// it's initialized by the runtime, and provides the address where
// our "heap" should start.
unsafe { &__heap_base as *const u8 as usize }
}
如果您想要原始指针,可以删除
as usize
。