<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/84424>84424</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            lld/mingw: Behavior difference with ld.bfd when re-exporting imported global
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            lld:COFF,
            julialang
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          Keno
      </td>
    </tr>
</table>

<pre>
    Over in https://github.com/JuliaLang/julia/pull/53421, we are seeing an issue where a library linked with `ld.bfd` is working, but `lld` is not (when targeting win64/mingw). The code in question is a bit strange, but it's essentially a sanity check to make sure that there weren't any linking mistakes and that there aren't multiple copies of the runtime library floating around (e.g. a common mistake is to load both debug and release copies of the runtime library into the same address space).
 
In reduced terms, we have a source file that at the LLVM level looks like this (fully minimized):
```
# cat metadata.ll
; ModuleID = 'metadata_opt.bc'
source_filename = "metadata"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-w64-windows-gnu-coff"

@jl_RTLD_DEFAULT_handle = external dllimport constant ptr
@jl_RTLD_DEFAULT_handle_pointer = dllexport constant ptr @jl_RTLD_DEFAULT_handle

define x86_stdcallcc i32 @_DllMainCRTStartup(ptr %0, i32 %1, ptr %2) {
top:
  ret i32 1
}
```

where `jl_RTLD_DEFAULT_handle` is just some `dllexported` global defined in `libjulia-internal.dll`, but for the present purposes, we may just treat it as the following:
```
# cat fakelibjulia.c
__declspec(dllexport) void *jl_RTLD_DEFAULT_handle = 0;
# gcc -shared -o libfakejulia.dll fakelibjulia.c 
```

Doing the following:
```
# llc.exe --filetype=obj -o metadata.o metadata.ll
# ld --disable-runtime-pseudo-reloc -shared -o metadata-bfd.dll --whole-archive metadata.o --no-whole-archive libfakejulia.dll
# lld.exe  -flavor gnu -m i386pep -Bdynamic --disable-runtime-pseudo-reloc -shared -o metadata-lld.dll --whole-archive metadata.o --no-whole-archive -L./usr/bin -ljulia -ljulia-internal
lld: error: automatic dllimport of jl_RTLD_DEFAULT_handle in metadata.o requires pseudo relocations
# lld.exe  -flavor gnu -m i386pep -Bdynamic --enable-runtime-pseudo-reloc -shared -o metadata-lld.dll --whole-archive metadata.o --no-whole-archive -L./usr/bin -ljulia -ljulia-internal
```

And then loading both libraries and comparing the pointers:
```
# cat print_pointers.c
#include <stdio.h>

extern __declspec(dllimport) void *jl_RTLD_DEFAULT_handle;
extern __declspec(dllimport) void *jl_RTLD_DEFAULT_handle_pointer;

int main(void) {
 printf("Pointers: %p %p\n", &jl_RTLD_DEFAULT_handle, jl_RTLD_DEFAULT_handle_pointer);
        return 0;
}
# gcc -o print_pointers-bfd.exe print_pointers.c metadata-bfd.dll libfakejulia.dll
# gcc -o print_pointers-lld.exe print_pointers.c metadata-lld.dll libfakejulia.dll
# ./print_pointers-bfd.exe
Pointers: 00007ffafef77020 00007ffafef77020
# ./print_pointers-lld.exe
Pointers: 00007ffafef77020 00007ffb0d1b20e0
```

The BFD result is expected. The LLD result is not (separate and apart from the fact that lld and bfd disagree over the necessity of runtime pseudo relocations - the output is the same for bfd if those are enabled, although it does require linking the mingw dllcrt in that case).

