Path: blob/main/contrib/llvm-project/llvm/lib/ObjCopy/MachO/MachOObject.cpp
35266 views
//===- MachOObject.cpp - Mach-O object file model ---------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "MachOObject.h"9#include "llvm/ADT/SmallPtrSet.h"10#include "llvm/Support/SystemZ/zOSSupport.h"11#include <unordered_set>1213using namespace llvm;14using namespace llvm::objcopy::macho;1516Section::Section(StringRef SegName, StringRef SectName)17: Segname(SegName), Sectname(SectName),18CanonicalName((Twine(SegName) + Twine(',') + SectName).str()) {}1920Section::Section(StringRef SegName, StringRef SectName, StringRef Content)21: Segname(SegName), Sectname(SectName),22CanonicalName((Twine(SegName) + Twine(',') + SectName).str()),23Content(Content) {}2425const SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) const {26assert(Index < Symbols.size() && "invalid symbol index");27return Symbols[Index].get();28}2930SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) {31return const_cast<SymbolEntry *>(32static_cast<const SymbolTable *>(this)->getSymbolByIndex(Index));33}3435void SymbolTable::removeSymbols(36function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove) {37llvm::erase_if(Symbols, ToRemove);38}3940void Object::updateLoadCommandIndexes() {41static constexpr char TextSegmentName[] = "__TEXT";42// Update indices of special load commands43for (size_t Index = 0, Size = LoadCommands.size(); Index < Size; ++Index) {44LoadCommand &LC = LoadCommands[Index];45switch (LC.MachOLoadCommand.load_command_data.cmd) {46case MachO::LC_CODE_SIGNATURE:47CodeSignatureCommandIndex = Index;48break;49case MachO::LC_SEGMENT:50if (StringRef(LC.MachOLoadCommand.segment_command_data.segname) ==51TextSegmentName)52TextSegmentCommandIndex = Index;53break;54case MachO::LC_SEGMENT_64:55if (StringRef(LC.MachOLoadCommand.segment_command_64_data.segname) ==56TextSegmentName)57TextSegmentCommandIndex = Index;58break;59case MachO::LC_SYMTAB:60SymTabCommandIndex = Index;61break;62case MachO::LC_DYSYMTAB:63DySymTabCommandIndex = Index;64break;65case MachO::LC_DYLD_INFO:66case MachO::LC_DYLD_INFO_ONLY:67DyLdInfoCommandIndex = Index;68break;69case MachO::LC_DATA_IN_CODE:70DataInCodeCommandIndex = Index;71break;72case MachO::LC_LINKER_OPTIMIZATION_HINT:73LinkerOptimizationHintCommandIndex = Index;74break;75case MachO::LC_FUNCTION_STARTS:76FunctionStartsCommandIndex = Index;77break;78case MachO::LC_DYLIB_CODE_SIGN_DRS:79DylibCodeSignDRsIndex = Index;80break;81case MachO::LC_DYLD_CHAINED_FIXUPS:82ChainedFixupsCommandIndex = Index;83break;84case MachO::LC_DYLD_EXPORTS_TRIE:85ExportsTrieCommandIndex = Index;86break;87}88}89}9091Error Object::removeLoadCommands(92function_ref<bool(const LoadCommand &)> ToRemove) {93auto It = std::stable_partition(94LoadCommands.begin(), LoadCommands.end(),95[&](const LoadCommand &LC) { return !ToRemove(LC); });96LoadCommands.erase(It, LoadCommands.end());9798updateLoadCommandIndexes();99return Error::success();100}101102Error Object::removeSections(103function_ref<bool(const std::unique_ptr<Section> &)> ToRemove) {104DenseMap<uint32_t, const Section *> OldIndexToSection;105uint32_t NextSectionIndex = 1;106for (LoadCommand &LC : LoadCommands) {107auto It = std::stable_partition(108std::begin(LC.Sections), std::end(LC.Sections),109[&](const std::unique_ptr<Section> &Sec) { return !ToRemove(Sec); });110for (auto I = LC.Sections.begin(), End = It; I != End; ++I) {111OldIndexToSection[(*I)->Index] = I->get();112(*I)->Index = NextSectionIndex++;113}114LC.Sections.erase(It, LC.Sections.end());115}116117auto IsDead = [&](const std::unique_ptr<SymbolEntry> &S) -> bool {118std::optional<uint32_t> Section = S->section();119return (Section && !OldIndexToSection.count(*Section));120};121122SmallPtrSet<const SymbolEntry *, 2> DeadSymbols;123for (const std::unique_ptr<SymbolEntry> &Sym : SymTable.Symbols)124if (IsDead(Sym))125DeadSymbols.insert(Sym.get());126127for (const LoadCommand &LC : LoadCommands)128for (const std::unique_ptr<Section> &Sec : LC.Sections)129for (const RelocationInfo &R : Sec->Relocations)130if (R.Symbol && *R.Symbol && DeadSymbols.count(*R.Symbol))131return createStringError(std::errc::invalid_argument,132"symbol '%s' defined in section with index "133"'%u' cannot be removed because it is "134"referenced by a relocation in section '%s'",135(*R.Symbol)->Name.c_str(),136*((*R.Symbol)->section()),137Sec->CanonicalName.c_str());138SymTable.removeSymbols(IsDead);139for (std::unique_ptr<SymbolEntry> &S : SymTable.Symbols)140if (S->section())141S->n_sect = OldIndexToSection[S->n_sect]->Index;142return Error::success();143}144145uint64_t Object::nextAvailableSegmentAddress() const {146uint64_t HeaderSize =147is64Bit() ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);148uint64_t Addr = HeaderSize + Header.SizeOfCmds;149for (const LoadCommand &LC : LoadCommands) {150const MachO::macho_load_command &MLC = LC.MachOLoadCommand;151switch (MLC.load_command_data.cmd) {152case MachO::LC_SEGMENT:153Addr = std::max(Addr,154static_cast<uint64_t>(MLC.segment_command_data.vmaddr) +155MLC.segment_command_data.vmsize);156break;157case MachO::LC_SEGMENT_64:158Addr = std::max(Addr, MLC.segment_command_64_data.vmaddr +159MLC.segment_command_64_data.vmsize);160break;161default:162continue;163}164}165return Addr;166}167168template <typename SegmentType>169static void170constructSegment(SegmentType &Seg, llvm::MachO::LoadCommandType CmdType,171StringRef SegName, uint64_t SegVMAddr, uint64_t SegVMSize) {172assert(SegName.size() <= sizeof(Seg.segname) && "too long segment name");173memset(&Seg, 0, sizeof(SegmentType));174Seg.cmd = CmdType;175strncpy(Seg.segname, SegName.data(), SegName.size());176Seg.maxprot |=177(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);178Seg.initprot |=179(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);180Seg.vmaddr = SegVMAddr;181Seg.vmsize = SegVMSize;182}183184LoadCommand &Object::addSegment(StringRef SegName, uint64_t SegVMSize) {185LoadCommand LC;186const uint64_t SegVMAddr = nextAvailableSegmentAddress();187if (is64Bit())188constructSegment(LC.MachOLoadCommand.segment_command_64_data,189MachO::LC_SEGMENT_64, SegName, SegVMAddr, SegVMSize);190else191constructSegment(LC.MachOLoadCommand.segment_command_data,192MachO::LC_SEGMENT, SegName, SegVMAddr, SegVMSize);193194LoadCommands.push_back(std::move(LC));195return LoadCommands.back();196}197198/// Extracts a segment name from a string which is possibly non-null-terminated.199static StringRef extractSegmentName(const char *SegName) {200return StringRef(SegName,201strnlen(SegName, sizeof(MachO::segment_command::segname)));202}203204std::optional<StringRef> LoadCommand::getSegmentName() const {205const MachO::macho_load_command &MLC = MachOLoadCommand;206switch (MLC.load_command_data.cmd) {207case MachO::LC_SEGMENT:208return extractSegmentName(MLC.segment_command_data.segname);209case MachO::LC_SEGMENT_64:210return extractSegmentName(MLC.segment_command_64_data.segname);211default:212return std::nullopt;213}214}215216std::optional<uint64_t> LoadCommand::getSegmentVMAddr() const {217const MachO::macho_load_command &MLC = MachOLoadCommand;218switch (MLC.load_command_data.cmd) {219case MachO::LC_SEGMENT:220return MLC.segment_command_data.vmaddr;221case MachO::LC_SEGMENT_64:222return MLC.segment_command_64_data.vmaddr;223default:224return std::nullopt;225}226}227228229