mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 11:16:06 +00:00
COFF: Implement safe ICF on rodata using address-significance tables.
Differential Revision: https://reviews.llvm.org/D51050 llvm-svn: 340555
This commit is contained in:
parent
075412d9cf
commit
ab038025a5
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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).
|
||||
//
|
||||
|
@ -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();
|
||||
|
9
lld/test/COFF/Inputs/icf-safe.s
Normal file
9
lld/test/COFF/Inputs/icf-safe.s
Normal file
@ -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
|
36
lld/test/COFF/icf-safe.s
Normal file
36
lld/test/COFF/icf-safe.s
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user