Keep the largest common symbol.
This requires templating some functions over ELFT, but that opens other cleanup
opportunities for future patches.
llvm-svn: 246405
diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp
index d39b6cd..3efdf12 100644
--- a/lld/ELF/SymbolTable.cpp
+++ b/lld/ELF/SymbolTable.cpp
@@ -12,12 +12,12 @@
#include "Symbols.h"
using namespace llvm;
+using namespace llvm::object;
using namespace lld;
using namespace lld::elf2;
SymbolTable::SymbolTable() {
- resolve(new (Alloc) SyntheticUndefined("_start"));
}
void SymbolTable::addFile(std::unique_ptr<InputFile> File) {
@@ -32,11 +32,41 @@
ObjectFileBase &Old = *ObjectFiles[0];
if (!Old.isCompatibleWith(*File))
error(Twine(Old.getName() + " is incompatible with " + File->getName()));
+ } else {
+ auto *Start = new (Alloc) SyntheticUndefined("_start");
+ switch (File->kind()) {
+ case InputFile::Object32LEKind:
+ resolve<ELF32LE>(Start);
+ break;
+ case InputFile::Object32BEKind:
+ resolve<ELF32BE>(Start);
+ break;
+ case InputFile::Object64LEKind:
+ resolve<ELF64LE>(Start);
+ break;
+ case InputFile::Object64BEKind:
+ resolve<ELF64BE>(Start);
+ break;
+ }
}
ObjectFiles.emplace_back(File);
- for (SymbolBody *Body : File->getSymbols())
- resolve(Body);
+ for (SymbolBody *Body : File->getSymbols()) {
+ switch (File->kind()) {
+ case InputFile::Object32LEKind:
+ resolve<ELF32LE>(Body);
+ break;
+ case InputFile::Object32BEKind:
+ resolve<ELF32BE>(Body);
+ break;
+ case InputFile::Object64LEKind:
+ resolve<ELF64LE>(Body);
+ break;
+ case InputFile::Object64BEKind:
+ resolve<ELF64BE>(Body);
+ break;
+ }
+ }
}
void SymbolTable::reportRemainingUndefines() {
@@ -49,7 +79,7 @@
// This function resolves conflicts if there's an existing symbol with
// the same name. Decisions are made based on symbol type.
-void SymbolTable::resolve(SymbolBody *New) {
+template <class ELFT> void SymbolTable::resolve(SymbolBody *New) {
// Find an existing Symbol or create and insert a new one.
StringRef Name = New->getName();
Builder.add(Name);
@@ -64,7 +94,7 @@
// compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
// equivalent (conflicting), or more preferable, respectively.
SymbolBody *Existing = Sym->Body;
- int comp = Existing->compare(New);
+ int comp = Existing->compare<ELFT>(New);
if (comp < 0)
Sym->Body = New;
if (comp == 0)
diff --git a/lld/ELF/SymbolTable.h b/lld/ELF/SymbolTable.h
index f108e65..4e47805 100644
--- a/lld/ELF/SymbolTable.h
+++ b/lld/ELF/SymbolTable.h
@@ -51,7 +51,7 @@
private:
void addObject(ObjectFileBase *File);
- void resolve(SymbolBody *Body);
+ template <class ELFT> void resolve(SymbolBody *Body);
llvm::DenseMap<StringRef, Symbol *> Symtab;
llvm::BumpPtrAllocator Alloc;
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index d12db27..7eb7dda 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -19,25 +19,36 @@
// Returns 1, 0 or -1 if this symbol should take precedence
// over the Other, tie or lose, respectively.
-int SymbolBody::compare(SymbolBody *Other) {
+template <class ELFT> int SymbolBody::compare(SymbolBody *Other) {
std::pair<bool, bool> L(isDefined(), !isWeak());
std::pair<bool, bool> R(Other->isDefined(), !Other->isWeak());
// Normalize
if (L > R)
- return -Other->compare(this);
+ return -Other->compare<ELFT>(this);
if (L != R)
return -1;
if (L.first && L.second) {
- // FIXME: In the case where both are common we need to pick the largest
- // and remember the alignment restriction.
- if (isCommon())
+ if (isCommon()) {
+ if (Other->isCommon()) {
+ // FIXME: We also need to remember the alignment restriction.
+ if (cast<DefinedCommon<ELFT>>(this)->Sym.st_size >=
+ cast<DefinedCommon<ELFT>>(Other)->Sym.st_size)
+ return 1;
+ return -1;
+ }
return -1;
+ }
if (Other->isCommon())
return 1;
return 0;
}
return 1;
}
+
+template int SymbolBody::compare<ELF32LE>(SymbolBody *Other);
+template int SymbolBody::compare<ELF32BE>(SymbolBody *Other);
+template int SymbolBody::compare<ELF64LE>(SymbolBody *Other);
+template int SymbolBody::compare<ELF64BE>(SymbolBody *Other);
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 9360dcb..b944301 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -71,7 +71,7 @@
// Decides which symbol should "win" in the symbol table, this or
// the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if
// they are duplicate (conflicting) symbols.
- int compare(SymbolBody *Other);
+ template <class ELFT> int compare(SymbolBody *Other);
protected:
SymbolBody(Kind K, StringRef Name, bool IsWeak)
diff --git a/lld/test/elf2/Inputs/common.s b/lld/test/elf2/Inputs/common.s
new file mode 100644
index 0000000..fd5a99e
--- /dev/null
+++ b/lld/test/elf2/Inputs/common.s
@@ -0,0 +1,2 @@
+.comm sym1,8,4
+.comm sym2,4,4
diff --git a/lld/test/elf2/common.s b/lld/test/elf2/common.s
new file mode 100644
index 0000000..936a1b9
--- /dev/null
+++ b/lld/test/elf2/common.s
@@ -0,0 +1,28 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/common.s -o %t2
+// RUN: lld -flavor gnu2 %t %t2 -o %t3
+// RUN: llvm-readobj -t %t3 | FileCheck %s
+// REQUIRES: x86
+
+// CHECK: Name: sym2
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined
+
+// CHECK: Name: sym1
+// CHECK-NEXT: Value: 0x0
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Binding: Global
+// CHECK-NEXT: Type: Object
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: Undefined
+
+
+.globl _start
+_start:
+
+.comm sym1,4,4
+.comm sym2,8,4