Home | History | Annotate | Line # | Download | only in MachO
      1 //===- Object.cpp - Mach-O object file model --------------------*- C++ -*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 
      9 #include "Object.h"
     10 #include "llvm/ADT/SmallPtrSet.h"
     11 #include <unordered_set>
     12 
     13 namespace llvm {
     14 namespace objcopy {
     15 namespace macho {
     16 
     17 const SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) const {
     18   assert(Index < Symbols.size() && "invalid symbol index");
     19   return Symbols[Index].get();
     20 }
     21 
     22 SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) {
     23   return const_cast<SymbolEntry *>(
     24       static_cast<const SymbolTable *>(this)->getSymbolByIndex(Index));
     25 }
     26 
     27 void SymbolTable::removeSymbols(
     28     function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove) {
     29   llvm::erase_if(Symbols, ToRemove);
     30 }
     31 
     32 void Object::updateLoadCommandIndexes() {
     33   // Update indices of special load commands
     34   for (size_t Index = 0, Size = LoadCommands.size(); Index < Size; ++Index) {
     35     LoadCommand &LC = LoadCommands[Index];
     36     switch (LC.MachOLoadCommand.load_command_data.cmd) {
     37     case MachO::LC_SYMTAB:
     38       SymTabCommandIndex = Index;
     39       break;
     40     case MachO::LC_DYSYMTAB:
     41       DySymTabCommandIndex = Index;
     42       break;
     43     case MachO::LC_DYLD_INFO:
     44     case MachO::LC_DYLD_INFO_ONLY:
     45       DyLdInfoCommandIndex = Index;
     46       break;
     47     case MachO::LC_DATA_IN_CODE:
     48       DataInCodeCommandIndex = Index;
     49       break;
     50     case MachO::LC_FUNCTION_STARTS:
     51       FunctionStartsCommandIndex = Index;
     52       break;
     53     }
     54   }
     55 }
     56 
     57 Error Object::removeLoadCommands(
     58     function_ref<bool(const LoadCommand &)> ToRemove) {
     59   auto It = std::stable_partition(
     60       LoadCommands.begin(), LoadCommands.end(),
     61       [&](const LoadCommand &LC) { return !ToRemove(LC); });
     62   LoadCommands.erase(It, LoadCommands.end());
     63 
     64   updateLoadCommandIndexes();
     65   return Error::success();
     66 }
     67 
     68 Error Object::removeSections(
     69     function_ref<bool(const std::unique_ptr<Section> &)> ToRemove) {
     70   DenseMap<uint32_t, const Section *> OldIndexToSection;
     71   uint32_t NextSectionIndex = 1;
     72   for (LoadCommand &LC : LoadCommands) {
     73     auto It = std::stable_partition(
     74         std::begin(LC.Sections), std::end(LC.Sections),
     75         [&](const std::unique_ptr<Section> &Sec) { return !ToRemove(Sec); });
     76     for (auto I = LC.Sections.begin(), End = It; I != End; ++I) {
     77       OldIndexToSection[(*I)->Index] = I->get();
     78       (*I)->Index = NextSectionIndex++;
     79     }
     80     LC.Sections.erase(It, LC.Sections.end());
     81   }
     82 
     83   auto IsDead = [&](const std::unique_ptr<SymbolEntry> &S) -> bool {
     84     Optional<uint32_t> Section = S->section();
     85     return (Section && !OldIndexToSection.count(*Section));
     86   };
     87 
     88   SmallPtrSet<const SymbolEntry *, 2> DeadSymbols;
     89   for (const std::unique_ptr<SymbolEntry> &Sym : SymTable.Symbols)
     90     if (IsDead(Sym))
     91       DeadSymbols.insert(Sym.get());
     92 
     93   for (const LoadCommand &LC : LoadCommands)
     94     for (const std::unique_ptr<Section> &Sec : LC.Sections)
     95       for (const RelocationInfo &R : Sec->Relocations)
     96         if (R.Symbol && *R.Symbol && DeadSymbols.count(*R.Symbol))
     97           return createStringError(std::errc::invalid_argument,
     98                                    "symbol '%s' defined in section with index "
     99                                    "'%u' cannot be removed because it is "
    100                                    "referenced by a relocation in section '%s'",
    101                                    (*R.Symbol)->Name.c_str(),
    102                                    *((*R.Symbol)->section()),
    103                                    Sec->CanonicalName.c_str());
    104   SymTable.removeSymbols(IsDead);
    105   for (std::unique_ptr<SymbolEntry> &S : SymTable.Symbols)
    106     if (S->section())
    107       S->n_sect = OldIndexToSection[S->n_sect]->Index;
    108   return Error::success();
    109 }
    110 
    111 uint64_t Object::nextAvailableSegmentAddress() const {
    112   uint64_t HeaderSize =
    113       is64Bit() ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
    114   uint64_t Addr = HeaderSize + Header.SizeOfCmds;
    115   for (const LoadCommand &LC : LoadCommands) {
    116     const MachO::macho_load_command &MLC = LC.MachOLoadCommand;
    117     switch (MLC.load_command_data.cmd) {
    118     case MachO::LC_SEGMENT:
    119       Addr = std::max(Addr,
    120                       static_cast<uint64_t>(MLC.segment_command_data.vmaddr) +
    121                           MLC.segment_command_data.vmsize);
    122       break;
    123     case MachO::LC_SEGMENT_64:
    124       Addr = std::max(Addr, MLC.segment_command_64_data.vmaddr +
    125                                 MLC.segment_command_64_data.vmsize);
    126       break;
    127     default:
    128       continue;
    129     }
    130   }
    131   return Addr;
    132 }
    133 
    134 template <typename SegmentType>
    135 static void
    136 constructSegment(SegmentType &Seg, llvm::MachO::LoadCommandType CmdType,
    137                  StringRef SegName, uint64_t SegVMAddr, uint64_t SegVMSize) {
    138   assert(SegName.size() <= sizeof(Seg.segname) && "too long segment name");
    139   memset(&Seg, 0, sizeof(SegmentType));
    140   Seg.cmd = CmdType;
    141   strncpy(Seg.segname, SegName.data(), SegName.size());
    142   Seg.maxprot |=
    143       (MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);
    144   Seg.initprot |=
    145       (MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE);
    146   Seg.vmaddr = SegVMAddr;
    147   Seg.vmsize = SegVMSize;
    148 }
    149 
    150 LoadCommand &Object::addSegment(StringRef SegName, uint64_t SegVMSize) {
    151   LoadCommand LC;
    152   const uint64_t SegVMAddr = nextAvailableSegmentAddress();
    153   if (is64Bit())
    154     constructSegment(LC.MachOLoadCommand.segment_command_64_data,
    155                      MachO::LC_SEGMENT_64, SegName, SegVMAddr, SegVMSize);
    156   else
    157     constructSegment(LC.MachOLoadCommand.segment_command_data,
    158                      MachO::LC_SEGMENT, SegName, SegVMAddr, SegVMSize);
    159 
    160   LoadCommands.push_back(std::move(LC));
    161   return LoadCommands.back();
    162 }
    163 
    164 /// Extracts a segment name from a string which is possibly non-null-terminated.
    165 static StringRef extractSegmentName(const char *SegName) {
    166   return StringRef(SegName,
    167                    strnlen(SegName, sizeof(MachO::segment_command::segname)));
    168 }
    169 
    170 Optional<StringRef> LoadCommand::getSegmentName() const {
    171   const MachO::macho_load_command &MLC = MachOLoadCommand;
    172   switch (MLC.load_command_data.cmd) {
    173   case MachO::LC_SEGMENT:
    174     return extractSegmentName(MLC.segment_command_data.segname);
    175   case MachO::LC_SEGMENT_64:
    176     return extractSegmentName(MLC.segment_command_64_data.segname);
    177   default:
    178     return None;
    179   }
    180 }
    181 
    182 Optional<uint64_t> LoadCommand::getSegmentVMAddr() const {
    183   const MachO::macho_load_command &MLC = MachOLoadCommand;
    184   switch (MLC.load_command_data.cmd) {
    185   case MachO::LC_SEGMENT:
    186     return MLC.segment_command_data.vmaddr;
    187   case MachO::LC_SEGMENT_64:
    188     return MLC.segment_command_64_data.vmaddr;
    189   default:
    190     return None;
    191   }
    192 }
    193 
    194 } // end namespace macho
    195 } // end namespace objcopy
    196 } // end namespace llvm
    197