2017-04-26 278 views
0

我目前正忙于使用通过LLVM编译的WebAssembly,但我还没有设法理解堆栈/堆栈指针以及它如何与整个内存布局相关。WebAssembly堆栈/堆栈指针初始化和内存布局

我得知我必须使用s2wasm--allocate-stack N使我的程序运行和我想,这基本上增加(data (i32.const 4) "8\00\00\00")(与N = 8)到我生成一伙,与二进制部分显然是一个指针到存储器偏移量和i32常量是它在线性存储器中的偏移量。

然而,我不太明白的是,为什么指针的值是56(同样是N = 8),以及这个值如何与内存中堆栈的确切区域相关,在我的情况下像:

0-3: zero 4-7: 56 7-35: other data sections 36-55: zeroes 56-59: zero

我知道,我是“只使用emscripten”可能更多的候选人,但我也想明白这一点。

  • 堆栈指针是否始终存储在线性内存的偏移量4?
  • 它的初始值是如何计算的? (在数据之后对齐到下一个偏移%16 == 0 + N)
  • 之前存储了什么,以及它指向的偏移之后有什么?

回答

4

我在another question中提到过这个。从C++的堆实际上有3个地方的值可以结束:

  1. 在执行堆栈(操作码的每个推压并弹出的值,因此add啪啪2,再压入1)。
  2. 作为本地人。
  3. Memory

注意,你不能拿的1和2的地址只有在这些情况下,我希望一个代码生成器去与3,如何做到这一点没有被WebAssembly决定的,它取决于无论你选择哪种ABI。 Emscripten和其他工具所做的是将堆栈指针存储在地址4处,然后在程序的早期选择堆栈应该到的位置。它不是始终是4,但总是坚持ABI,尤其是涉及动态链接时更简单。

初始值:该位置必须足够大以容纳整个堆栈,并且malloc的实现必须知道它,因为它无法为其分配堆空间。这就是为什么一些工具允许你指定最大尺寸。

任何事情都可以在之前/之后存储(尽管之后您可能会有先前的堆栈值)。 WebAssembly当前没有防护页,所以耗尽内存堆栈会破坏堆值(除非代码生成器也发出堆栈检查)。这完全是“内存安全”,因为它仍然无法逃脱WebAssembly.Memory,所以浏览器无法拥有,但开发人员自己的代码完全可以拥有。构建在WebAssembly之上的内存安全语言必须在WebAssembly.Memory内强制执行内存安全性。

请注意,我没有解释1和2。它们的存在意味着大多数C++程序在WebAssembly中使用的内存堆栈少于使用堆栈的本地C++程序。

+0

谢谢您的详细解答。我想要做的是自己创建一个运行时,运行一些超级基本的C代码,我用cmake - > s2wasm - > wast2wasm编译。如您所述,malloc需要知道堆栈的位置,以便它不会对其进行分配。但它是如何知道的?假设在使用binaryen工具链时,初始堆栈指针值指向最大偏移量exclusive,VM应该将堆栈值放在 - 并且malloc可以使用超出该偏移量的所有内容时是否正确? – dcode

+0

链接器输出'__stack_pointer',如果你指定了一个堆栈分配大小,它也会输出一个名为'.stack'的重定位。这不是唯一的方法,如果你自己推出,我建议你看看[tool-conventions](https://github.com/WebAssembly/tool-conventions/),其中包括建议使用全局为堆栈指针。 –

+0

是否有可能通过clang/s2wasm/wasm这样的全球性产生这样的全球性?我现在结束了'int stacktop(){int * ptr; return(int)&ptr + sizeof(int *); },这可能与从JS背景来到WebAssembly的人所期望的一样愚蠢。但无论如何,感谢您的耐心! – dcode