Skip to content

Commit bbf015f

Browse files
author
Alexander Yermolovich
committed
changed to using BinarySections, cleaned up code that is no longer necessary, etc
1 parent 417196c commit bbf015f

File tree

10 files changed

+129
-166
lines changed

10 files changed

+129
-166
lines changed

bolt/include/bolt/Core/BinarySection.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,8 @@ class BinarySection {
340340
/// Does this section have any non-pending relocations?
341341
bool hasRelocations() const { return !Relocations.empty(); }
342342

343+
bool hasDynamicRelocations() const { return !DynamicRelocations.empty(); }
344+
343345
/// Does this section have any pending relocations?
344346
bool hasPendingRelocations() const { return !PendingRelocations.empty(); }
345347

bolt/include/bolt/Core/Relocation.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -180,11 +180,6 @@ inline raw_ostream &operator<<(raw_ostream &OS, const Relocation &Rel) {
180180
return OS;
181181
}
182182

183-
uint32_t getRelocationSymbol(const object::ELFObjectFileBase *Obj,
184-
const object::RelocationRef &Rel);
185-
186-
int64_t getRelocationAddend(const object::ELFObjectFileBase *Obj,
187-
const object::RelocationRef &Rel);
188183
} // namespace bolt
189184
} // namespace llvm
190185

bolt/include/bolt/Passes/IdenticalCodeFolding.h

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,30 +39,35 @@ class IdenticalCodeFolding : public BinaryFunctionPass {
3939
All, // Aggressive ICF for code.
4040
};
4141
explicit IdenticalCodeFolding(const cl::opt<bool> &PrintPass)
42-
: BinaryFunctionPass(PrintPass) {
43-
VtableBitVector.resize((((uint64_t)1) << 32) / 8);
44-
}
42+
: BinaryFunctionPass(PrintPass) {}
4543

4644
const char *getName() const override { return "identical-code-folding"; }
4745
Error runOnFunctions(BinaryContext &BC) override;
4846

4947
private:
5048
/// Bit vector of memory addresses of vtables.
5149
llvm::BitVector VtableBitVector;
52-
bool isInVTable(uint64_t Address) const {
50+
/// Returns true if the memory address is in the bit vector of vtables.
51+
bool isAddressInVTable(uint64_t Address) const {
5352
return VtableBitVector.test(Address / 8);
5453
}
54+
/// Initialize bit vector of memory addresses of vtables.
55+
void initVtable() {VtableBitVector.resize((((uint64_t)1) << 32) / 8);}
56+
/// Mark memory address of vtable as used.
57+
void setAddressUsedInVTable(uint64_t Address) { VtableBitVector.set(Address / 8); }
5558
/// Scans symbol table and creates a bit vector of memory addresses of
5659
/// vtables.
57-
void processSymbolTable(const BinaryContext &BC);
60+
void initVTableReferences(const BinaryContext &BC);
5861
/// Analyze .text section and relocations and mark functions that are not
5962
/// safe to fold.
60-
Error markFunctionsUnsafeToFold(BinaryContext &BC);
61-
/// Process relocations in the .data section to identify function
62-
/// references.
63-
Error processDataRelocations(BinaryContext &BC,
64-
const SectionRef &SecRefRelData,
65-
const bool HasAddressTaken);
63+
void markFunctionsUnsafeToFold(BinaryContext &BC);
64+
/// Process static and dynamic relocations in the data sections to identify
65+
/// function references, and marks them as unsafe to fold. It filters out
66+
/// symbol references that are in vtables.
67+
void analyzeDataRelocations(BinaryContext &BC);
68+
/// Process functions that have CFG created and mark functions unsafe to fold
69+
/// that are used in non-control flow instructions.
70+
void analyzeFunctions(BinaryContext &BC);
6671
};
6772

6873
} // namespace bolt

bolt/lib/Core/Relocation.cpp

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,65 +1115,3 @@ void Relocation::print(raw_ostream &OS) const {
11151115
OS << ", 0x" << Twine::utohexstr(Addend);
11161116
OS << ", 0x" << Twine::utohexstr(Value);
11171117
}
1118-
1119-
namespace {
1120-
template <typename ELFT>
1121-
int64_t getRelocationAddend(const llvm::object::ELFObjectFile<ELFT> *Obj,
1122-
const llvm::object::RelocationRef &RelRef) {
1123-
using ELFShdrTy = typename ELFT::Shdr;
1124-
using Elf_Rela = typename ELFT::Rela;
1125-
int64_t Addend = 0;
1126-
const llvm::object::ELFFile<ELFT> &EF = Obj->getELFFile();
1127-
llvm::object::DataRefImpl Rel = RelRef.getRawDataRefImpl();
1128-
const ELFShdrTy *RelocationSection = cantFail(EF.getSection(Rel.d.a));
1129-
switch (RelocationSection->sh_type) {
1130-
default:
1131-
llvm_unreachable("unexpected relocation section type");
1132-
case ELF::SHT_REL:
1133-
break;
1134-
case ELF::SHT_RELA: {
1135-
const Elf_Rela *RelA = Obj->getRela(Rel);
1136-
Addend = RelA->r_addend;
1137-
break;
1138-
}
1139-
}
1140-
1141-
return Addend;
1142-
}
1143-
1144-
template <typename ELFT>
1145-
uint32_t getRelocationSymbol(const llvm::object::ELFObjectFile<ELFT> *Obj,
1146-
const llvm::object::RelocationRef &RelRef) {
1147-
using ELFShdrTy = typename ELFT::Shdr;
1148-
uint32_t Symbol = 0;
1149-
const llvm::object::ELFFile<ELFT> &EF = Obj->getELFFile();
1150-
llvm::object::DataRefImpl Rel = RelRef.getRawDataRefImpl();
1151-
const ELFShdrTy *RelocationSection = cantFail(EF.getSection(Rel.d.a));
1152-
switch (RelocationSection->sh_type) {
1153-
default:
1154-
llvm_unreachable("unexpected relocation section type");
1155-
case ELF::SHT_REL:
1156-
Symbol = Obj->getRel(Rel)->getSymbol(EF.isMips64EL());
1157-
break;
1158-
case ELF::SHT_RELA:
1159-
Symbol = Obj->getRela(Rel)->getSymbol(EF.isMips64EL());
1160-
break;
1161-
}
1162-
1163-
return Symbol;
1164-
}
1165-
} // namespace
1166-
1167-
namespace llvm {
1168-
namespace bolt {
1169-
uint32_t getRelocationSymbol(const llvm::object::ELFObjectFileBase *Obj,
1170-
const llvm::object::RelocationRef &Rel) {
1171-
return ::getRelocationSymbol(cast<llvm::object::ELF64LEObjectFile>(Obj), Rel);
1172-
}
1173-
1174-
int64_t getRelocationAddend(const llvm::object::ELFObjectFileBase *Obj,
1175-
const llvm::object::RelocationRef &Rel) {
1176-
return ::getRelocationAddend(cast<llvm::object::ELF64LEObjectFile>(Obj), Rel);
1177-
}
1178-
} // namespace bolt
1179-
} // namespace llvm

bolt/lib/Passes/IdenticalCodeFolding.cpp

Lines changed: 46 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include "bolt/Core/HashUtilities.h"
1515
#include "bolt/Core/ParallelUtilities.h"
1616
#include "llvm/ADT/BitVector.h"
17+
#include "llvm/ADT/DenseSet.h"
18+
#include "llvm/ADT/DenseMap.h"
1719
#include "llvm/ADT/SmallVector.h"
1820
#include "llvm/Support/CommandLine.h"
1921
#include "llvm/Support/ThreadPool.h"
@@ -354,94 +356,51 @@ typedef std::unordered_map<BinaryFunction *, std::vector<BinaryFunction *>,
354356

355357
namespace llvm {
356358
namespace bolt {
357-
/// Scans symbol table and creates a bit vector of memory addresses of vtables.
358-
void IdenticalCodeFolding::processSymbolTable(const BinaryContext &BC) {
359-
for (auto &[Address, Data] : BC.getBinaryData()) {
359+
/// Scans symbol table and creates a bit vector of memory addresses of vtable symbols.
360+
void IdenticalCodeFolding::initVTableReferences(const BinaryContext &BC) {
361+
initVtable();
362+
for (const auto &[Address, Data] : BC.getBinaryData()) {
360363
// Filter out all symbols that are not vtables.
361364
if (!Data->getName().starts_with("_ZTV"))
362365
continue;
363-
for (uint64_t I = Address / 8, End = I + (Data->getSize() / 8); I < End;
364-
++I)
365-
VtableBitVector.set(I);
366+
for (uint64_t I = Address, End = I + Data->getSize(); I < End; I += 8)
367+
setAddressUsedInVTable(I);
366368
}
367369
}
368-
Error IdenticalCodeFolding::processDataRelocations(
369-
BinaryContext &BC, const SectionRef &SecRefRelData,
370-
const bool HasAddressTaken) {
371-
for (const RelocationRef &Rel : SecRefRelData.relocations()) {
372-
if (isInVTable(Rel.getOffset()))
370+
void IdenticalCodeFolding::analyzeDataRelocations(BinaryContext &BC) {
371+
initVTableReferences(BC);
372+
for (const BinarySection &Sec : BC.sections()) {
373+
if (!Sec.hasSectionRef() || !Sec.isData())
373374
continue;
374-
symbol_iterator SymbolIter = Rel.getSymbol();
375-
const ObjectFile *OwningObj = Rel.getObject();
376-
assert(SymbolIter != OwningObj->symbol_end() &&
377-
"relocation Symbol expected");
378-
const SymbolRef &Symbol = *SymbolIter;
379-
const uint64_t SymbolAddress = cantFail(Symbol.getAddress());
380-
const ELFObjectFileBase *ELFObj = dyn_cast<ELFObjectFileBase>(OwningObj);
381-
if (!ELFObj)
382-
return createFatalBOLTError(
383-
Twine("BOLT-ERROR: Only ELFObjectFileBase is supported"));
384-
const int64_t Addend = getRelocationAddend(ELFObj, Rel);
385-
BinaryFunction *BF = BC.getBinaryFunctionAtAddress(SymbolAddress + Addend);
386-
if (!BF)
387-
continue;
388-
BF->setHasAddressTaken(HasAddressTaken);
375+
for (const auto &Rel : Sec.relocations()) {
376+
const uint64_t RelAddr = Rel.Offset + Sec.getAddress();
377+
if (isAddressInVTable(RelAddr))
378+
continue;
379+
BinaryFunction *BF = BC.getFunctionForSymbol(Rel.Symbol);
380+
if (!BF)
381+
continue;
382+
BF->setHasAddressTaken(true);
383+
}
384+
for (const auto &Rel : Sec.dynamicRelocations()) {
385+
const uint64_t RelAddr = Rel.Offset + Sec.getAddress();
386+
if (isAddressInVTable(RelAddr))
387+
continue;
388+
BinaryFunction *BF =
389+
BC.getBinaryFunctionContainingAddress(Rel.Addend,
390+
/*CheckPastEnd*/ false,
391+
/*UseMaxSize*/ true);
392+
if (!BF)
393+
continue;
394+
BF->setHasAddressTaken(true);
395+
}
389396
}
390-
return Error::success();
391397
}
392-
393-
Error IdenticalCodeFolding::markFunctionsUnsafeToFold(BinaryContext &BC) {
394-
if (!BC.isX86())
395-
BC.outs() << "BOLT-WARNING: safe ICF is only supported for x86\n";
396-
processSymbolTable(BC);
397-
for (const auto &Sec : BC.sections()) {
398-
if (!Sec.hasSectionRef() || !Sec.isRela())
399-
continue;
400-
const SectionRef &SecRef = Sec.getSectionRef();
401-
section_iterator RelocatedSecIter = cantFail(SecRef.getRelocatedSection());
402-
assert(RelocatedSecIter != SecRef.getObject()->section_end() &&
403-
"Relocation section exists without corresponding relocated section");
404-
const SectionRef &RelocatedSecRef = *RelocatedSecIter;
405-
const StringRef RelocatedSectionName = cantFail(RelocatedSecRef.getName());
406-
const bool SkipRelocs =
407-
StringSwitch<bool>(RelocatedSectionName)
408-
.Cases(".plt", ".got.plt", ".eh_frame", ".gcc_except_table",
409-
".fini_array", ".init_array", true)
410-
.Default(false);
411-
if (!RelocatedSecRef.isData() || SkipRelocs)
412-
continue;
413-
414-
Error ErrorStatus =
415-
processDataRelocations(BC, SecRef, /* HasAddressTaken */ true);
416-
if (ErrorStatus)
417-
return ErrorStatus;
418-
}
419-
ErrorOr<BinarySection &> SecRelDataIA =
420-
BC.getUniqueSectionByName(".rela.init_array");
421-
if (SecRelDataIA) {
422-
const SectionRef SecRefRelData = SecRelDataIA->getSectionRef();
423-
Error ErrorStatus =
424-
processDataRelocations(BC, SecRefRelData, /* !HasAddressTaken */ false);
425-
if (ErrorStatus)
426-
return ErrorStatus;
427-
}
428-
ErrorOr<BinarySection &> SecRelDataFIA =
429-
BC.getUniqueSectionByName(".rela.fini_array");
430-
if (SecRelDataFIA) {
431-
const SectionRef SecRefRelData = SecRelDataFIA->getSectionRef();
432-
Error ErrorStatus =
433-
processDataRelocations(BC, SecRefRelData, /* !HasAddressTaken */ false);
434-
if (ErrorStatus)
435-
return ErrorStatus;
436-
}
437-
398+
void IdenticalCodeFolding::analyzeFunctions(BinaryContext &BC) {
438399
ParallelUtilities::WorkFuncTy WorkFun = [&](BinaryFunction &BF) {
439-
for (const BinaryBasicBlock *BB : BF.getLayout().blocks()) {
440-
for (const MCInst &Inst : *BB) {
400+
for (const BinaryBasicBlock *BB : BF.getLayout().blocks())
401+
for (const MCInst &Inst : *BB)
441402
if (!(BC.MIB->isCall(Inst) || BC.MIB->isBranch(Inst)))
442403
BF.processInstructionForFuncReferences(BC, Inst);
443-
}
444-
}
445404
};
446405
ParallelUtilities::PredicateTy SkipFunc =
447406
[&](const BinaryFunction &BF) -> bool {
@@ -459,7 +418,15 @@ Error IdenticalCodeFolding::markFunctionsUnsafeToFold(BinaryContext &BC) {
459418
<< '\n';
460419
}
461420
});
462-
return Error::success();
421+
}
422+
void IdenticalCodeFolding::markFunctionsUnsafeToFold(BinaryContext &BC) {
423+
NamedRegionTimer MarkFunctionsUnsafeToFoldTimer(
424+
"markFunctionsUnsafeToFold", "markFunctionsUnsafeToFold", "ICF breakdown",
425+
"ICF breakdown", opts::TimeICF);
426+
if (!BC.isX86())
427+
BC.outs() << "BOLT-WARNING: safe ICF is only supported for x86\n";
428+
analyzeDataRelocations(BC);
429+
analyzeFunctions(BC);
463430
}
464431

465432
Error IdenticalCodeFolding::runOnFunctions(BinaryContext &BC) {
@@ -597,8 +564,7 @@ Error IdenticalCodeFolding::runOnFunctions(BinaryContext &BC) {
597564
LLVM_DEBUG(SinglePass.stopTimer());
598565
};
599566
if (opts::ICF == ICFLevel::Safe)
600-
if (Error Err = markFunctionsUnsafeToFold(BC))
601-
return Err;
567+
markFunctionsUnsafeToFold(BC);
602568
hashFunctions();
603569
createCongruentBuckets();
604570

bolt/lib/Rewrite/RewriteInstance.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2120,6 +2120,64 @@ void RewriteInstance::adjustCommandLineOptions() {
21202120
}
21212121
}
21222122

2123+
namespace {
2124+
template <typename ELFT>
2125+
int64_t getRelocationAddend(const ELFObjectFile<ELFT> *Obj,
2126+
const RelocationRef &RelRef) {
2127+
using ELFShdrTy = typename ELFT::Shdr;
2128+
using Elf_Rela = typename ELFT::Rela;
2129+
int64_t Addend = 0;
2130+
const ELFFile<ELFT> &EF = Obj->getELFFile();
2131+
DataRefImpl Rel = RelRef.getRawDataRefImpl();
2132+
const ELFShdrTy *RelocationSection = cantFail(EF.getSection(Rel.d.a));
2133+
switch (RelocationSection->sh_type) {
2134+
default:
2135+
llvm_unreachable("unexpected relocation section type");
2136+
case ELF::SHT_REL:
2137+
break;
2138+
case ELF::SHT_RELA: {
2139+
const Elf_Rela *RelA = Obj->getRela(Rel);
2140+
Addend = RelA->r_addend;
2141+
break;
2142+
}
2143+
}
2144+
2145+
return Addend;
2146+
}
2147+
2148+
int64_t getRelocationAddend(const ELFObjectFileBase *Obj,
2149+
const RelocationRef &Rel) {
2150+
return getRelocationAddend(cast<ELF64LEObjectFile>(Obj), Rel);
2151+
}
2152+
2153+
template <typename ELFT>
2154+
uint32_t getRelocationSymbol(const ELFObjectFile<ELFT> *Obj,
2155+
const RelocationRef &RelRef) {
2156+
using ELFShdrTy = typename ELFT::Shdr;
2157+
uint32_t Symbol = 0;
2158+
const ELFFile<ELFT> &EF = Obj->getELFFile();
2159+
DataRefImpl Rel = RelRef.getRawDataRefImpl();
2160+
const ELFShdrTy *RelocationSection = cantFail(EF.getSection(Rel.d.a));
2161+
switch (RelocationSection->sh_type) {
2162+
default:
2163+
llvm_unreachable("unexpected relocation section type");
2164+
case ELF::SHT_REL:
2165+
Symbol = Obj->getRel(Rel)->getSymbol(EF.isMips64EL());
2166+
break;
2167+
case ELF::SHT_RELA:
2168+
Symbol = Obj->getRela(Rel)->getSymbol(EF.isMips64EL());
2169+
break;
2170+
}
2171+
2172+
return Symbol;
2173+
}
2174+
2175+
uint32_t getRelocationSymbol(const ELFObjectFileBase *Obj,
2176+
const RelocationRef &Rel) {
2177+
return getRelocationSymbol(cast<ELF64LEObjectFile>(Obj), Rel);
2178+
}
2179+
} // anonymous namespace
2180+
21232181
bool RewriteInstance::analyzeRelocation(
21242182
const RelocationRef &Rel, uint64_t &RType, std::string &SymbolName,
21252183
bool &IsSectionRelocation, uint64_t &SymbolAddress, int64_t &Addend,

bolt/test/X86/icf-safe-process-rela-data.test

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
## Check that BOLT handles correctly folding functions with --icf=safe that can be referenced.
2-
## This checks when only reference to a function is in .rela.data section.
1+
## Check that BOLT handles correctly folding functions with --icf=safe that are only reference in a .rela.data section.
32

43
# REQUIRES: system-linux
54
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o

bolt/test/X86/icf-safe-test1-no-relocs.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
## Checks that BOLT handles correctly with no relocations with --icf=safe option.
1+
## Check that BOLT handles correctly a binary with no relocations with the --icf=safe option.
22

33
# REQUIRES: system-linux
44
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o
55
# RUN: %clang %cflags %t1.o -o %t.exe
66
# RUN: not llvm-bolt --no-threads %t.exe --icf=safe -debug -debug-only=bolt-icf -o %t.bolt 2>&1 | FileCheck --check-prefix=SAFEICFCHECK %s
77

8-
# SAFEICFCHECK: BOLT-ERROR: Binary built without relocations. Safe ICF is not supported
8+
# SAFEICFCHECK: BOLT-ERROR: binary built without relocations. Safe ICF is not supported
99

1010
## int main(int argc, char **argv) {
1111
## return temp;

bolt/test/X86/icf-safe-test1.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
## Check that BOLT handles correctly folding functions with --icf=safe that can be referenced.
2-
## It invokes BOLT twice first testing CFG path, and second when function has to be disassembled.
1+
## Check that BOLT handles correctly folding functions with --icf=safe that can be referenced by non-control flow instructions.
2+
## It invokes BOLT twice first testing CFG path, and second when functions have to be disassembled.
33

44
# REQUIRES: system-linux
55
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-linux %s -o %t1.o

0 commit comments

Comments
 (0)