xref: /llvm-project/bolt/lib/Rewrite/ExecutableFileMemoryManager.cpp (revision ad8fd5b18545f90a2c3abcd056e9c566721d8711)
12f09f445SMaksim Panchenko //===- bolt/Rewrite/ExecutableFileMemoryManager.cpp -----------------------===//
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 
9a34c753fSRafael Auler #include "bolt/Rewrite/ExecutableFileMemoryManager.h"
1005634f73SJob Noorman #include "bolt/Rewrite/JITLinkLinker.h"
11a34c753fSRafael Auler #include "bolt/Rewrite/RewriteInstance.h"
1205634f73SJob Noorman #include "llvm/ExecutionEngine/JITLink/JITLink.h"
131d539352SMaksim Panchenko #include "llvm/Support/MemAlloc.h"
14a34c753fSRafael Auler 
15a34c753fSRafael Auler #undef  DEBUG_TYPE
16a34c753fSRafael Auler #define DEBUG_TYPE "efmm"
17a34c753fSRafael Auler 
18a34c753fSRafael Auler using namespace llvm;
19a34c753fSRafael Auler using namespace object;
20a34c753fSRafael Auler using namespace bolt;
21a34c753fSRafael Auler 
22a34c753fSRafael Auler namespace llvm {
23a34c753fSRafael Auler 
24a34c753fSRafael Auler namespace bolt {
25a34c753fSRafael Auler 
2605634f73SJob Noorman namespace {
271d539352SMaksim Panchenko 
orderedSections(jitlink::LinkGraph & G)2805634f73SJob Noorman SmallVector<jitlink::Section *> orderedSections(jitlink::LinkGraph &G) {
2905634f73SJob Noorman   SmallVector<jitlink::Section *> Sections(
3005634f73SJob Noorman       llvm::map_range(G.sections(), [](auto &S) { return &S; }));
3105634f73SJob Noorman   llvm::sort(Sections, [](const auto *LHS, const auto *RHS) {
3205634f73SJob Noorman     return LHS->getOrdinal() < RHS->getOrdinal();
3305634f73SJob Noorman   });
3405634f73SJob Noorman   return Sections;
3505634f73SJob Noorman }
3605634f73SJob Noorman 
sectionAlignment(const jitlink::Section & Section)3705634f73SJob Noorman size_t sectionAlignment(const jitlink::Section &Section) {
3805634f73SJob Noorman   assert(!Section.empty() && "Cannot get alignment for empty section");
3905634f73SJob Noorman   return JITLinkLinker::orderedBlocks(Section).front()->getAlignment();
4005634f73SJob Noorman }
4105634f73SJob Noorman 
sectionName(const jitlink::Section & Section,const BinaryContext & BC)4205634f73SJob Noorman StringRef sectionName(const jitlink::Section &Section,
4305634f73SJob Noorman                       const BinaryContext &BC) {
4405634f73SJob Noorman   auto Name = Section.getName();
4505634f73SJob Noorman 
4605634f73SJob Noorman   if (BC.isMachO()) {
4705634f73SJob Noorman     // JITLink "normalizes" section names as "SegmentName,SectionName" on
4805634f73SJob Noorman     // Mach-O. BOLT internally refers to sections just by the section name so
4905634f73SJob Noorman     // strip-off the segment name.
5005634f73SJob Noorman     auto SegmentEnd = Name.find(',');
5105634f73SJob Noorman     assert(SegmentEnd != StringRef::npos && "Mach-O segment not found");
5205634f73SJob Noorman     Name = Name.substr(SegmentEnd + 1);
5305634f73SJob Noorman   }
5405634f73SJob Noorman 
5505634f73SJob Noorman   return Name;
5605634f73SJob Noorman }
5705634f73SJob Noorman 
5805634f73SJob Noorman struct SectionAllocInfo {
5905634f73SJob Noorman   void *Address;
6005634f73SJob Noorman   size_t Size;
6105634f73SJob Noorman   size_t Alignment;
6205634f73SJob Noorman };
6305634f73SJob Noorman 
6405634f73SJob Noorman struct AllocInfo {
6505634f73SJob Noorman   SmallVector<SectionAllocInfo, 8> AllocatedSections;
6605634f73SJob Noorman 
~AllocInfollvm::bolt::__anon319135a00111::AllocInfo6705634f73SJob Noorman   ~AllocInfo() {
6805634f73SJob Noorman     for (auto &Section : AllocatedSections)
6905634f73SJob Noorman       deallocate_buffer(Section.Address, Section.Size, Section.Alignment);
7005634f73SJob Noorman   }
7105634f73SJob Noorman 
allocateSectionllvm::bolt::__anon319135a00111::AllocInfo7205634f73SJob Noorman   SectionAllocInfo allocateSection(const jitlink::Section &Section) {
7305634f73SJob Noorman     auto Size = JITLinkLinker::sectionSize(Section);
7405634f73SJob Noorman     auto Alignment = sectionAlignment(Section);
7505634f73SJob Noorman     auto *Buf = allocate_buffer(Size, Alignment);
7605634f73SJob Noorman     SectionAllocInfo Alloc{Buf, Size, Alignment};
7705634f73SJob Noorman     AllocatedSections.push_back(Alloc);
7805634f73SJob Noorman     return Alloc;
7905634f73SJob Noorman   }
8005634f73SJob Noorman };
8105634f73SJob Noorman 
8205634f73SJob Noorman struct BOLTInFlightAlloc : ExecutableFileMemoryManager::InFlightAlloc {
8305634f73SJob Noorman   // Even though this is passed using a raw pointer in FinalizedAlloc, we keep
8405634f73SJob Noorman   // it in a unique_ptr as long as possible to enjoy automatic cleanup when
8505634f73SJob Noorman   // something goes wrong.
8605634f73SJob Noorman   std::unique_ptr<AllocInfo> Alloc;
8705634f73SJob Noorman 
8805634f73SJob Noorman public:
BOLTInFlightAllocllvm::bolt::__anon319135a00111::BOLTInFlightAlloc8905634f73SJob Noorman   BOLTInFlightAlloc(std::unique_ptr<AllocInfo> Alloc)
9005634f73SJob Noorman       : Alloc(std::move(Alloc)) {}
9105634f73SJob Noorman 
abandonllvm::bolt::__anon319135a00111::BOLTInFlightAlloc9205634f73SJob Noorman   virtual void abandon(OnAbandonedFunction OnAbandoned) override {
933429aa3eSRafael Auler     OnAbandoned(Error::success());
9405634f73SJob Noorman   }
9505634f73SJob Noorman 
finalizellvm::bolt::__anon319135a00111::BOLTInFlightAlloc9605634f73SJob Noorman   virtual void finalize(OnFinalizedFunction OnFinalized) override {
9705634f73SJob Noorman     OnFinalized(ExecutableFileMemoryManager::FinalizedAlloc(
9805634f73SJob Noorman         orc::ExecutorAddr::fromPtr(Alloc.release())));
9905634f73SJob Noorman   }
10005634f73SJob Noorman };
10105634f73SJob Noorman 
10205634f73SJob Noorman } // anonymous namespace
10305634f73SJob Noorman 
updateSection(const jitlink::Section & JLSection,uint8_t * Contents,size_t Size,size_t Alignment)10405634f73SJob Noorman void ExecutableFileMemoryManager::updateSection(
10505634f73SJob Noorman     const jitlink::Section &JLSection, uint8_t *Contents, size_t Size,
10605634f73SJob Noorman     size_t Alignment) {
10705634f73SJob Noorman   auto SectionID = JLSection.getName();
10805634f73SJob Noorman   auto SectionName = sectionName(JLSection, BC);
10905634f73SJob Noorman   auto Prot = JLSection.getMemProt();
11005634f73SJob Noorman   auto IsCode = (Prot & orc::MemProt::Exec) != orc::MemProt::None;
11105634f73SJob Noorman   auto IsReadOnly = (Prot & orc::MemProt::Write) == orc::MemProt::None;
112f3ea4228SJob Noorman 
113a34c753fSRafael Auler   // Register a debug section as a note section.
114a34c753fSRafael Auler   if (!ObjectsLoaded && RewriteInstance::isDebugSection(SectionName)) {
115a34c753fSRafael Auler     BinarySection &Section =
11605634f73SJob Noorman         BC.registerOrUpdateNoteSection(SectionName, Contents, Size, Alignment);
117a34c753fSRafael Auler     Section.setSectionID(SectionID);
118a34c753fSRafael Auler     assert(!Section.isAllocatable() && "note sections cannot be allocatable");
11905634f73SJob Noorman     return;
120a34c753fSRafael Auler   }
121a34c753fSRafael Auler 
12240c2e0faSMaksim Panchenko   if (!IsCode && (SectionName == ".strtab" || SectionName == ".symtab" ||
123*ad8fd5b1SKazu Hirata                   SectionName == "" || SectionName.starts_with(".rela.")))
12405634f73SJob Noorman     return;
125a34c753fSRafael Auler 
126a34c753fSRafael Auler   SmallVector<char, 256> Buf;
127a34c753fSRafael Auler   if (ObjectsLoaded > 0) {
128a34c753fSRafael Auler     if (BC.isELF()) {
129a34c753fSRafael Auler       SectionName = (Twine(SectionName) + ".bolt.extra." + Twine(ObjectsLoaded))
130a34c753fSRafael Auler                         .toStringRef(Buf);
131a34c753fSRafael Auler     } else if (BC.isMachO()) {
132a34c753fSRafael Auler       assert((SectionName == "__text" || SectionName == "__data" ||
133a34c753fSRafael Auler               SectionName == "__fini" || SectionName == "__setup" ||
134a34c753fSRafael Auler               SectionName == "__cstring" || SectionName == "__literal16") &&
135a34c753fSRafael Auler              "Unexpected section in the instrumentation library");
136a34c753fSRafael Auler       // Sections coming from the instrumentation runtime are prefixed with "I".
137a34c753fSRafael Auler       SectionName = ("I" + Twine(SectionName)).toStringRef(Buf);
138a34c753fSRafael Auler     }
139a34c753fSRafael Auler   }
140a34c753fSRafael Auler 
1414d3a0cadSMaksim Panchenko   BinarySection *Section = nullptr;
142*ad8fd5b1SKazu Hirata   if (!OrgSecPrefix.empty() && SectionName.starts_with(OrgSecPrefix)) {
1434d3a0cadSMaksim Panchenko     // Update the original section contents.
1444d3a0cadSMaksim Panchenko     ErrorOr<BinarySection &> OrgSection =
1454d3a0cadSMaksim Panchenko         BC.getUniqueSectionByName(SectionName.substr(OrgSecPrefix.length()));
1464d3a0cadSMaksim Panchenko     assert(OrgSection && OrgSection->isAllocatable() &&
1474d3a0cadSMaksim Panchenko            "Original section must exist and be allocatable.");
148a34c753fSRafael Auler 
1494d3a0cadSMaksim Panchenko     Section = &OrgSection.get();
15005634f73SJob Noorman     Section->updateContents(Contents, Size);
1514d3a0cadSMaksim Panchenko   } else {
1524d3a0cadSMaksim Panchenko     // If the input contains a section with the section name, rename it in the
1534d3a0cadSMaksim Panchenko     // output file to avoid the section name conflict and emit the new section
1544d3a0cadSMaksim Panchenko     // under a unique internal name.
1554d3a0cadSMaksim Panchenko     ErrorOr<BinarySection &> OrgSection =
1564d3a0cadSMaksim Panchenko         BC.getUniqueSectionByName(SectionName);
1574d3a0cadSMaksim Panchenko     bool UsePrefix = false;
1584d3a0cadSMaksim Panchenko     if (OrgSection && OrgSection->hasSectionRef()) {
1594d3a0cadSMaksim Panchenko       OrgSection->setOutputName(OrgSecPrefix + SectionName);
1604d3a0cadSMaksim Panchenko       UsePrefix = true;
1614d3a0cadSMaksim Panchenko     }
1624d3a0cadSMaksim Panchenko 
1634d3a0cadSMaksim Panchenko     // Register the new section under a unique name to avoid name collision with
1644d3a0cadSMaksim Panchenko     // sections in the input file.
1654d3a0cadSMaksim Panchenko     BinarySection &NewSection = BC.registerOrUpdateSection(
1664d3a0cadSMaksim Panchenko         UsePrefix ? NewSecPrefix + SectionName : SectionName, ELF::SHT_PROGBITS,
16705634f73SJob Noorman         BinarySection::getFlags(IsReadOnly, IsCode, true), Contents, Size,
1684d3a0cadSMaksim Panchenko         Alignment);
1694d3a0cadSMaksim Panchenko     if (UsePrefix)
1704d3a0cadSMaksim Panchenko       NewSection.setOutputName(SectionName);
1714d3a0cadSMaksim Panchenko     Section = &NewSection;
1724d3a0cadSMaksim Panchenko   }
1734d3a0cadSMaksim Panchenko 
1744d3a0cadSMaksim Panchenko   LLVM_DEBUG({
175a34c753fSRafael Auler     dbgs() << "BOLT: allocating "
176a34c753fSRafael Auler            << (IsCode ? "code" : (IsReadOnly ? "read-only data" : "data"))
1774d3a0cadSMaksim Panchenko            << " section : " << Section->getOutputName() << " ("
1784d3a0cadSMaksim Panchenko            << Section->getName() << ")"
1794d3a0cadSMaksim Panchenko            << " with size " << Size << ", alignment " << Alignment << " at "
18005634f73SJob Noorman            << Contents << ", ID = " << SectionID << "\n";
1814d3a0cadSMaksim Panchenko   });
1824d3a0cadSMaksim Panchenko 
1834d3a0cadSMaksim Panchenko   Section->setSectionID(SectionID);
184a34c753fSRafael Auler }
185a34c753fSRafael Auler 
allocate(const jitlink::JITLinkDylib * JD,jitlink::LinkGraph & G,OnAllocatedFunction OnAllocated)18605634f73SJob Noorman void ExecutableFileMemoryManager::allocate(const jitlink::JITLinkDylib *JD,
18705634f73SJob Noorman                                            jitlink::LinkGraph &G,
18805634f73SJob Noorman                                            OnAllocatedFunction OnAllocated) {
18905634f73SJob Noorman   auto Alloc = std::make_unique<AllocInfo>();
19005634f73SJob Noorman 
19105634f73SJob Noorman   for (auto *Section : orderedSections(G)) {
19205634f73SJob Noorman     if (Section->empty())
19305634f73SJob Noorman       continue;
19405634f73SJob Noorman 
19505634f73SJob Noorman     auto SectionAlloc = Alloc->allocateSection(*Section);
19605634f73SJob Noorman     updateSection(*Section, static_cast<uint8_t *>(SectionAlloc.Address),
19705634f73SJob Noorman                   SectionAlloc.Size, SectionAlloc.Alignment);
19805634f73SJob Noorman 
19905634f73SJob Noorman     size_t CurrentOffset = 0;
20005634f73SJob Noorman     auto *Buf = static_cast<char *>(SectionAlloc.Address);
20105634f73SJob Noorman     for (auto *Block : JITLinkLinker::orderedBlocks(*Section)) {
20205634f73SJob Noorman       CurrentOffset = jitlink::alignToBlock(CurrentOffset, *Block);
20305634f73SJob Noorman       auto BlockSize = Block->getSize();
20405634f73SJob Noorman       auto *BlockBuf = Buf + CurrentOffset;
20505634f73SJob Noorman 
20605634f73SJob Noorman       if (Block->isZeroFill())
20705634f73SJob Noorman         std::memset(BlockBuf, 0, BlockSize);
20805634f73SJob Noorman       else
20905634f73SJob Noorman         std::memcpy(BlockBuf, Block->getContent().data(), BlockSize);
21005634f73SJob Noorman 
21105634f73SJob Noorman       Block->setMutableContent({BlockBuf, Block->getSize()});
21205634f73SJob Noorman       CurrentOffset += BlockSize;
21305634f73SJob Noorman     }
21405634f73SJob Noorman   }
21505634f73SJob Noorman 
21605634f73SJob Noorman   OnAllocated(std::make_unique<BOLTInFlightAlloc>(std::move(Alloc)));
21705634f73SJob Noorman }
21805634f73SJob Noorman 
deallocate(std::vector<FinalizedAlloc> Allocs,OnDeallocatedFunction OnDeallocated)21905634f73SJob Noorman void ExecutableFileMemoryManager::deallocate(
22005634f73SJob Noorman     std::vector<FinalizedAlloc> Allocs, OnDeallocatedFunction OnDeallocated) {
22105634f73SJob Noorman   for (auto &Alloc : Allocs)
22205634f73SJob Noorman     delete Alloc.release().toPtr<AllocInfo *>();
22305634f73SJob Noorman 
22405634f73SJob Noorman   OnDeallocated(Error::success());
225a34c753fSRafael Auler }
226a34c753fSRafael Auler 
22740c2e0faSMaksim Panchenko } // namespace bolt
228a34c753fSRafael Auler 
22940c2e0faSMaksim Panchenko } // namespace llvm
230