wasm-ld --export-all 不适用于静态库

问题描述 投票:0回答:1

在使用 clang 工具链构建 WASM 模块时,我遇到了一个我很难理解的行为。基本上,我有一个非常简单的 C++ 代码(在

test.cc
中):

extern "C" int foo() { return 42; }

我想以此为基础构建一个 WASM 模块,该模块仅导出其中定义的函数。不同的是,我在链接最终的二进制文件之前添加了创建静态库的中间步骤。

阅读完https://lld.llvm.org/WebAssembly.html#exports后,我就是这样做的:

/usr/bin/clang --target=wasm32 -nostdlib -c test.cc -o test.o
/usr/bin/llvm-ar rcsD libtest.a test.o
/usr/bin/wasm-ld -o test.wasm libtest.a --no-entry --no-gc-sections --export-all

但是查看最终结果,我发现那里没有定义

foo
函数:

llvm-objdump -d test.wasm

test.wasm:      file format wasm

Disassembly of section CODE:

00000000 <CODE>:
        # 1 functions in section.

00000001 <__wasm_call_ctors>:

       3: 0b            end

同时,如果我使用

--export=foo
而不是
--export-all
,它会按我的预期工作:

llvm-objdump -d test.wasm

test.wasm:      file format wasm

Disassembly of section CODE:

00000000 <CODE>:
        # 2 functions in section.

00000001 <__wasm_call_ctors>:

       3: 0b            end

00000004 <foo>:
        .local i32
       8: 41 2a         i32.const       42
       a: 21 00         local.set       0
       c: 20 00         local.get       0
       e: 0f            return
       f: 0b            end

最后,如果我直接使用目标文件而不是先将其打包到静态库中,它也可以按预期工作。这就是我怀疑问题实际上所在的地方。

我可能推测链接器可能有一些逻辑以不同的方式对待静态库,并且仅从明确请求的静态库中导出符号,并且

--export-all
仅适用于保留的符号,而同时,普通的
--export
意味着必须保留该符号。然而,我未能找到上述理论的证实。

有人可以帮助我理解静态库和常规对象文件之间的区别来自哪里吗?因此,为什么

--export-all
不从链接的静态库中导出符号?

这可能是链接器普遍假定的行为,这就是为什么我很难在文档中找到对此的参考?

谢谢你。

FWIW,如果有帮助的话,我也尝试了多种不同的组合:

  1. 使用
    __attribute__(( export_name("blah-blah") ))
    不起作用
  2. 使用
    __attribute__(( visibility("default") ))
    与或不使用
    --export-dynamic
    都不起作用
  3. 直接使用
    wasm-ld
    或通过
    clang
    包装器会产生相同的行为。
linker clang static-libraries webassembly
1个回答
0
投票

我可能推测链接器可能有一些以不同方式对待静态库的逻辑。

没错。

wasm-ld
是 GNU
ld
(GNU linux 链接器)的衍生版本,并且具有 关于何时认为链接需要目标文件的基本规则相同。

任何在命令行中显式输入的目标文件都是无条件、静态地需要的 链接到输出图像。

默认情况下,作为静态库的存档成员的目标文件被认为是需要的, 当且仅当它为未解析的符号引用提供至少一个定义 已在链接中较早累积。请参阅 Stackoverflow 静态库标签 wiki

此默认值可以通过以下方式覆盖:

--whole-archive libtest.a --no-whole-archive

效果:

--whole-archive liba.a [libb.a]... --no-whole-archive

就是让链接器暂停其对于静态库顺序的默认策略

liba.a [libb.a]...
并考虑这些档案中的所有目标文件 无论他们是否解决任何引用,都需要。请参阅
wasm-ld --help

如果

--whole-archive
未生效,则链接必须在任何对象之前至少消耗一个显式对象文件 静态库中的文件将被视为需要,因为没有未解析的引用可以 累积直到显式输入包含某些未解析引用的目标文件。

您的链接:

`/usr/bin/wasm-ld -o test.wasm libtest.a --no-entry --no-gc-sections --export-all

不会改变这一点。

--export-all
的作用只是迁移所有符号 将输出图像的全局符号表放入其动态符号表中,使得 它们可供动态链接器访问。但由于
libtest.a(test.o)
甚至没有链接 进入图像,
foo
首先不会进入全局符号表。

另一方面,您的链接:

`/usr/bin/wasm-ld -o test.wasm libtest.a --no-entry --no-gc-sections --export=foo

确实有效,因为:

$ wasm-ld --help | grep '\--export=<value>'
  --export=<value>        Force a symbol to be exported
  

关键词是力量

--export=foo
的作用是强制链接器假设 在链接消耗任何文件之前以及最后,
foo
是一个未解析的引用 如果找到定义,则在动态符号表中输入
foo
。该假设将 诱导链接器认为需要
libtest.a(test.o)
,在您的情况下,该链接相当于:

$ /usr/bin/wasm-ld -o test.wasm libtest.a --no-entry --no-gc-sections --undefined=foo --export-all

您尝试使用:

__attribute__(( export_name("blah-blah") ))

和:

__attribute__(( visibility("default") ))

不成功,因为第一个仅导致应用到的符号由别名表示 图像的动态符号表,第二个仅应用默认的动态可见性 到图像中的符号。如果没有定义,它们都不能使图像中的符号被定义 其中已链接。

© www.soinside.com 2019 - 2024. All rights reserved.