Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -253,18 +253,22 @@ // Undefined symbol. class Undefined : public SymbolBody { typedef SymbolBody::Kind Kind; - bool CanKeepUndefined; + bool Optional; + // If it was ever seen in live sections. + bool Live = false; protected: Undefined(Kind K, StringRef N, bool IsWeak, uint8_t Visibility, bool IsTls); public: - Undefined(StringRef N, bool IsWeak, uint8_t Visibility, - bool CanKeepUndefined); + Undefined(StringRef N, bool IsWeak, uint8_t Visibility, bool Opt); static bool classof(const SymbolBody *S) { return S->isUndefined(); } - bool canKeepUndefined() const { return CanKeepUndefined; } + bool canKeepUndefined() const { + return Optional || (Config->GcSections && !Live); + } + void setLive() { Live = true; } }; template class UndefinedElf : public Undefined { Index: ELF/Symbols.cpp =================================================================== --- ELF/Symbols.cpp +++ ELF/Symbols.cpp @@ -171,13 +171,12 @@ Undefined::Undefined(SymbolBody::Kind K, StringRef N, bool IsWeak, uint8_t Visibility, bool IsTls) : SymbolBody(K, N, IsWeak, Visibility, IsTls, /*IsFunction*/ false), - CanKeepUndefined(false) {} + Optional(false) {} -Undefined::Undefined(StringRef N, bool IsWeak, uint8_t Visibility, - bool CanKeepUndefined) +Undefined::Undefined(StringRef N, bool IsWeak, uint8_t Visibility, bool Opt) : Undefined(SymbolBody::UndefinedKind, N, IsWeak, Visibility, /*IsTls*/ false) { - this->CanKeepUndefined = CanKeepUndefined; + this->Optional = Opt; } template Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -292,6 +292,17 @@ SymbolBody *Body = File.getSymbolBody(SymIndex); uint32_t Type = RI.getType(Config->Mips64EL); + auto Name = C.getSectionName(); + if (Body && Body->isUndefined()) { + if (auto *U = dyn_cast(Body->repl())) + U->setLive(); + + // Set "used" bit for --as-needed. + if (!Body->isWeak()) + if (auto *S = dyn_cast>(Body->repl())) + S->File->IsUsed = true; + } + // Ignore "hint" relocation because it is for optional code optimization. if (Target->isHintRel(Type)) continue; @@ -299,11 +310,6 @@ if (Target->isGotRelative(Type)) HasGotOffRel = true; - // Set "used" bit for --as-needed. - if (Body && Body->isUndefined() && !Body->isWeak()) - if (auto *S = dyn_cast>(Body->repl())) - S->File->IsUsed = true; - if (Body) Body = Body->repl(); Index: test/ELF/gc-sections-unref-undef.s =================================================================== --- test/ELF/gc-sections-unref-undef.s +++ test/ELF/gc-sections-unref-undef.s @@ -0,0 +1,26 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld %t -o %t.out -e main --gc-sections +# RUN: llvm-readobj %t.out > /dev/null + +## Don't allow undefines if GC is not enabled +# RUN: not ld.lld %t -o %t.out -e main 2>&1 | FileCheck %s +# CHECK: undefined symbol: _UNDEFINED + +.text +.section .text._unreferenced_function,"ax",@progbits +.globl _unreferenced_function +.type _unreferenced_function,@function +_unreferenced_function: + callq _UNDEFINED + +.section .text._function,"ax",@progbits +.globl _function +.type _function,@function +_function: + +.section .text.main,"ax",@progbits +.globl main +.type main,@function +main: + callq _function Index: test/ELF/gc-sections-unref-undef2.s =================================================================== --- test/ELF/gc-sections-unref-undef2.s +++ test/ELF/gc-sections-unref-undef2.s @@ -0,0 +1,26 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: not ld.lld %t -o %t.out -e main --gc-sections 2>&1 | FileCheck %s +# CHECK: undefined symbol: _UNDEFINED + +## This checks that if there are section with unreferenced +## undefined and the section where it is used, then +## we still can see the error. +.text +.section .text._unreferenced_function,"ax",@progbits +.globl _unreferenced_function +.type _unreferenced_function,@function +_unreferenced_function: + callq _UNDEFINED + +.section .text._function,"ax",@progbits +.globl _function +.type _function,@function +_function: + callq _UNDEFINED + +.section .text.main,"ax",@progbits +.globl main +.type main,@function +main: + callq _function