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