<div dir="ltr">Yes, you've got the right idea. The reason the function index needs to be indirected through the GOT is because you are using -fPIC and you are correct about the visibility as well. See `requiresGOTAccess` and the comment in `addGOTEntry` in lld/wasm/Relocations.cpp for the specifics of how the visibility and PIC affect this.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Aug 6, 2020 at 7:29 AM Ömer Sinan Ağacan <<a href="mailto:omeragacan@gmail.com">omeragacan@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Thanks, I joined Discord as well.<br>
<br>
Here's an update: I was able to come up with a tiny C program which is compiled<br>
to a similar "GOT.func" import. C code:<br>
<br>
    __attribute__ ((visibility("default")))<br>
    int c_fn_2(int x, int y)<br>
    {<br>
        return x + y;<br>
    }<br>
<br>
    __attribute__ ((visibility("default")))<br>
    int (*c_fn(void)) (int x, int y)<br>
    {<br>
        return &c_fn_2;<br>
    }<br>
<br>
Compile with:<br>
<br>
    clang-10 -fPIC --target=wasm32-unknown-emscripten test.c -c -o test.o -O<br>
    wasm2wat test.o > test.wat<br>
<br>
Generated wat:<br>
<br>
    (module<br>
      (type (;0;) (func (param i32 i32) (result i32)))<br>
      (type (;1;) (func (result i32)))<br>
      (import "env" "__linear_memory" (memory (;0;) 0))<br>
      (import "env" "__indirect_function_table" (table (;0;) 0 funcref))<br>
      (import "GOT.func" "c_fn_2" (global (;0;) (mut i32)))<br>
      (func $c_fn_2 (type 0) (param i32 i32) (result i32)<br>
        local.get 1<br>
        local.get 0<br>
        i32.add)<br>
      (func $c_fn (type 1) (result i32)<br>
        global.get 0))<br>
<br>
Now if I remove the visibility attribute in `c_fn_2` the GOT.func import<br>
disappears:<br>
<br>
    (module<br>
      (type (;0;) (func (param i32 i32) (result i32)))<br>
      (type (;1;) (func (result i32)))<br>
      (import "env" "__linear_memory" (memory (;0;) 0))<br>
      (import "env" "__indirect_function_table" (table (;0;) 0 funcref))<br>
      (import "env" "__table_base" (global (;0;) i32))<br>
      (func $c_fn_2 (type 0) (param i32 i32) (result i32)<br>
        local.get 1<br>
        local.get 0<br>
        i32.add)<br>
      (func $c_fn (type 1) (result i32)<br>
        global.get 0<br>
        i32.const 0<br>
        i32.add))<br>