Finally, I want to note that the issue is the library, not the executable. The same behavior is observed via dlsym (as in the original issue).
```
julia> lib_lld = dlopen("metadata-lld.dll")
Ptr{Nothing} @0x00007ffb0d1b0000

julia> lib_bfd = dlopen("metadata-bfd.dll")
Ptr{Nothing} @0x00007ffb08ff0000

julia> unsafe_load(Ptr{Ptr{Cvoid}}(dlsym(lib_lld, "jl_RTLD_DEFAULT_handle_pointer")))
Ptr{Nothing} @0x00007ffb0d1b20e0

julia> unsafe_load(Ptr{Ptr{Cvoid}}(dlsym(lib_bfd, "jl_RTLD_DEFAULT_handle_pointer")))
Ptr{Nothing} @0x00007ffab81a9818

julia> cglobal(:jl_RTLD_DEFAULT_handle, Ptr{Cvoid})
Ptr{Ptr{Nothing}} @0x00007ffab81a9818
```

In particular, the value that lld gives is one extra level of indirection removed from that used by bfd:
```
julia> unsafe_load(unsafe_load(Ptr{Ptr{Ptr{Cvoid}}}(dlsym(lib_lld,` "jl_RTLD_DEFAULT_handle_pointer"))))
Ptr{Nothing} @0x00007ffb0d1b20e0
```

Versions:
```
# ld --version
GNU ld (GNU Binutils) 2.42
Copyright (C) 2024 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.
# lld.exe -flavor ld --version
LLD 16.0.6 (compatible with GNU linkers)
```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzMWFtv6zgO_jXqC-HAkdNcHvrQJpPB2e1cMHNmXgPZomOdypJHkpNmf_2Ckp2T0zbtXLDAFqnj2BRvIj-SEt6rvUG8Y7cP7HZzI_rQWHf3bzT2prTydPfTAR0oA00InWfFPeNbxrd7FZq-nFS2ZXz7r14r8SjMnvHtF7pnfNv1WjO-vS1mfMr4Go4IwiF4RGX2IAwo73uEY4MOQYBWpRPuBFqZJ5RwVKEBNs-1nJS1ZPMclIejdU-KhKyh7EN8rcd3xgZgfHls0EAQbo-BxByVmc8Y37bK7I-MrybwuUGorESy6I8efVCWVAEBpQrggxNmj6MEFRhfeEDv0QQltD6BAC-MCieoGqyeIFhoxROC7x1CaESAEA06okPD-CKAMMkoUqdVPogn9CCMvKQWI3Hb66A6TSp2Cj3YmijA9SaoFs9OqrUV0T7hbG8kGY6T_QQEVLZtrRkFkWHBgrZCQmlDAxLLfh-lO9Qo_EeClAk2vvCiRRBSOvQefCcqJG-yfMPye0hfnww4lH2FEgK61g-b3ogD7a-3vasQaqUHPyXj4fHx9x9A4wE1aGufPGj1RBTKk1V1Tz5vlVGt-g9KxlcUgFEcm-fDJ_3kBVQiQItBSBHEROvhRfEAP1jZa_y0AVZsgPHFSLSzXZiUFeOLRJuU3JGShgxO5HwkZ5wnuhRgQM-0OFmKxUSJWcuK-2PW8UXOivuCxwv9nH77k-7ms3jJ1HhTL2nRlC8zs6Sb-bhmPst-nfLlS_nBxVgZZD8v57v5LDvSvzLSHn22N31W2bo-Lxyus_yL3v3y-XGz23y3vf_t8fOuEUYOrPA5oDNCg9RatZ11ASprfBAmQBfcByx2nVUmoIuspNb4_IoDXF18qaTEWhkEssoHWQmtqwpUwWn1bqP1D0KZ9S-ffw3Chb5jfBk589uc4i7S8dsIPMNzzvgK2OJh8KDtzpEE4DDEJdNBgcXm7RiL14RYbH7NhoRHX3ofwNs2Up79gBGu9tqW5N9ooSQkIihTZYTOLLrPCD2RWpPoAYtq62LCdA4JjaDrXWc9jmnWilOSGRwKQi4QPtLXVmt7JNj8IHNq8YSjEpMqvdvtJFbad1gxvjxbQZ48WEW4c_9OIOWsePgqYl9VkPlGOJSQWUIYEpikSa1fiId3NmBjCfr-tG1aVxN8Rsgyyutw6pAVG1t-IS3OaGHfAA5aKyHLpPKi1JgN4Jh1HntpM4fafmPSyCEraxlNyrJjYzVmwlWNOuCltCwz9sXblx65tEBGCyCrtThYB3vTQ9aCKpbzDjvIHuTJiFZVf0dZYv7Xlc0eJ4xve-8Y35bKQKaj3uP3OYiTEVSmi3tA56yjG9EH24qgqguMsTVciSVlLpVx-EevHHpIlkG0TFAZ93_PY2j-_xz2Ztzfx6YBTaznlAKxpKdSrYamorJtJ9yYHwMW-49Sv3PKhBG5_Zj8jBfKVLqXlM5rH6Syk4YV313qlIoFvMSJtKcf48QZIf4hn1H3r4gTr8oEaIUyjC9p_TcVIBlds1hWf_7qKKoVXbyw27WhysnXwPj8igF8fSVszypRzzLKHP4cht6ZS4A8V5wRKe2LTYmgQiH9cq9ew851IHmb85gs1zmPIX-dMwX32wonmksH53meL-pa1FgvFjnPXz14l-2g7Z9nW-ZyWvIc83dSi6aCh-0GHPpeB6rf-NxhFVCmieHx8fLdMGt47IQTAWPiiU64ALWzbapMogqpz9VaRoKylkDgvHeIYGmmIjqDFXpP84Stz933a2SDLFLbPnR9VOHck1NbQKwVNfDWpyErQZqk4BQ6NLbfN9QRSIt-xM_zTEKc4nhEWFy5QHAbFa-Ev2jy03WrDE1BxPgTHKmfC5bc8XX2Gca6QcVhjiB6cho9wmes-kD6JddGK0psxEFZR-ts6dEdUMJBCZDan1pytvBJMQTr1J7USJIuNPx2Y9McWnxHOuxoE1JDajsatZYXXf0Y3THVV0NcBccWDz_a0FBzsdhQ05k_XwYU3V965htxtCFXxQ1p-hfELev6qrjeeFHjjkoC48vEKF3XEfIWG_oQmPpTy_hy8EYCNf4RdEUV0-dP-uUi0f65ojT6_w8UFeVyKlbL6fJNRavUntOuFdfKFl_DC92_FfxS_EcavIVJnwwQpqiq18KRRAr-g9A9fgWWvTqgj0ljKLOCE8MsbWtQRiqHVTzgcNhaSqkBn0SA3qOE8kTYca07uLJ11zfy9XZeCT0agv7apv6tAHzLq7-j87FXfG9ioK7_kAjT0-9__I2eMr6kuwdl-qC0p36CT2bDbL223cmpfRNrwzq-y_kMtoT3v9o6HAmZt7Y3MmJ6xFBTTcYCpDx0zu6daGk_a1rlh1WseICT7eOM51AqH5wq-4CE6b2RQymJhy5g62HAbRBI1-_RoBMafu5LrSp4VBUajzBYBwVYF-E1kAQHtku6rUCAFjTHD5Rv6dkID6L0VvcB9QmMhaNwTphwmrxuxcdO_LVzqbhO55N8MidNYgcbVKkxHQJG1yvzRFV-jILznt3Iu0KuipW4wbvpIl8t54tFwW-aO4H1YloWK7moihXnktdY3uYLPp_ObldLjjfqjnYnL_JlXkxveTGp5CqfEW2el1Ulb9ksx1YoPdH60E6s29_EenO3nM347EaLErWPZ6acp_Fm_dN2m9pFCm3KHR1PRDm73dy4O2KTlf3es1mulQ_-K-Oggsa7mBrDSWVxDw9jSZSqrtGhqQaHpCNRiCedDrM0klMlT80yyuF84aZ3-u6dQ1sSP3xlnbNfsAqMb6ORnvFttPO_AQAA__8XKALo">