diff options
-rw-r--r-- | lld/ELF/SymbolTable.cpp | 21 | ||||
-rw-r--r-- | lld/test/ELF/abs-conflict.s | 16 |
2 files changed, 31 insertions, 6 deletions
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index c7fe4ceea68..6734e54a135 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -291,18 +291,24 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) { // We have a new non-common defined symbol with the specified binding. Return 1 // if the new symbol should win, -1 if the new symbol should lose, or 0 if there // is a conflict. If the new symbol wins, also update the binding. -static int compareDefinedNonCommon(Symbol *S, bool WasInserted, - uint8_t Binding) { +template <typename ELFT> +static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding, + bool IsAbsolute, typename ELFT::uint Value) { if (int Cmp = compareDefined(S, WasInserted, Binding)) { if (Cmp > 0) S->Binding = Binding; return Cmp; } - if (isa<DefinedCommon>(S->body())) { + SymbolBody *B = S->body(); + if (isa<DefinedCommon>(B)) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) warn("common " + S->body()->getName() + " is overridden"); return 1; + } else if (auto *R = dyn_cast<DefinedRegular<ELFT>>(B)) { + if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute && + R->Value == Value) + return -1; } return 0; } @@ -377,7 +383,8 @@ Symbol *SymbolTable<ELFT>::addRegular(StringRef Name, uint8_t StOther, bool WasInserted; std::tie(S, WasInserted) = insert(Name, Type, StOther & 3, /*CanOmitFromDynSym*/ false, File); - int Cmp = compareDefinedNonCommon(S, WasInserted, Binding); + int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding, + Section == nullptr, Value); if (Cmp > 0) replaceBody<DefinedRegular<ELFT>>(S, Name, /*IsLocal=*/false, StOther, Type, Value, Size, Section, File); @@ -394,7 +401,8 @@ Symbol *SymbolTable<ELFT>::addSynthetic(StringRef N, bool WasInserted; std::tie(S, WasInserted) = insert(N, STT_NOTYPE, /*Visibility*/ StOther & 0x3, /*CanOmitFromDynSym*/ false, nullptr); - int Cmp = compareDefinedNonCommon(S, WasInserted, STB_GLOBAL); + int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, STB_GLOBAL, + /*IsAbsolute*/ false, /*Value*/ 0); if (Cmp > 0) replaceBody<DefinedSynthetic<ELFT>>(S, N, Value, Section); else if (Cmp == 0) @@ -431,7 +439,8 @@ Symbol *SymbolTable<ELFT>::addBitcode(StringRef Name, uint8_t Binding, bool WasInserted; std::tie(S, WasInserted) = insert(Name, Type, StOther & 3, CanOmitFromDynSym, F); - int Cmp = compareDefinedNonCommon(S, WasInserted, Binding); + int Cmp = compareDefinedNonCommon<ELFT>(S, WasInserted, Binding, + /*IsAbs*/ false, /*Value*/ 0); if (Cmp > 0) replaceBody<DefinedRegular<ELFT>>(S, Name, /*IsLocal=*/false, StOther, Type, 0, 0, nullptr, F); diff --git a/lld/test/ELF/abs-conflict.s b/lld/test/ELF/abs-conflict.s new file mode 100644 index 00000000000..7837a6bae50 --- /dev/null +++ b/lld/test/ELF/abs-conflict.s @@ -0,0 +1,16 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +// RUN: ld.lld %t.o %t.o -o %t.so -shared +// RUN: llvm-readobj --dyn-symbols %t.so | FileCheck %s + +// CHECK: Name: foo +// CHECK-NEXT: Value: 0x123 + +.global foo +foo = 0x123 + +// RUN: echo ".global foo; foo = 0x124" > %t2.s +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t2.s -o %t2.o +// RUN: not ld.lld %t.o %t2.o -o %t.so -shared 2>&1 | FileCheck --check-prefix=DUP %s + +// DUP: duplicate symbol 'foo' |