如何防止wasi-sdk的clang++在每个导出的函数中插入__wasm_call_ctors调用?

huangapple go评论56阅读模式
英文:

How to prevent wasi-sdk clang++ from inserting __wasm_call_ctors call to every exported function?

问题

I'm building C++ WASM application using wasi-sdk (versions 17 and 20 tested) clang++ as a compiler. I'm running the WASM code using WAMR in a custom embedded runtime. I use WAMR build-in libc instead of wasi-sdk's one. The application does not have main() - it exports few functions that the runtime calls when necessary. The problem I have is that clang++ inserts calls to constructors of static objects to all of my entry points.

Sample code:

struct Bar
{
    Bar() {}
};

Bar bar;

extern "C" void foo() {}

The build command I use is:

/opt/wasi-sdk/bin/clang++ -Wl,--no-entry -Wl,--allow-undefined -Wl,--export=foo -nostdlib -lc++ -lc++abi test.cpp

This results WASM code that calls c'tors every time (showing only foo export):

(func $foo (type 0)
  return)
(func $foo.command_export (type 0)
  call $__wasm_call_ctors         <<< this is the problem
  call $foo)
(export "foo" (func $foo.command_export))

-nostdlib -lc++ -lc++abi are needed to get rid of wasi-sdk libc but still provide its C++ standard library. If I compile without these flags, the export is as expected:

(export "foo" (func $foo))

Question: how to prevent clang++ from inserting calls to static object c'tors?

英文:

I'm building C++ WASM application using wasi-sdk (versions 17 and 20 tested) clang++ as a compiler. I'm running the WASM code using WAMR in a custom embedded runtime. I use WAMR build-in libc instead of wasi-sdk's one. The application does not have main() - it exports few functions that the runtime calls when necessary. The problem I have is that clang++ inserts calls to constructors of static objects to all of my entry points.

Sample code:
<!-- language: c++ -->

struct Bar
{
    Bar() {}
};

Bar bar;

extern &quot;C&quot; void foo() {}

The build command I use is:

/opt/wasi-sdk/bin/clang++ -Wl,--no-entry -Wl,--allow-undefined -Wl,--export=foo -nostdlib -lc++ -lc++abi test.cpp

This results WASM code that calls c'tors every time (showing only foo export):

  (func $foo (type 0)
    return)
  (func $foo.command_export (type 0)
    call $__wasm_call_ctors         &lt;&lt;&lt; this is the problem
    call $foo)
  (export &quot;foo&quot; (func $foo.command_export)))

-nostdlib -lc++ -lc++abi are needed to get rid of wasi-sdk libc, but still provide it's C++ standard library. If I compile without these flags the export is as expected:

  (export &quot;foo&quot; (func $foo)))

Question: how to prevent clang++ from inserting calls to static object c'tors?

答案1

得分: 1

问题在于 -Wl,--no-entry 移除了通常调用 __wasm_call_ctors_start 函数。由于静态构造函数现在不再被调用,clang 决定在每个导出的函数中插入这些包装函数,以确保静态构造函数被调用。显然,这是一项特性 - 在这里有一个关于此的好讨论:https://reviews.llvm.org/D62922。

因此,解决方案是:

  • 使用链接器标志 -mexec-model=reactor -nostdlib -lc++ -lc++abi
  • 提供名为 _initialize 的 wasm 函数,该函数只调用 __wasm_call_ctors
  • 一旦加载 WASM 模块,从运行时作为第一步调用 _initialize
英文:

The problem was that -Wl,--no-entry removed _start function that normally calls __wasm_call_ctors. As static c'tors were now not called, clang decided to insert those wrappers to each and every exported function to ensure statics constructors are called. Apparently this is a feature - here's a good discussion about this: https://reviews.llvm.org/D62922.

So the solution is to

  • use linker flags -mexec-model=reactor -nostdlib -lc++ -lc++abi
  • provide wasm function _initialize that just calls __wasm_call_ctors
  • call _initialize from the runtime as a 1st thing once the WASM module
    is loaded

huangapple
  • 本文由 发表于 2023年6月16日 03:33:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76484993.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定