summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/COFF/Chunks.h4
-rw-r--r--lld/COFF/Driver.cpp45
-rw-r--r--lld/COFF/ICF.cpp6
-rw-r--r--lld/COFF/InputFiles.cpp5
-rw-r--r--lld/COFF/InputFiles.h2
-rw-r--r--lld/test/COFF/Inputs/icf-safe.s9
-rw-r--r--lld/test/COFF/icf-safe.s36
7 files changed, 105 insertions, 2 deletions
diff --git a/lld/COFF/Chunks.h b/lld/COFF/Chunks.h
index 9e896531bd9..1a68c86e9c9 100644
--- a/lld/COFF/Chunks.h
+++ b/lld/COFF/Chunks.h
@@ -114,6 +114,10 @@ protected:
public:
// The offset from beginning of the output section. The writer sets a value.
uint64_t OutputSectionOff = 0;
+
+ // Whether this section needs to be kept distinct from other sections during
+ // ICF. This is set by the driver using address-significance tables.
+ bool KeepUnique = false;
};
// A chunk corresponding a section of an input file.
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 4462e6e6c78..e8837924b4d 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -32,6 +32,7 @@
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/Debug.h"
+#include "llvm/Support/LEB128.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/TarWriter.h"
@@ -741,6 +742,46 @@ static void parseOrderFile(StringRef Arg) {
}
}
+static void markAddrsig(Symbol *S) {
+ if (auto *D = dyn_cast_or_null<Defined>(S))
+ if (Chunk *C = D->getChunk())
+ C->KeepUnique = true;
+}
+
+static void findKeepUniqueSections() {
+ // Exported symbols could be address-significant in other executables or DSOs,
+ // so we conservatively mark them as address-significant.
+ for (Export &R : Config->Exports)
+ markAddrsig(R.Sym);
+
+ // Visit the address-significance table in each object file and mark each
+ // referenced symbol as address-significant.
+ for (ObjFile *Obj : ObjFile::Instances) {
+ ArrayRef<Symbol *> Syms = Obj->getSymbols();
+ if (Obj->AddrsigSec) {
+ ArrayRef<uint8_t> Contents;
+ Obj->getCOFFObj()->getSectionContents(Obj->AddrsigSec, Contents);
+ const uint8_t *Cur = Contents.begin();
+ while (Cur != Contents.end()) {
+ unsigned Size;
+ const char *Err;
+ uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err);
+ if (Err)
+ fatal(toString(Obj) + ": could not decode addrsig section: " + Err);
+ if (SymIndex >= Syms.size())
+ fatal(toString(Obj) + ": invalid symbol index in addrsig section");
+ markAddrsig(Syms[SymIndex]);
+ Cur += Size;
+ }
+ } else {
+ // If an object file does not have an address-significance table,
+ // conservatively mark all of its symbols as address-significant.
+ for (Symbol *S : Syms)
+ markAddrsig(S);
+ }
+ }
+}
+
void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
// If the first command line argument is "/lib", link.exe acts like lib.exe.
// We call our own implementation of lib.exe that understands bitcode files.
@@ -1452,8 +1493,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
markLive(Symtab->getChunks());
// Identify identical COMDAT sections to merge them.
- if (Config->DoICF)
+ if (Config->DoICF) {
+ findKeepUniqueSections();
doICF(Symtab->getChunks());
+ }
// Write the result.
writeResult();
diff --git a/lld/COFF/ICF.cpp b/lld/COFF/ICF.cpp
index 7feb3c4e0b0..943f6ede3db 100644
--- a/lld/COFF/ICF.cpp
+++ b/lld/COFF/ICF.cpp
@@ -93,7 +93,11 @@ bool ICF::isEligible(SectionChunk *C) {
return true;
// So are vtables.
- return C->Sym && C->Sym->getName().startswith("??_7");
+ if (C->Sym && C->Sym->getName().startswith("??_7"))
+ return true;
+
+ // Anything else not in an address-significance table is eligible.
+ return !C->KeepUnique;
}
// Split an equivalence class into smaller classes.
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index 289cdb1f6cd..3dd522b6b3e 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -161,6 +161,11 @@ SectionChunk *ObjFile::readSection(uint32_t SectionNumber,
return nullptr;
}
+ if (Name == ".llvm_addrsig") {
+ AddrsigSec = Sec;
+ return nullptr;
+ }
+
// Object files may have DWARF debug info or MS CodeView debug info
// (or both).
//
diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h
index 2bfb9e4b002..2b045358fca 100644
--- a/lld/COFF/InputFiles.h
+++ b/lld/COFF/InputFiles.h
@@ -145,6 +145,8 @@ public:
// if we are not producing a PDB.
llvm::pdb::DbiModuleDescriptorBuilder *ModuleDBI = nullptr;
+ const coff_section *AddrsigSec = nullptr;
+
private:
void initializeChunks();
void initializeSymbols();
diff --git a/lld/test/COFF/Inputs/icf-safe.s b/lld/test/COFF/Inputs/icf-safe.s
new file mode 100644
index 00000000000..3a2b3b18e7a
--- /dev/null
+++ b/lld/test/COFF/Inputs/icf-safe.s
@@ -0,0 +1,9 @@
+.section .rdata,"dr",one_only,non_addrsig1
+.globl non_addrsig1
+non_addrsig1:
+.byte 3
+
+.section .rdata,"dr",one_only,non_addrsig2
+.globl non_addrsig2
+non_addrsig2:
+.byte 3
diff --git a/lld/test/COFF/icf-safe.s b/lld/test/COFF/icf-safe.s
new file mode 100644
index 00000000000..99eb051c1db
--- /dev/null
+++ b/lld/test/COFF/icf-safe.s
@@ -0,0 +1,36 @@
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-win32 %s -o %t1.obj
+# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-win32 %S/Inputs/icf-safe.s -o %t2.obj
+# RUN: lld-link /dll /noentry /out:%t.dll /verbose /opt:noref,icf %t1.obj %t2.obj 2>&1 | FileCheck %s
+# RUN: lld-link /dll /noentry /out:%t.dll /verbose /opt:noref,icf /export:g3 /export:g4 %t1.obj %t2.obj 2>&1 | FileCheck --check-prefix=EXPORT %s
+
+# CHECK-NOT: Selected
+# CHECK: Selected g3
+# CHECK-NEXT: Removed g4
+# CHECK-NOT: Removed
+# CHECK-NOT: Selected
+
+# EXPORT-NOT: Selected
+
+.section .rdata,"dr",one_only,g1
+.globl g1
+g1:
+.byte 1
+
+.section .rdata,"dr",one_only,g2
+.globl g2
+g2:
+.byte 1
+
+.section .rdata,"dr",one_only,g3
+.globl g3
+g3:
+.byte 2
+
+.section .rdata,"dr",one_only,g4
+.globl g4
+g4:
+.byte 2
+
+.addrsig
+.addrsig_sym g1
+.addrsig_sym g2
OpenPOWER on IntegriCloud