Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasm-ld crash when LTO enabled: __cxx_global_var_init.1 present in "init functions" but not defined #62243

Closed
sbc100 opened this issue Apr 19, 2023 · 5 comments · Fixed by #73095
Labels
lld:wasm LTO Link time optimization (regular/full LTO or ThinLTO)

Comments

@sbc100
Copy link
Collaborator

sbc100 commented Apr 19, 2023

We've seen certain situations where in LTO builds wasm-ld will crash during Writer::createCallCtorsFunction because one of the init function in the generted LTO object file ( __cxx_global_var_init.1) in undefined and does not get assigned a function index (so crashes in sym->getFunctionIndex()).

I'm still working on reducing the repro case as more.

This seems to have started with https://reviews.llvm.org/D135427, which I guess makes sense since that change explicitly calls out __cxx_global_var_init as being discarded.

@llvmbot
Copy link
Collaborator

llvmbot commented Apr 19, 2023

@llvm/issue-subscribers-backend-webassembly

@EugeneZelenko EugeneZelenko added lld:wasm LTO Link time optimization (regular/full LTO or ThinLTO) and removed lld backend:WebAssembly labels Apr 19, 2023
@llvmbot
Copy link
Collaborator

llvmbot commented Apr 19, 2023

@llvm/issue-subscribers-lld-wasm

@jeremiahar
Copy link

Pasting this here as well for visibility from emscripten-core/emscripten#19774 . A potential repro is this:

CMakeLists.txt:

cmake_minimum_required(VERSION 3.13)

set(CMAKE_EXECUTABLE_SUFFIX_CXX .html)
set(CMAKE_CXX_STANDARD 17)

add_executable(lto_bug dummy.cpp)

add_library(main
  main.cpp
)

add_library(lib1
  lib1.cpp
)

target_link_libraries(lto_bug
  PRIVATE

  main
  lib1
)

main.cpp

int DoIt()
{
    return 0; 
}
inline int Unused0 = DoIt();

int GetUnused();

int main(int, char **)
{
    return GetUnused();
}

lib1.cpp:

int DoIt();
inline int Unused0 = DoIt();

int GetUnused()
{
    return Unused0;
}

dummy.cpp:

// Dummy file for cmake's add_executable

Compilation commands:

[jeremiah@jeremiah build]$ ~/emsdk/upstream/emscripten/emcmake cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-flto" ../
configure: cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=-flto ../ -DCMAKE_TOOLCHAIN_FILE=/home/jeremiah/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_CROSSCOMPILING_EMULATOR=/home/jeremiah/emsdk/node/16.20.0_64bit/bin/node
CMake Warning (dev) in CMakeLists.txt:
  No project() command is present.  The top-level CMakeLists.txt file must
  contain a literal, direct call to the project() command.  Add a line of
  code such as

    project(ProjectName)

  near the top of the file, but after cmake_minimum_required().

  CMake is pretending there is a "project(Project)" command on the first
  line.
This warning is for project developers.  Use -Wno-dev to suppress it.

CMake Warning (dev) in CMakeLists.txt:
  cmake_minimum_required() should be called prior to this top-level project()
  call.  Please see the cmake-commands(7) manual for usage documentation of
  both commands.
This warning is for project developers.  Use -Wno-dev to suppress it.