<br>
Comparing these two programs I think I see a potential answer to my question of<br>
why this GOT.func import is needed. I can't find documentation how what these<br>
attributes mean exactly (the closest one I could find is [1]), but I think<br>
without `visibility("default")` the symbol is not visible in other compilation<br>
units (here I think "compilation unit" means a module in Wasm, though it may<br>
also be a C compilation unit, I'm not sure), in other words it's DSO-local. When<br>
it's DSO-local the importing modules do not need to know about the function's<br>
table index as they can never refer to it directly (e.g. the C expression<br>
`c_fn_2` doesn't make sense in the importing modules).<br>
<br>
When we add `visibility("default")` and make c_fn_2 visible in other modules we<br>
need to be able to compare return value of `c_fn` with the value of symbol<br>
`c_fn_2`, as that pointer equality must hold according to C standard.<br>
<br>
The approach taken here is we expect the symbol's table index to be defined in<br>
the *loading module*, and import that index with that `GOT.func` import. The<br>
host (e.g. wasmtime or the browser) is then responsible for generating a table<br>
index for this function in the loading module and providing that "GOT.func"<br>
import in load time. In importing module code we use that index for c_fn_2, so<br>
if the importing module does something like `c_fn_2 == c_fn()` that's evaluated<br>
to `true` as expected.<br>
<br>
Can anyone deny or confirm that this is indeed the reason for that `GOT.func`<br>
import?<br>
<br>
Thanks,<br>
<br>
Ömer<br>
<br>
[1]: <a href="https://clang.llvm.org/docs/LTOVisibility.html" rel="noreferrer" target="_blank">https://clang.llvm.org/docs/LTOVisibility.html</a><br>
<br>
Thomas Lively <<a href="mailto:tlively@google.com" target="_blank">tlively@google.com</a>>, 6 Ağu 2020 Per, 00:54 tarihinde şunu yazdı:<br>
><br>
> +Sam Clegg Is the expert on this dynamic linking stuff.<br>
><br>
> A lot of us WebAssembly toolchain folks have been hanging out in the WebAssembly Discord, especially on the #emscripten channel, so that would be another good place to ask future WebAssembly-specific questions.<br>
><br>
> On Tue, Aug 4, 2020 at 9:06 PM Ömer Sinan Ağacan via llvm-dev <<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a>> wrote:<br>
>><br>
>> Hi,<br>
>><br>
>> Sorry if you've seen this message before on llvm.discourse.group or elsewhere --<br>
>> I've been trying to get to the bottom of this for a while now and asked about<br>
>> this in a few different platforms before.<br>
>><br>
>> I'm currently trying to debug a bug in a LLVM-generated Wasm code. The bug could<br>
>> be in the code that generates LLVM (rustc) or in the LLVM, I'm not sure yet.<br>
>> LLVM IR and Wasm can be seen in [1].<br>
>><br>
>> The problem is this line:<br>
>><br>
>>     (import "GOT.func"<br>
>> "_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$i32$GT$3fmt17h9ba9fea9cadf7bd5E"<br>
>> (global (;3;) (mut i32)))<br>
>><br>
>> The same symbol is already imported from "env" in the same module:<br>
>><br>
>>     (import "env"<br>
>> "_ZN5core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$i32$GT$3fmt17h9ba9fea9cadf7bd5E"<br>
>> (func (;4;) (type 1)))<br>
>><br>
>> So there's no need to import it from "GOT.func" and I want to get rid of that<br>
>> "GOT.func" import.<br>
>><br>
>> This LLVM IR is generated when compiling Rust code to a "staticlib", which is<br>
>> supposed to include *all* dependencies of the code so that it'll be linkable<br>
>> with code for other languages. Because of the "GOT.func" import this module is<br>
>> not linkable, it needs to resolve that "GOT.func" import in runtime using<br>
>> dynamic linking for Wasm [2].<br>
>><br>
>> I'm trying to understand whether this is a rustc bug or an LLVM bug. I'm using<br>
>> LLVM 10 downloaded from the official web page and rustc nightly. I can build<br>
>> LLVM from source and use it, but I don't have any experience in LLVM code base.<br>
>> Questions:<br>
>><br>
>> - Given a reference to a symbol, how does LLVM decide how to import it?<br>
>>   Currently I see these uses of the problematic symbol in LLVM IR:<br>
>><br>
>>   - `store i8* bitcast (i1 (i32*, %"core::fmt::Formatter"*)*<br>
>> @"_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$i32$GT$3fmt17h9ba9fea9cadf7bd5E"<br>
>> to i8*), i8** %11, align 4`<br>
>><br>
>>   - `store i8* bitcast (i1 (i32*, %"core::fmt::Formatter"*)*<br>
>> @"_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$i32$GT$3fmt17h9ba9fea9cadf7bd5E"<br>
>> to i8*), i8** %14, align 4`<br>
>><br>
>>   - `store i8* bitcast (i1 (i32*, %"core::fmt::Formatter"*)*<br>
>> @"_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$i32$GT$3fmt17h9ba9fea9cadf7bd5E"<br>
>> to i8*), i8** %17, align 4`<br>
>><br>
>>   - `declare zeroext i1<br>
>> @"_ZN4core3fmt3num3imp52_$LT$impl$u20$core..fmt..Display$u20$for$u20$i32$GT$3fmt17h9ba9fea9cadf7bd5E"(i32*<br>
>> noalias readonly align 4 dereferenceable(4), %"core::fmt::Formatter"*<br>
>> align 4 dereferenceable(36)) unnamed_addr #1`<br>
>><br>
>>   First three look very similar so I'm guessing the first three are causing one<br>
>>   of those imports, and the last one is causing the other import, but I'm not<br>
>>   sure which one is generating which import. Any ideas?<br>
>><br>
>> - Any suggestions on how to debug this? Just knowing which line in the LLVM IR<br>
>>   listed above causes this "GOT.func" import would be helpful.<br>
>><br>
>> Thanks,<br>
>><br>
>> Ömer<br>
>><br>
>> [1]: <a href="https://gist.github.com/osa1/4c672fe8998c8e8768cf9f7c014c61d8" rel="noreferrer" target="_blank">https://gist.github.com/osa1/4c672fe8998c8e8768cf9f7c014c61d8</a><br>
>> [2]: <a href="https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md" rel="noreferrer" target="_blank">https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md</a><br>
>> _______________________________________________<br>
>> LLVM Developers mailing list<br>
>> <a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a><br>
>> <a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</a><br>
</blockquote></div>