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