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