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 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 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 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 6705634f73SJob Noorman ~AllocInfo() { 6805634f73SJob Noorman for (auto &Section : AllocatedSections) 6905634f73SJob Noorman deallocate_buffer(Section.Address, Section.Size, Section.Alignment); 7005634f73SJob Noorman } 7105634f73SJob Noorman 7205634f73SJob 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: 8905634f73SJob Noorman BOLTInFlightAlloc(std::unique_ptr<AllocInfo> Alloc) 9005634f73SJob Noorman : Alloc(std::move(Alloc)) {} 9105634f73SJob Noorman 9205634f73SJob Noorman virtual void abandon(OnAbandonedFunction OnAbandoned) override { 93*3429aa3eSRafael Auler OnAbandoned(Error::success()); 9405634f73SJob Noorman } 9505634f73SJob Noorman 9605634f73SJob 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 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" || 123ee0e9ccbSMaksim Panchenko SectionName == "" || SectionName.startswith(".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; 1424d3a0cadSMaksim Panchenko if (!OrgSecPrefix.empty() && SectionName.startswith(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 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 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