2017-04-26 239 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