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