diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1138,6 +1138,7 @@ } // Symbol resolution of non-local symbols. + SmallVector unds; for (size_t i = firstGlobal, end = eSyms.size(); i != end; ++i) { const Elf_Sym &eSym = eSyms[i]; uint8_t binding = eSym.getBinding(); @@ -1154,8 +1155,7 @@ // Handle global undefined symbols. if (eSym.st_shndx == SHN_UNDEF) { - this->symbols[i]->resolve(Undefined{this, name, binding, stOther, type}); - this->symbols[i]->referenced = true; + unds.push_back(i); continue; } @@ -1202,6 +1202,20 @@ fatal(toString(this) + ": unexpected binding: " + Twine((int)binding)); } + + // Undefined symbols (excluding those defined relative to non-prevailing + // sections) can trigger recursive fetch. Process defined symbols first so + // that the relative order between a defined symbol and an undefined symbol + // does not change the symbol resolution behavior. In addition, a set of + // interconnected symbols will all be resolved to the same file, instead of + // being resolved to different files. + for (unsigned i : unds) { + const Elf_Sym &eSym = eSyms[i]; + StringRefZ name = this->stringTable.data() + eSym.st_name; + this->symbols[i]->resolve(Undefined{this, name, eSym.getBinding(), + eSym.st_other, eSym.getType()}); + this->symbols[i]->referenced = true; + } } ArchiveFile::ArchiveFile(std::unique_ptr &&file) diff --git a/lld/test/ELF/interconnected-lazy.s b/lld/test/ELF/interconnected-lazy.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/interconnected-lazy.s @@ -0,0 +1,42 @@ +# REQUIRES: x86 + +# RUN: split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/main.s -o %t/main.o +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/a.s -o %t/a.o +# RUN: llvm-mc -filetype=obj -triple=x86_64 %t/b.s -o %t/b.o + +## foo and __foo are interconnected and defined in two lazy object files. +## Test we resolve both to the same file. +# RUN: ld.lld -y a -y foo -y __foo %t/main.o --start-lib %t/a.o %t/b.o --end-lib -o /dev/null | FileCheck %s + +# CHECK: a.o: lazy definition of __foo +# CHECK-NEXT: a.o: lazy definition of a +# CHECK-NEXT: a.o: lazy definition of foo +# CHECK-NEXT: b.o: definition of __foo +# CHECK-NEXT: b.o: definition of foo +# CHECK-NEXT: b.o: reference to a +# CHECK-NEXT: a.o: definition of a + +#--- main.s +.globl _start +_start: + call b + +#--- a.s +.globl a +.weak foo +a: +foo: + +.weak __foo +__foo: + +#--- b.s +.globl b +.weak foo +b: + call a +foo: + +.weak __foo +__foo: