12f09f445SMaksim Panchenko //===- bolt/Core/BinarySection.cpp - Section in a binary file -------------===//
2a34c753fSRafael Auler //
3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information.
5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a34c753fSRafael Auler //
7a34c753fSRafael Auler //===----------------------------------------------------------------------===//
8a34c753fSRafael Auler //
92f09f445SMaksim Panchenko // This file implements the BinarySection class.
102f09f445SMaksim Panchenko //
11a34c753fSRafael Auler //===----------------------------------------------------------------------===//
12a34c753fSRafael Auler
13a34c753fSRafael Auler #include "bolt/Core/BinarySection.h"
14a34c753fSRafael Auler #include "bolt/Core/BinaryContext.h"
15a34c753fSRafael Auler #include "bolt/Utils/Utils.h"
16a34c753fSRafael Auler #include "llvm/MC/MCStreamer.h"
17a34c753fSRafael Auler #include "llvm/Support/CommandLine.h"
18a34c753fSRafael Auler
19a34c753fSRafael Auler #define DEBUG_TYPE "bolt"
20a34c753fSRafael Auler
21a34c753fSRafael Auler using namespace llvm;
22a34c753fSRafael Auler using namespace bolt;
23a34c753fSRafael Auler
24a34c753fSRafael Auler namespace opts {
25a34c753fSRafael Auler extern cl::opt<bool> PrintRelocations;
26a34c753fSRafael Auler extern cl::opt<bool> HotData;
2740c2e0faSMaksim Panchenko } // namespace opts
28a34c753fSRafael Auler
isELF() const2940c2e0faSMaksim Panchenko bool BinarySection::isELF() const { return BC.isELF(); }
30a34c753fSRafael Auler
isMachO() const3140c2e0faSMaksim Panchenko bool BinarySection::isMachO() const { return BC.isMachO(); }
32a34c753fSRafael Auler
33a34c753fSRafael Auler uint64_t
hash(const BinaryData & BD,std::map<const BinaryData *,uint64_t> & Cache) const34a34c753fSRafael Auler BinarySection::hash(const BinaryData &BD,
35a34c753fSRafael Auler std::map<const BinaryData *, uint64_t> &Cache) const {
36a34c753fSRafael Auler auto Itr = Cache.find(&BD);
37a34c753fSRafael Auler if (Itr != Cache.end())
38a34c753fSRafael Auler return Itr->second;
39a34c753fSRafael Auler
40a34c753fSRafael Auler Cache[&BD] = 0;
41a34c753fSRafael Auler
42a34c753fSRafael Auler uint64_t Offset = BD.getAddress() - getAddress();
43a34c753fSRafael Auler const uint64_t EndOffset = BD.getEndAddress() - getAddress();
44a34c753fSRafael Auler auto Begin = Relocations.lower_bound(Relocation{Offset, 0, 0, 0, 0});
45a34c753fSRafael Auler auto End = Relocations.upper_bound(Relocation{EndOffset, 0, 0, 0, 0});
46a34c753fSRafael Auler const StringRef Contents = getContents();
47a34c753fSRafael Auler
4840c2e0faSMaksim Panchenko hash_code Hash =
4940c2e0faSMaksim Panchenko hash_combine(hash_value(BD.getSize()), hash_value(BD.getSectionName()));
50a34c753fSRafael Auler
51a34c753fSRafael Auler while (Begin != End) {
52a34c753fSRafael Auler const Relocation &Rel = *Begin++;
53a34c753fSRafael Auler Hash = hash_combine(
5440c2e0faSMaksim Panchenko Hash, hash_value(Contents.substr(Offset, Begin->Offset - Offset)));
553652483cSRafael Auler if (BinaryData *RelBD = BC.getBinaryDataByName(Rel.Symbol->getName()))
56a34c753fSRafael Auler Hash = hash_combine(Hash, hash(*RelBD, Cache));
57a34c753fSRafael Auler Offset = Rel.Offset + Rel.getSize();
58a34c753fSRafael Auler }
59a34c753fSRafael Auler
6040c2e0faSMaksim Panchenko Hash = hash_combine(Hash,
61a34c753fSRafael Auler hash_value(Contents.substr(Offset, EndOffset - Offset)));
62a34c753fSRafael Auler
63a34c753fSRafael Auler Cache[&BD] = Hash;
64a34c753fSRafael Auler
65a34c753fSRafael Auler return Hash;
66a34c753fSRafael Auler }
67a34c753fSRafael Auler
emitAsData(MCStreamer & Streamer,StringRef NewName) const68a34c753fSRafael Auler void BinarySection::emitAsData(MCStreamer &Streamer, StringRef NewName) const {
69a34c753fSRafael Auler StringRef SectionName = !NewName.empty() ? NewName : getName();
70a34c753fSRafael Auler StringRef SectionContents = getContents();
71a34c753fSRafael Auler MCSectionELF *ELFSection =
72a34c753fSRafael Auler BC.Ctx->getELFSection(SectionName, getELFType(), getELFFlags());
73a34c753fSRafael Auler
74*adf4142fSFangrui Song Streamer.switchSection(ELFSection);
75a34c753fSRafael Auler Streamer.emitValueToAlignment(getAlignment());
76a34c753fSRafael Auler
77a34c753fSRafael Auler if (BC.HasRelocations && opts::HotData && isReordered())
78a34c753fSRafael Auler Streamer.emitLabel(BC.Ctx->getOrCreateSymbol("__hot_data_start"));
79a34c753fSRafael Auler
80a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: emitting "
81a34c753fSRafael Auler << (isAllocatable() ? "" : "non-")
82a34c753fSRafael Auler << "allocatable data section " << SectionName << '\n');
83a34c753fSRafael Auler
84a34c753fSRafael Auler if (!hasRelocations()) {
85a34c753fSRafael Auler Streamer.emitBytes(SectionContents);
86a34c753fSRafael Auler } else {
87a34c753fSRafael Auler uint64_t SectionOffset = 0;
88a34c753fSRafael Auler for (const Relocation &Relocation : relocations()) {
89a34c753fSRafael Auler assert(Relocation.Offset < SectionContents.size() && "overflow detected");
90a34c753fSRafael Auler // Skip undefined symbols.
91a34c753fSRafael Auler if (BC.UndefinedSymbols.count(Relocation.Symbol))
92a34c753fSRafael Auler continue;
93a34c753fSRafael Auler if (SectionOffset < Relocation.Offset) {
9440c2e0faSMaksim Panchenko Streamer.emitBytes(SectionContents.substr(
9540c2e0faSMaksim Panchenko SectionOffset, Relocation.Offset - SectionOffset));
96a34c753fSRafael Auler SectionOffset = Relocation.Offset;
97a34c753fSRafael Auler }
98a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: emitting relocation for symbol "
99a34c753fSRafael Auler << (Relocation.Symbol ? Relocation.Symbol->getName()
100a34c753fSRafael Auler : StringRef("<none>"))
101a34c753fSRafael Auler << " at offset 0x"
102a34c753fSRafael Auler << Twine::utohexstr(Relocation.Offset) << " with size "
103a34c753fSRafael Auler << Relocation::getSizeForType(Relocation.Type) << '\n');
104a34c753fSRafael Auler size_t RelocationSize = Relocation.emit(&Streamer);
105a34c753fSRafael Auler SectionOffset += RelocationSize;
106a34c753fSRafael Auler }
107a34c753fSRafael Auler assert(SectionOffset <= SectionContents.size() && "overflow error");
1083652483cSRafael Auler if (SectionOffset < SectionContents.size())
109a34c753fSRafael Auler Streamer.emitBytes(SectionContents.substr(SectionOffset));
110a34c753fSRafael Auler }
111a34c753fSRafael Auler
112a34c753fSRafael Auler if (BC.HasRelocations && opts::HotData && isReordered())
113a34c753fSRafael Auler Streamer.emitLabel(BC.Ctx->getOrCreateSymbol("__hot_data_end"));
114a34c753fSRafael Auler }
115a34c753fSRafael Auler
flushPendingRelocations(raw_pwrite_stream & OS,SymbolResolverFuncTy Resolver)116a34c753fSRafael Auler void BinarySection::flushPendingRelocations(raw_pwrite_stream &OS,
117a34c753fSRafael Auler SymbolResolverFuncTy Resolver) {
118a34c753fSRafael Auler if (PendingRelocations.empty() && Patches.empty())
119a34c753fSRafael Auler return;
120a34c753fSRafael Auler
121a34c753fSRafael Auler const uint64_t SectionAddress = getAddress();
122a34c753fSRafael Auler
123a34c753fSRafael Auler // We apply relocations to original section contents. For allocatable sections
124a34c753fSRafael Auler // this means using their input file offsets, since the output file offset
125a34c753fSRafael Auler // could change (e.g. for new instance of .text). For non-allocatable
126a34c753fSRafael Auler // sections, the output offset should always be a valid one.
12740c2e0faSMaksim Panchenko const uint64_t SectionFileOffset =
12840c2e0faSMaksim Panchenko isAllocatable() ? getInputFileOffset() : getOutputFileOffset();
129a34c753fSRafael Auler LLVM_DEBUG(
130a34c753fSRafael Auler dbgs() << "BOLT-DEBUG: flushing pending relocations for section "
131a34c753fSRafael Auler << getName() << '\n'
132a34c753fSRafael Auler << " address: 0x" << Twine::utohexstr(SectionAddress) << '\n'
133a34c753fSRafael Auler << " offset: 0x" << Twine::utohexstr(SectionFileOffset) << '\n');
134a34c753fSRafael Auler
1353652483cSRafael Auler for (BinaryPatch &Patch : Patches)
13640c2e0faSMaksim Panchenko OS.pwrite(Patch.Bytes.data(), Patch.Bytes.size(),
137a34c753fSRafael Auler SectionFileOffset + Patch.Offset);
138a34c753fSRafael Auler
139a34c753fSRafael Auler for (Relocation &Reloc : PendingRelocations) {
140a34c753fSRafael Auler uint64_t Value = Reloc.Addend;
141a34c753fSRafael Auler if (Reloc.Symbol)
142a34c753fSRafael Auler Value += Resolver(Reloc.Symbol);
1434a4045f7SElvina Yakubova
1444a4045f7SElvina Yakubova Value = Relocation::adjustValue(Reloc.Type, Value,
1454a4045f7SElvina Yakubova SectionAddress + Reloc.Offset);
1464a4045f7SElvina Yakubova
147a34c753fSRafael Auler OS.pwrite(reinterpret_cast<const char *>(&Value),
148a34c753fSRafael Auler Relocation::getSizeForType(Reloc.Type),
149a34c753fSRafael Auler SectionFileOffset + Reloc.Offset);
1504a4045f7SElvina Yakubova
151a34c753fSRafael Auler LLVM_DEBUG(
152a34c753fSRafael Auler dbgs() << "BOLT-DEBUG: writing value 0x" << Twine::utohexstr(Value)
153a34c753fSRafael Auler << " of size " << Relocation::getSizeForType(Reloc.Type)
154a34c753fSRafael Auler << " at section offset 0x" << Twine::utohexstr(Reloc.Offset)
155a34c753fSRafael Auler << " address 0x"
156a34c753fSRafael Auler << Twine::utohexstr(SectionAddress + Reloc.Offset)
157a34c753fSRafael Auler << " file offset 0x"
158a34c753fSRafael Auler << Twine::utohexstr(SectionFileOffset + Reloc.Offset) << '\n';);
159a34c753fSRafael Auler }
160a34c753fSRafael Auler
161a34c753fSRafael Auler clearList(PendingRelocations);
162a34c753fSRafael Auler }
163a34c753fSRafael Auler
~BinarySection()164a34c753fSRafael Auler BinarySection::~BinarySection() {
165a34c753fSRafael Auler if (isReordered()) {
166a34c753fSRafael Auler delete[] getData();
167a34c753fSRafael Auler return;
168a34c753fSRafael Auler }
169a34c753fSRafael Auler
170a34c753fSRafael Auler if (!isAllocatable() &&
171a34c753fSRafael Auler (!hasSectionRef() ||
172a34c753fSRafael Auler OutputContents.data() != getContents(Section).data())) {
173a34c753fSRafael Auler delete[] getOutputData();
174a34c753fSRafael Auler }
175a34c753fSRafael Auler }
176a34c753fSRafael Auler
clearRelocations()17740c2e0faSMaksim Panchenko void BinarySection::clearRelocations() { clearList(Relocations); }
178a34c753fSRafael Auler
print(raw_ostream & OS) const179a34c753fSRafael Auler void BinarySection::print(raw_ostream &OS) const {
180a34c753fSRafael Auler OS << getName() << ", "
18140c2e0faSMaksim Panchenko << "0x" << Twine::utohexstr(getAddress()) << ", " << getSize() << " (0x"
18240c2e0faSMaksim Panchenko << Twine::utohexstr(getOutputAddress()) << ", " << getOutputSize() << ")"
18340c2e0faSMaksim Panchenko << ", data = " << getData() << ", output data = " << getOutputData();
184a34c753fSRafael Auler
185a34c753fSRafael Auler if (isAllocatable())
186a34c753fSRafael Auler OS << " (allocatable)";
187a34c753fSRafael Auler
188a34c753fSRafael Auler if (isVirtual())
189a34c753fSRafael Auler OS << " (virtual)";
190a34c753fSRafael Auler
191a34c753fSRafael Auler if (isTLS())
192a34c753fSRafael Auler OS << " (tls)";
193a34c753fSRafael Auler
1943652483cSRafael Auler if (opts::PrintRelocations)
195a34c753fSRafael Auler for (const Relocation &R : relocations())
196a34c753fSRafael Auler OS << "\n " << R;
197a34c753fSRafael Auler }
198a34c753fSRafael Auler
199a34c753fSRafael Auler BinarySection::RelocationSetType
reorderRelocations(bool Inplace) const200a34c753fSRafael Auler BinarySection::reorderRelocations(bool Inplace) const {
201a34c753fSRafael Auler assert(PendingRelocations.empty() &&
202a34c753fSRafael Auler "reodering pending relocations not supported");
203a34c753fSRafael Auler RelocationSetType NewRelocations;
204a34c753fSRafael Auler for (const Relocation &Rel : relocations()) {
205a34c753fSRafael Auler uint64_t RelAddr = Rel.Offset + getAddress();
206a34c753fSRafael Auler BinaryData *BD = BC.getBinaryDataContainingAddress(RelAddr);
207a34c753fSRafael Auler BD = BD->getAtomicRoot();
208a34c753fSRafael Auler assert(BD);
209a34c753fSRafael Auler
210a34c753fSRafael Auler if ((!BD->isMoved() && !Inplace) || BD->isJumpTable())
211a34c753fSRafael Auler continue;
212a34c753fSRafael Auler
213a34c753fSRafael Auler Relocation NewRel(Rel);
214a34c753fSRafael Auler uint64_t RelOffset = RelAddr - BD->getAddress();
215a34c753fSRafael Auler NewRel.Offset = BD->getOutputOffset() + RelOffset;
216a34c753fSRafael Auler assert(NewRel.Offset < getSize());
217a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: moving " << Rel << " -> " << NewRel
218a34c753fSRafael Auler << "\n");
219a34c753fSRafael Auler auto Res = NewRelocations.emplace(std::move(NewRel));
220a34c753fSRafael Auler (void)Res;
221a34c753fSRafael Auler assert(Res.second && "Can't overwrite existing relocation");
222a34c753fSRafael Auler }
223a34c753fSRafael Auler return NewRelocations;
224a34c753fSRafael Auler }
225a34c753fSRafael Auler
reorderContents(const std::vector<BinaryData * > & Order,bool Inplace)226a34c753fSRafael Auler void BinarySection::reorderContents(const std::vector<BinaryData *> &Order,
227a34c753fSRafael Auler bool Inplace) {
228a34c753fSRafael Auler IsReordered = true;
229a34c753fSRafael Auler
230a34c753fSRafael Auler Relocations = reorderRelocations(Inplace);
231a34c753fSRafael Auler
232a34c753fSRafael Auler std::string Str;
233a34c753fSRafael Auler raw_string_ostream OS(Str);
234a34c753fSRafael Auler const char *Src = Contents.data();
235a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: reorderContents for " << Name << "\n");
236a34c753fSRafael Auler for (BinaryData *BD : Order) {
237a34c753fSRafael Auler assert((BD->isMoved() || !Inplace) && !BD->isJumpTable());
238a34c753fSRafael Auler assert(BD->isAtomic() && BD->isMoveable());
239a34c753fSRafael Auler const uint64_t SrcOffset = BD->getAddress() - getAddress();
240a34c753fSRafael Auler assert(SrcOffset < Contents.size());
241a34c753fSRafael Auler assert(SrcOffset == BD->getOffset());
2423652483cSRafael Auler while (OS.tell() < BD->getOutputOffset())
243a34c753fSRafael Auler OS.write((unsigned char)0);
244a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "BOLT-DEBUG: " << BD->getName() << " @ " << OS.tell()
245a34c753fSRafael Auler << "\n");
246a34c753fSRafael Auler OS.write(&Src[SrcOffset], BD->getOutputSize());
247a34c753fSRafael Auler }
248a34c753fSRafael Auler if (Relocations.empty()) {
249a34c753fSRafael Auler // If there are no existing relocations, tack a phony one at the end
250a34c753fSRafael Auler // of the reordered segment to force LLVM to recognize and map this
251a34c753fSRafael Auler // section.
252a34c753fSRafael Auler MCSymbol *ZeroSym = BC.registerNameAtAddress("Zero", 0, 0, 0);
253a34c753fSRafael Auler addRelocation(OS.tell(), ZeroSym, ELF::R_X86_64_64, 0xdeadbeef);
254a34c753fSRafael Auler
255a34c753fSRafael Auler uint64_t Zero = 0;
256a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&Zero), sizeof(Zero));
257a34c753fSRafael Auler }
258a34c753fSRafael Auler auto *NewData = reinterpret_cast<char *>(copyByteArray(OS.str()));
259a34c753fSRafael Auler Contents = OutputContents = StringRef(NewData, OS.str().size());
260a34c753fSRafael Auler OutputSize = Contents.size();
261a34c753fSRafael Auler }
262a34c753fSRafael Auler
encodeELFNote(StringRef NameStr,StringRef DescStr,uint32_t Type)263a34c753fSRafael Auler std::string BinarySection::encodeELFNote(StringRef NameStr, StringRef DescStr,
264a34c753fSRafael Auler uint32_t Type) {
265a34c753fSRafael Auler std::string Str;
266a34c753fSRafael Auler raw_string_ostream OS(Str);
267a34c753fSRafael Auler const uint32_t NameSz = NameStr.size() + 1;
268a34c753fSRafael Auler const uint32_t DescSz = DescStr.size();
269a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&(NameSz)), 4);
270a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&(DescSz)), 4);
271a34c753fSRafael Auler OS.write(reinterpret_cast<const char *>(&(Type)), 4);
272a34c753fSRafael Auler OS << NameStr << '\0';
2733652483cSRafael Auler for (uint64_t I = NameSz; I < alignTo(NameSz, 4); ++I)
274a34c753fSRafael Auler OS << '\0';
275a34c753fSRafael Auler OS << DescStr;
2763652483cSRafael Auler for (uint64_t I = DescStr.size(); I < alignTo(DescStr.size(), 4); ++I)
277a34c753fSRafael Auler OS << '\0';
278a34c753fSRafael Auler return OS.str();
279a34c753fSRafael Auler }
280