[llvm] [WebAssembly] Support multiple `.init_array` fragments when writing Wasm objects (PR #111008)

George Stagg via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 17 03:59:19 PDT 2024


georgestagg wrote:

> I suppose that C++ and rust always generate just a single fragment which is why we haven't seen issues with this before?

I guess so, let me throw together a quick C++ example and see how it currently handles the constructors...

<details>
First, compile and test this C++ code:

```cpp
#include <iostream>
using namespace std;

class Init1 {
  public: Init1() { cout << "Init1" << endl; }
};

class Init2 {
  public: Init2() { cout << "Init2" << endl; }
};

Init1 init1a;
Init1 init1b;
Init2 init2;

int main() {
  cout << "main" << endl;
  return 0;
}
```

```
$ em++ -S -emit-llvm -c test.cpp -o test.ll
$ em++ -c test.cpp -o test.o
$ em++ test.o -o test.js

$ node test.js
Init1
Init1
Init2
main
```

Let's make sure the `WASM_INIT_FUNC` subsection is populated in the object `test.o`:

```
$ /[...]/bin/obj2yaml test.o
[...]
  - Type:            CUSTOM
    Name:            linking
    Version:         2
    SymbolTable:
[...]
      - Index:           68
        Kind:            FUNCTION
        Name:            _GLOBAL__sub_I_test.cpp
        Flags:           [ BINDING_LOCAL ]
[...]
    InitFunctions:
      - Priority:        65535
        Symbol:          68
[...]
```

Yes, but just with a single function. I suppose the constructor functions have been coalesced into a single function. Let's take a look in `test.ll`:

```
@llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @_GLOBAL__sub_I_test.cpp, ptr null }]

[...]
; Function Attrs: noinline
define internal void @_GLOBAL__sub_I_test.cpp() #0 {
  call void @__cxx_global_var_init()
  call void @__cxx_global_var_init.1()
  call void @__cxx_global_var_init.2()
  ret void
}
``` 

Indeed, the global constructors are combined into a single function. Note that LLVM generates code using `@llvm.global_ctors`, rather than adding to the `.init_array` section, presumably because `.init_array` is not portable.
</details>

Yes, at least for simple C++.

> BTW viewing this diff with "ignore whitespace" helped a lot to see what was going on.

Yes, apologies. The diff is smaller than it looks due to the change in indentation!

> Regarding the test case, can it be written in assembly instead?

Unfortunately, I'm not sure how to express this in WebAssembly text format directly. There is an open issue about defining custom sections (https://github.com/WebAssembly/design/issues/1153) in the text format and I'm not entirely sure how to express the test, since the bug occurs in the code that converts the `.init_array` pointers into the format required for the custom `linking` section.

I would be willing to change the test, but would need specific help in how to proceed.

https://github.com/llvm/llvm-project/pull/111008


More information about the llvm-commits mailing list