-- Configuring done (0.5s)
-- Generating done (0.0s)
-- Build files have been written to: /home/jeremiah/projects/emscripten_lto_bug/build
[jeremiah@jeremiah build]$ make -j64 VERBOSE=1
/usr/bin/cmake -S/home/jeremiah/projects/emscripten_lto_bug -B/home/jeremiah/projects/emscripten_lto_bug/build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake -E cmake_progress_start /home/jeremiah/projects/emscripten_lto_bug/build/CMakeFiles /home/jeremiah/projects/emscripten_lto_bug/build//CMakeFiles/progress.marks
make  -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/home/jeremiah/projects/emscripten_lto_bug/build'
make  -f CMakeFiles/lib1.dir/build.make CMakeFiles/lib1.dir/depend
make  -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/depend
make[2]: Entering directory '/home/jeremiah/projects/emscripten_lto_bug/build'
cd /home/jeremiah/projects/emscripten_lto_bug/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/jeremiah/projects/emscripten_lto_bug /home/jeremiah/projects/emscripten_lto_bug /home/jeremiah/projects/emscripten_lto_bug/build /home/jeremiah/projects/emscripten_lto_bug/build /home/jeremiah/projects/emscripten_lto_bug/build/CMakeFiles/lib1.dir/DependInfo.cmake --color=
make[2]: Entering directory '/home/jeremiah/projects/emscripten_lto_bug/build'
cd /home/jeremiah/projects/emscripten_lto_bug/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/jeremiah/projects/emscripten_lto_bug /home/jeremiah/projects/emscripten_lto_bug /home/jeremiah/projects/emscripten_lto_bug/build /home/jeremiah/projects/emscripten_lto_bug/build /home/jeremiah/projects/emscripten_lto_bug/build/CMakeFiles/main.dir/DependInfo.cmake --color=
Dependencies file "CMakeFiles/lib1.dir/lib1.cpp.o.d" is newer than depends file "/home/jeremiah/projects/emscripten_lto_bug/build/CMakeFiles/lib1.dir/compiler_depend.internal".
Consolidate compiler generated dependencies of target lib1
make[2]: Leaving directory '/home/jeremiah/projects/emscripten_lto_bug/build'
make  -f CMakeFiles/lib1.dir/build.make CMakeFiles/lib1.dir/build
Dependencies file "CMakeFiles/main.dir/main.cpp.o.d" is newer than depends file "/home/jeremiah/projects/emscripten_lto_bug/build/CMakeFiles/main.dir/compiler_depend.internal".
Consolidate compiler generated dependencies of target main
make[2]: Leaving directory '/home/jeremiah/projects/emscripten_lto_bug/build'
make  -f CMakeFiles/main.dir/build.make CMakeFiles/main.dir/build
make[2]: Entering directory '/home/jeremiah/projects/emscripten_lto_bug/build'
make[2]: Nothing to be done for 'CMakeFiles/lib1.dir/build'.
make[2]: Leaving directory '/home/jeremiah/projects/emscripten_lto_bug/build'
make[2]: Entering directory '/home/jeremiah/projects/emscripten_lto_bug/build'
make[2]: Nothing to be done for 'CMakeFiles/main.dir/build'.
make[2]: Leaving directory '/home/jeremiah/projects/emscripten_lto_bug/build'
[ 33%] Built target lib1
[ 66%] Built target main
make  -f CMakeFiles/lto_bug.dir/build.make CMakeFiles/lto_bug.dir/depend
make[2]: Entering directory '/home/jeremiah/projects/emscripten_lto_bug/build'
cd /home/jeremiah/projects/emscripten_lto_bug/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /home/jeremiah/projects/emscripten_lto_bug /home/jeremiah/projects/emscripten_lto_bug /home/jeremiah/projects/emscripten_lto_bug/build /home/jeremiah/projects/emscripten_lto_bug/build /home/jeremiah/projects/emscripten_lto_bug/build/CMakeFiles/lto_bug.dir/DependInfo.cmake --color=
Dependencies file "CMakeFiles/lto_bug.dir/dummy.cpp.o.d" is newer than depends file "/home/jeremiah/projects/emscripten_lto_bug/build/CMakeFiles/lto_bug.dir/compiler_depend.internal".
Consolidate compiler generated dependencies of target lto_bug
make[2]: Leaving directory '/home/jeremiah/projects/emscripten_lto_bug/build'
make  -f CMakeFiles/lto_bug.dir/build.make CMakeFiles/lto_bug.dir/build
make[2]: Entering directory '/home/jeremiah/projects/emscripten_lto_bug/build'
[ 83%] Linking CXX executable lto_bug.html
/usr/bin/cmake -E cmake_link_script CMakeFiles/lto_bug.dir/link.txt --verbose=1
/home/jeremiah/emsdk/upstream/emscripten/em++ -flto -O3 -DNDEBUG @CMakeFiles/lto_bug.dir/objects1.rsp -o lto_bug.html @CMakeFiles/lto_bug.dir/linkLibs.rsp
wasm-ld: /b/s/w/ir/cache/builder/emscripten-releases/llvm-project/llvm/include/llvm/Support/Casting.h:578: decltype(auto) llvm::cast(From *) [To = lld::wasm::DefinedFunction, From = const lld::wasm::FunctionSymbol]: Assertion `isa<To>(Val) && "cast<Ty>() argument of incompatible type!"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.      Program arguments: /home/jeremiah/emsdk/upstream/bin/wasm-ld -o lto_bug.wasm CMakeFiles/lto_bug.dir/dummy.cpp.o libmain.a liblib1.a -L/home/jeremiah/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/lto -lGL -lal -lhtml5 -lstubs -lnoexit -lc -ldlmalloc -lcompiler_rt -lc++-noexcept -lc++abi-noexcept -lsockets -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr /tmp/tmp2ow3pfaelibemscripten_js_symbols.so --strip-debug --export-if-defined=main --export-if-defined=__start_em_asm --export-if-defined=__stop_em_asm --export-if-defined=__start_em_lib_deps --export-if-defined=__stop_em_lib_deps --export-if-defined=__start_em_js --export-if-defined=__stop_em_js --export-if-defined=__main_argc_argv --export=stackSave --export=stackRestore --export=stackAlloc --export=__errno_location --export=__get_temp_ret --export=__set_temp_ret --export=__wasm_call_ctors --export-table -z stack-size=65536 --initial-memory=16777216 --no-entry --max-memory=16777216 --global-base=1024
 #0 0x00007f58210121e8 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/home/jeremiah/emsdk/upstream/bin/../lib/libLLVM-17git.so+0x1c121e8)
 #1 0x00007f582100feae llvm::sys::RunSignalHandlers() (/home/jeremiah/emsdk/upstream/bin/../lib/libLLVM-17git.so+0x1c0feae)
 #2 0x00007f58210128c5 SignalHandler(int) Signals.cpp:0:0
 #3 0x00007f581f00cab0 (/usr/lib/libc.so.6+0x39ab0)
 #4 0x00007f581f05c26c (/usr/lib/libc.so.6+0x8926c)
 #5 0x00007f581f00ca08 raise (/usr/lib/libc.so.6+0x39a08)
 #6 0x00007f581eff5538 abort (/usr/lib/libc.so.6+0x22538)
 #7 0x00007f581eff545c (/usr/lib/libc.so.6+0x2245c)
 #8 0x00007f581f0053d6 (/usr/lib/libc.so.6+0x323d6)
 #9 0x0000561afea34177 (/home/jeremiah/emsdk/upstream/bin/wasm-ld+0x4f8177)
#10 0x0000561afea3d957 lld::wasm::(anonymous namespace)::Writer::run() Writer.cpp:0:0
#11 0x0000561afea35846 lld::wasm::writeResult() (/home/jeremiah/emsdk/upstream/bin/wasm-ld+0x4f9846)
#12 0x0000561afea0e185 lld::wasm::(anonymous namespace)::LinkerDriver::linkerMain(llvm::ArrayRef<char const*>) Driver.cpp:0:0
#13 0x0000561afea0b10a lld::wasm::link(llvm::ArrayRef<char const*>, llvm::raw_ostream&, llvm::raw_ostream&, bool, bool) (/home/jeremiah/emsdk/upstream/bin/wasm-ld+0x4cf10a)
#14 0x0000561afe6e7552 lld::unsafeLldMain(llvm::ArrayRef<char const*>, llvm::raw_ostream&, llvm::raw_ostream&, llvm::ArrayRef<lld::DriverDef>, bool) (/home/jeremiah/emsdk/upstream/bin/wasm-ld+0x1ab552)
#15 0x0000561afe6e6699 lld_main(int, char**, llvm::ToolContext const&) (/home/jeremiah/emsdk/upstream/bin/wasm-ld+0x1aa699)
#16 0x0000561afe6e6b71 main (/home/jeremiah/emsdk/upstream/bin/wasm-ld+0x1aab71)
#17 0x00007f581eff6850 (/usr/lib/libc.so.6+0x23850)
#18 0x00007f581eff690a __libc_start_main (/usr/lib/libc.so.6+0x2390a)
#19 0x0000561afe6e624a _start (/home/jeremiah/emsdk/upstream/bin/wasm-ld+0x1aa24a)
em++: error: '/home/jeremiah/emsdk/upstream/bin/wasm-ld -o lto_bug.wasm CMakeFiles/lto_bug.dir/dummy.cpp.o libmain.a liblib1.a -L/home/jeremiah/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/lto -lGL -lal -lhtml5 -lstubs -lnoexit -lc -ldlmalloc -lcompiler_rt -lc++-noexcept -lc++abi-noexcept -lsockets -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr /tmp/tmp2ow3pfaelibemscripten_js_symbols.so --strip-debug --export-if-defined=main --export-if-defined=__start_em_asm --export-if-defined=__stop_em_asm --export-if-defined=__start_em_lib_deps --export-if-defined=__stop_em_lib_deps --export-if-defined=__start_em_js --export-if-defined=__stop_em_js --export-if-defined=__main_argc_argv --export=stackSave --export=stackRestore --export=stackAlloc --export=__errno_location --export=__get_temp_ret --export=__set_temp_ret --export=__wasm_call_ctors --export-table -z stack-size=65536 --initial-memory=16777216 --no-entry --max-memory=16777216 --global-base=1024' failed (received SIGABRT (-6))
make[2]: *** [CMakeFiles/lto_bug.dir/build.make:101: lto_bug.html] Error 1
make[2]: Leaving directory '/home/jeremiah/projects/emscripten_lto_bug/build'
make[1]: *** [CMakeFiles/Makefile2:88: CMakeFiles/lto_bug.dir/all] Error 2
make[1]: Leaving directory '/home/jeremiah/projects/emscripten_lto_bug/build'
make: *** [Makefile:91: all] Error 2
[jeremiah@jeremiah build]$ 

@Mintyboi
Copy link

Mintyboi commented Aug 5, 2023

hi @EugeneZelenko, it's great that there is now a simple reproducer for this issue!
Do you think this issue can be relooked into and see if we can find a way to resolve this? 🙏

cc @MaskRay

@kleisauke
Copy link

Here's another reproducer:

cat <<EOT > foo.h
int foo();
inline int unused = foo(); // FIXME: Remove to fix the build
EOT
cat <<EOT > foo.cc
#include "foo.h"

int foo() {
  return 42;
}
EOT
cat <<EOT > main.cc
#include "foo.h"

int main() {
  return foo();
}
EOT
em++ -c -flto foo.cc -o foo.o
em++ -c -flto main.cc -o main.o
emar rcsT libfoo.a foo.o
emar rcsT libmain.a main.o
em++ libmain.a libfoo.a

aheejin added a commit to aheejin/llvm-project that referenced this issue Nov 22, 2023
tl;dr:
When doing LTO on multiple archives, the order with which bitcodes are
linked to the LTO module is hard to control, given that processing
undefined symbols can lead to parsing of an object file, which in turn
lead to parsing of another object file before finishing parsing of the
previous file. This can result in encountering a non-prevailing comdat
first when linking, which can make the the symbol undefined, and the
real definition is added later with an additional prefix to avoid
duplication (e.g. `__cxx_global_var_init` and `__cxx_global_var_init.2`)

So this one-line fix ensures we compile bitcodes in the order that we
process comdats, so that when multiple archived bitcode files have the
same variable with the same comdat, we make sure that the prevailing
comdat will be linked first in the LTO.

Fixes llvm#62243.

---

- Long version, feel free to skip:

When linking (non-archived) bitcode files directly in LTO, we add files
in `bitcodeFiles` vector in the order they are given in the command
line:
https://github.com/llvm/llvm-project/blob/fb57f4e0e0b302ec1b3181e952a4bd4b3c57a286/lld/wasm/Driver.cpp#L1201-L1204 ->
https://github.com/llvm/llvm-project/blob/fb57f4e0e0b302ec1b3181e952a4bd4b3c57a286/lld/wasm/SymbolTable.cpp#L54

The order they are added in `bitcodeFiles` is the order they are
compiled and linked into the LTO module later.

While parsing these bitcode files, we also add symbols to the symbol
table. Depending on their status, they are added as defined symbols or
undefined symbols.

---

On the other hand, when linking archives that contain bitcode files, the
order bitcode files are added to `bitcodeFiles` vector is hard to
predict.

When parsing archives, firstly, symbols are parsed as lazy symbols:
https://github.com/llvm/llvm-project/blob/fb57f4e0e0b302ec1b3181e952a4bd4b3c57a286/lld/wasm/InputFiles.cpp#L734-L739

And then we handle undefined symbols here:
https://github.com/llvm/llvm-project/blob/fb57f4e0e0b302ec1b3181e952a4bd4b3c57a286/lld/wasm/Driver.cpp#L1208-L1210
where we try to fetch lazy symbols' original objects:
https://github.com/llvm/llvm-project/blob/fb57f4e0e0b302ec1b3181e952a4bd4b3c57a286/lld/wasm/Driver.cpp#L708 ->
https://github.com/llvm/llvm-project/blob/907ed77ad1d7a154317e5f8398d17d441711dc38/lld/wasm/Symbols.cpp#L428
which causes the corresponding object file to be added to the symbol
table:
https://github.com/llvm/llvm-project/blob/fb57f4e0e0b302ec1b3181e952a4bd4b3c57a286/lld/wasm/InputFiles.cpp#L763
and the object file is parsed:
https://github.com/llvm/llvm-project/blob/fb57f4e0e0b302ec1b3181e952a4bd4b3c57a286/lld/wasm/SymbolTable.cpp#L53

But this `parse` call can lead to the parsing of other files before it
is added to `bitcodeFiles` in the next line. For example, we have two
bitcode files `a.o` and `b.o`, each of which is archived as `liba.a` and
`libb.a`. Both files have a variable with the same name and the same
comdat. When handling undefined symbols, suppose we start from a symbol
from `a.o`. We arrive here and all comdats in `a.o` are added to
`keptComdats`:
https://github.com/llvm/llvm-project/blob/fb57f4e0e0b302ec1b3181e952a4bd4b3c57a286/lld/wasm/InputFiles.cpp#L844-L845
And we call `createBitCodeSymbol` on all symbols in `a.o`:
https://github.com/llvm/llvm-project/blob/fb57f4e0e0b302ec1b3181e952a4bd4b3c57a286/lld/wasm/InputFiles.cpp#L847-L848
But this can cause the loading of another object in case some of those
symbols are undefined functions or data, like here:
https://github.com/llvm/llvm-project/blob/fb57f4e0e0b302ec1b3181e952a4bd4b3c57a286/lld/wasm/InputFiles.cpp#L791-L792
->
https://github.com/llvm/llvm-project/blob/fb57f4e0e0b302ec1b3181e952a4bd4b3c57a286/lld/wasm/SymbolTable.cpp#L534

So effectively, in the middle of parsing `a.o`, we proceed to parse
`b.o`. And when parsing `b.o`, we encounter the comdat variable. But
because we already added that comdat in `keptComdats` when parsing
`a.o`, so `b.o`'s comdat variable ends up being excluded, so it is added
as an undefined data, whereas `a.o`'s comdat variable will be added as a
defined data:
https://github.com/llvm/llvm-project/blob/fb57f4e0e0b302ec1b3181e952a4bd4b3c57a286/lld/wasm/InputFiles.cpp#L786-L798

For a lazy symbol, `addUndefinedData` does not replace the symbol unless
it is the first time being inserted, but `addDefinedData` does:
https://github.com/llvm/llvm-project/blob/fb57f4e0e0b302ec1b3181e952a4bd4b3c57a286/lld/wasm/SymbolTable.cpp#L382-L385
And because of this `a.o`'s comdat is to be the prevailing one, because
the symbol's `getFile()` will return `a.o`:
https://github.com/llvm/llvm-project/blob/907ed77ad1d7a154317e5f8398d17d441711dc38/lld/wasm/LTO.cpp#L104
But because `b.o`'s parsing started in the middle of `a.o`s parsing, it
ends first and gets added to `bitcodeFiles` first.
https://github.com/llvm/llvm-project/blob/fb57f4e0e0b302ec1b3181e952a4bd4b3c57a286/lld/wasm/SymbolTable.cpp#L54

So to sum up, `bitcodeFiles` now contains [`b.o`, `a.o`] but `a.o` has
the prevailing comdat. This does not happen when directly linking
bitcodes (without archives) because symbols are added in one-pass in the
order specified in the command line. This also does not happen in
non-LTO (even with archives), because object parsing uses
`ObjFile::parse` which is a separate process from this bitcode
processing.

---

I'm not sure if there is a rule that the prevailing comdat has to exist
in the first file having that comdat within `bitcodeFiles`, but my
observation says this is likely the case.

When adding bitcodes to the LTO, if a symbol's comdat is not a
prevailing one, this code demotes its linkage to `available_externally`:
https://github.com/llvm/llvm-project/blob/23c84fb362849865990c0e160158b19f54742147/llvm/lib/LTO/LTO.cpp#L869-L895
and subsequently all other variables that are associated with the same
comdat in that object file are demoted in the same way.
https://github.com/llvm/llvm-project/blob/23c84fb362849865990c0e160158b19f54742147/llvm/lib/LTO/LTO.cpp#L788-L792
In out case, because of the orders of `bitcodeFiles`, we start from
`b.o`, and the comdat symbols there become `available_externally`. This
is how `__cxx_global_var_init` in `global_var_init2.ll` in the attached
test becomes `available_externally`.

When linking those bitcodes in the LTO, if we traverse symbols in
the order of prevailing->non-prevailing, we end up keeping only one
global variable, but if we traverse in the other way around (i.e.,
non-prevailing first), we end up adding two symbols, because it lets us
add a `available_externally` symbol when we don't already have a
definition for it:
https://github.com/llvm/llvm-project/blob/23c84fb362849865990c0e160158b19f54742147/llvm/lib/LTO/LTO.cpp#L974-L986
Also when it is an `available_externally` symbol, it becomes a
declaration, not a definition. So we end up with a module like this:
```ll
declare dso_local void @__cxx_global_var_init()
define internal void @__cxx_global_var_init.2() comdat($unused) {
  ...
}
```

---

So this one-line fix ensures we compile bitcodes in the order that we
process comdats, so that when multiple archived bitcode files have the
same variable with the same comdat, we make sure that the prevailing
comdat will be linked first in the LTO.

---

This crash is said to be happening after llvm@12050a3
but even reverting this is not really a solution for us because we end
up with two definitions if we do that:
```ll
define internal void @__cxx_global_var_init() comdat($unused) {
  ...
}
define internal void @__cxx_global_var_init.2() comdat($unused) {
  ...
}
```
And the wasm's `__wasm_call_ctors` will be like
```wast
 (func $__wasm_call_ctors
  (call $emscripten_stack_init)
  (call $__cxx_global_var_init)
  (call $__cxx_global_var_init.2)
 )
```
aheejin added a commit that referenced this issue Nov 29, 2023
When doing LTO on multiple archives, the order with which bitcodes are
linked to the LTO module is hard to control, given that processing
undefined symbols can lead to parsing of an object file, which in turn
lead to parsing of another object file before finishing parsing of the
previous file. This can result in encountering a non-prevailing comdat
first when linking, which can make the the symbol undefined, and the
real definition is added later with an additional prefix to avoid
duplication (e.g. `__cxx_global_var_init` and `__cxx_global_var_init.2`)

So this one-line fix ensures we compile bitcodes in the order that we
process comdats, so that when multiple archived bitcode files have the
same variable with the same comdat, we make sure that the prevailing
comdat will be linked first in the LTO.

Fixes #62243.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
lld:wasm LTO Link time optimization (regular/full LTO or ThinLTO)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants