This is an archive of the discontinued LLVM Phabricator instance.

[WebAssembly] Use __stack_pointer global when writing wasm binary
ClosedPublic

Authored by sbc100 on Jun 13 2017, 2:11 PM.

Details

Summary

This ensures that symbolic relocations are generated for SP
accesses. Each object file models __stack_pointer as an
undefined external (a wasm import) which the linker can
then resolve by synthesizing a mutable global.

The relocations are of type R_WEBASSEMBLY_GLOBAL_INDEX_LEB
and this change also adds support for reading these types
of relocations.

Since its a globally imported symbol this does mean that
the get_global/set_global instruction won't be valid until
the objects are linked.

Diff Detail

Repository
rL LLVM

Event Timeline

sbc100 created this revision.Jun 13 2017, 2:11 PM

If you like I could probably split out the part of this change that is generally adding support for R_WEBASSEMBLY_GLOBAL_INDEX_LEB.

sbc100 updated this revision to Diff 102423.Jun 13 2017, 2:44 PM

revert part

sbc100 updated this revision to Diff 102430.Jun 13 2017, 3:02 PM
  • add a explict test in test/MC/WebAssembly
sbc100 edited the summary of this revision. (Show Details)Jun 13 2017, 3:57 PM
sunfish accepted this revision.Jun 16 2017, 11:15 AM

This looks like a good idea. It was awkward trying to track global variable indices in the MachineModuleInfo. In fact, you can just remove the MachineModuleInfoWasm class entirely now, unless you have another use for it.

This revision is now accepted and ready to land.Jun 16 2017, 11:15 AM
This revision was automatically updated to reflect the committed changes.
aheejin removed a subscriber: aheejin.
sanketdiwale added a subscriber: sanketdiwale.EditedJan 9 2021, 6:37 PM

Could you clarify what the __stack_pointer expects from the external code.

**//Edit://** Never mind. I found the clarification to the __stack_pointer problem here: https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md#interface-and-usage. Just needed to understand what the pointer was referring to. Giving a high enough initial value as an offset in the linear memory object for the stack, solves the problem. Leaving the original question below. Just in case someone is having the same problem.

I generated .wasm code for accessing a struct defined in c++ and when trying to run the corresponding code from the wasm module imported into a javascript file. I end up getting a "bus error:10". Simpler codes where the __stack_pointer is not used work fine.

To make things more concrete, I have a c++ code like:

// c++ code
struct foo {
 double a;
 double b;
}

double f(double x){
  foo r;
  r.b = x;
  return 0.0;
}

This generates a wasm file of the form

(module
  (type $t1 (func (param f64) (result f64)))
  (import "env" "__linear_memory" (memory $env.__linear_memory 0))
  (import "env" "__indirect_function_table" (table $env.__indirect_function_table 0 funcref))
  (import "env" "__stack_pointer" (global $env.__stack_pointer (mut i32)))
...
  (func $f (type $t1) (param $p0 f64) (result f64)
  (local $l1 i32) (local $l2 f64)
    global.get $env.__stack_pointer
    i32.const 32
    i32.sub
    local.tee $l1
    global.set $env.__stack_pointer
    local.get $l1
    ...
  )
  (export "f" (func $f))
...

and so on, using the __stack_pointer load and store values onto a stack.

However it's not clear as to what the stack object is when referenced from the external file.

For example, if I instantiate the corresponding wasm file from a javascript as shown below, it leads to crash with "bus error:10" displayed in the terminal:

// js file to load module
const http = require('http');
const fs = require('fs');

const buf = fs.readFileSync('foo.wasm');
var typedbuf = new Uint8Array(buf);
const env = {
    __linear_memory: new WebAssembly.Memory({initial:256}),
    __indirect_function_table: new WebAssembly.Table({initial:0,element:'anyfunc'}),
    __stack_pointer: new WebAssembly.Global({value:'i32', mutable:true}, 0)
}
WebAssembly.instantiate(typedbuf,{env:env}).then(res=>console.log(res.instance.exports.f(4))).catch(e => {
    // error caught
    console.log(e);
  });
...

Here the WebAssembly.instantiate, defines the imports in "env" and includes a "_ _stack_pointer" as a WebAssembly.Global object. However this doesn't seem to work as stated previously.
Does the "_ _stack_pointer" have to refer to a particular memory address, say from the "_ _linear_memory" object defined for the module? Or is there something else that the __stack_pointer should be referring to?

Herald added a project: Restricted Project. · View Herald TranscriptJan 9 2021, 6:37 PM