LLVM IR - › WebAssembly Wasm โมดูลว่างเปล่า | ตัวอย่าง

ฉันกำลังพยายามสร้างไฟล์ wasm ที่ถูกต้องซึ่งเว็บเบราว์เซอร์ (Firefox) จะเข้าใจได้อย่างถูกต้อง แต่ฉันไม่แน่ใจว่าฉันทำผิดที่นี่

นี่คือไฟล์ Main.ll

define i32 @main() {
  ret i32 42
}

จากนั้นฉันใช้ llc (Linux):

./llc -mtriple=wasm32-unknown-unknown -O3 -filetype=obj main.ll -o main.o

จากนั้นฉันใช้ wasm-ld (Linux):

./wasm-ld main.o -o main.wasm --no-entry -allow-unknown

จากนั้นฉันกำลังคัดลอก main.wasm ไปยัง Windows แล้วเปิดหน้าไฟล์ในเครื่องนี้:

|-- fille.html
|-- main.wasm

<div id="test">
</div>

<style>
    #test
    {
        border: 3px solid red;
        width: 100%;
        height: 100%;
    }
</style>

<script>
    fetch("main.wasm")
        .then(response => response.arrayBuffer())
        .then(bytes => WebAssembly.instantiate(bytes, {}))
        .then(results => {
          window.alert(results.instance.exports.main());
        });
</script>

แต่

TypeError: results.instance.exports.main ไม่ใช่ฟังก์ชัน

เกิดอะไรขึ้น?

นี่คือผลลัพธ์ของ:

console.log(JSON.stringify(ผลลัพธ์));

{"module":{},"instance":{}}

รุ่น:

./llc --version

LLVM (http://llvm.org/):
LLVM version 10.0.0

./wasm-ld --version

LLD 10.0.0

person Axelly    schedule 15.03.2020    source แหล่งที่มา


คำตอบ (1)


เหตุผลก็คือคุณไม่ได้ส่งออกสัญลักษณ์ใดๆ ในระหว่างการเชื่อมโยง

คุณอาจต้องการตรวจสอบ the Exports section of wasm-ld docs เพื่อดูรายละเอียด แต่นี่คือสิ่งที่พวกเขาพูดถึงเกี่ยวกับค่าเริ่มต้น:

เมื่อสร้างปฏิบัติการ เฉพาะจุดเริ่มต้น (_start) และสัญลักษณ์ที่มีแฟล็ก WASM_SYMBOL_EXPORTED เท่านั้นที่จะถูกส่งออกตามค่าเริ่มต้น

คุณมีสองทางเลือก:

  1. เปลี่ยนชื่อ main เป็น _start - สิ่งนี้จะช่วยให้แน่ใจว่า _start จะถูกส่งออกและการพึ่งพาใด ๆ ของมันจะถูกนำเข้าอย่างถูกต้องจากสภาพแวดล้อม แทนที่จะเป็น GCd ทั้งหมด เช่นเดียวกับสิ่งที่เกิดขึ้นในขณะนี้
  2. โทร wasm-ld ด้วยแฟล็ก --export-all - สิ่งนี้จะส่งออกสัญลักษณ์ทั้งหมดในไฟล์อ็อบเจ็กต์ โดยทั่วไปไม่แนะนำให้ใช้ตัวเลือกนี้ เนื่องจากคุณอาจป้องกันการปรับขนาดที่เป็นประโยชน์และเปิดเผยสิ่งที่คุณไม่ได้ตั้งใจจะเปิดเผย แต่อาจใช้ได้สำหรับการสร้างต้นแบบ
  3. โทร wasm-ld ด้วย --export-dynamic - จะส่งออกสัญลักษณ์ทั้งหมดที่ทำเครื่องหมายว่ามองเห็นได้ในระดับ IR
  4. แสดงรายการสัญลักษณ์อย่างชัดเจนเมื่อเรียก wasm-ld ด้วย เช่น --export=main.

ข้อแม้อีกประการหนึ่งที่ควรทราบในทุกตัวเลือกยกเว้น (1) ก็คือ main ได้รับการปฏิบัติในลักษณะพิเศษ และด้วยโค้ดปัจจุบันของคุณ มันจะส่งผลให้มีสัญลักษณ์ที่แตกต่างกันสองตัว:

  1. main - wrapper ฟังก์ชันที่สร้างขึ้นอัตโนมัติโดยมีสอง args สำหรับ argc และ argv ที่เรียกใช้ฟังก์ชันของคุณ
  2. __original_main - สัญลักษณ์ของฟังก์ชันที่คุณกำหนดไว้จริง

เพื่อให้แน่ใจว่าคุณจะไม่ประสบปัญหานี้ ให้ทำตามตัวเลือกที่ 1 และเปลี่ยนชื่อ main เป็น _start ซึ่งเป็นจุดเข้าเฉพาะของ Wasm และไม่ยอมรับพารามิเตอร์ใดๆ หรือเปลี่ยนลายเซ็นของฟังก์ชัน main ของคุณเป็นฟังก์ชันที่ถูกต้องและยอมรับทั้งสองอย่าง argc และ argv เหมือนใน C.

หวังว่าทั้งหมดนี้จะช่วยให้คุณก้าวต่อไปได้

person RReverser    schedule 15.03.2020
comment
@Axelly ดีใจที่มันช่วยได้ :) - person RReverser; 17.03.2020