在 C 代码中使用 memcpy 并使用 wasm 目标编译时出现 llvm-link 错误

llvm-link error when using memcpy in C code and compiling with wasm target

我正在尝试通过 clang 将两个 *.c 文件编译为 LLVM 位码,link 使用 llvm-link 将它们一起编译,并从中生成一个 *.wasm 文件.我通过 https://github.com/yurydelendik/wasmception

提供的 Makefile 在我的机器上构建了 LLVM

在我在 C 代码中使用 memcpy 之前,它工作正常。然后 llvm-link 因错误停止:

Intrinsic has incorrect argument type!
void (i8*, i8*, i32, i1)* @llvm.memcpy.p0i8.p0i8.i32

以下是重现问题的最小示例:

one.c

#define EXPORT __attribute__((visibility("default")))
#include <string.h>

char* some_str();

EXPORT void do_something() {
  char* cpy_src = some_str();
  char other_str[15];
  memcpy(other_str, cpy_src, strlen(cpy_src));
}

two.c

char* some_str() {
  return "Hello World";
}

执行以下命令:

$ clang --target=wasm32-unknown-unknown-wasm --sysroot=../wasmception/sysroot -S -emit-llvm -nostartfiles -fvisibility=hidden one.c -o one.bc
[...]
$ clang --target=wasm32-unknown-unknown-wasm --sysroot=../wasmception/sysroot -S -emit-llvm -nostartfiles -fvisibility=hidden two.c -o two.bc
[...]

请注意,没有进行任何优化,因为这会消除此处不必要的 memcpy 调用。正如我所说,这是一个脱离上下文来显示错误的最小示例。

$ llvm-link one.bc two.bc -o res.bc -v
Loading 'one.bc'
Linking in 'one.bc'
Loading 'two.bc'
Linking in 'two.bc'
Intrinsic has incorrect argument type!
void (i8*, i8*, i32, i1)* @llvm.memcpy.p0i8.p0i8.i32
llvm-link: error: linked module is broken!

当我注释掉示例文件中的 memcpy 调用时,错误消失了。当然,这不是我正在工作的真实项目中的选项。

我是不是做错了什么?在 WebAssembly 上下文中使用 memcpy 通常是个坏主意吗?这可能是 LLVM/Clang 中的错误吗?

通读这些 github 问题,WASM 后端目前似乎不支持 memcpy 内在函数:

https://github.com/WebAssembly/design/issues/236
https://github.com/WebAssembly/design/issues/1003

作为解决方法,您可以指示 clang 使用 -fno-builtin 禁用内部扩展,以便生成的代码将调用实际的 memcpy 函数。