xref: /freebsd/contrib/llvm-project/lld/MachO/InputSection.cpp (revision 9f23cbd6cae82fd77edfad7173432fa8dccd0a95)
1 //===- InputSection.cpp ---------------------------------------------------===//
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 "InputSection.h"
10 #include "ConcatOutputSection.h"
11 #include "Config.h"
12 #include "InputFiles.h"
13 #include "OutputSegment.h"
14 #include "Symbols.h"
15 #include "SyntheticSections.h"
16 #include "Target.h"
17 #include "UnwindInfoSection.h"
18 #include "Writer.h"
19 
20 #include "lld/Common/ErrorHandler.h"
21 #include "lld/Common/Memory.h"
22 #include "llvm/Support/Endian.h"
23 #include "llvm/Support/xxhash.h"
24 
25 using namespace llvm;
26 using namespace llvm::MachO;
27 using namespace llvm::support;
28 using namespace lld;
29 using namespace lld::macho;
30 
31 // Verify ConcatInputSection's size on 64-bit builds. The size of std::vector
32 // can differ based on STL debug levels (e.g. iterator debugging on MSVC's STL),
33 // so account for that.
34 static_assert(sizeof(void *) != 8 ||
35                   sizeof(ConcatInputSection) == sizeof(std::vector<Reloc>) + 88,
36               "Try to minimize ConcatInputSection's size, we create many "
37               "instances of it");
38 
39 std::vector<ConcatInputSection *> macho::inputSections;
40 
41 uint64_t InputSection::getFileSize() const {
42   return isZeroFill(getFlags()) ? 0 : getSize();
43 }
44 
45 uint64_t InputSection::getVA(uint64_t off) const {
46   return parent->addr + getOffset(off);
47 }
48 
49 static uint64_t resolveSymbolVA(const Symbol *sym, uint8_t type) {
50   const RelocAttrs &relocAttrs = target->getRelocAttrs(type);
51   if (relocAttrs.hasAttr(RelocAttrBits::BRANCH))
52     return sym->resolveBranchVA();
53   if (relocAttrs.hasAttr(RelocAttrBits::GOT))
54     return sym->resolveGotVA();
55   if (relocAttrs.hasAttr(RelocAttrBits::TLV))
56     return sym->resolveTlvVA();
57   return sym->getVA();
58 }
59 
60 const Defined *InputSection::getContainingSymbol(uint64_t off) const {
61   auto *nextSym = llvm::upper_bound(
62       symbols, off, [](uint64_t a, const Defined *b) { return a < b->value; });
63   if (nextSym == symbols.begin())
64     return nullptr;
65   return *std::prev(nextSym);
66 }
67 
68 std::string InputSection::getLocation(uint64_t off) const {
69   // First, try to find a symbol that's near the offset. Use it as a reference
70   // point.
71   if (auto *sym = getContainingSymbol(off))
72     return (toString(getFile()) + ":(symbol " + toString(*sym) + "+0x" +
73             Twine::utohexstr(off - sym->value) + ")")
74         .str();
75 
76   // If that fails, use the section itself as a reference point.
77   for (const Subsection &subsec : section.subsections) {
78     if (subsec.isec == this) {
79       off += subsec.offset;
80       break;
81     }
82   }
83 
84   return (toString(getFile()) + ":(" + getName() + "+0x" +
85           Twine::utohexstr(off) + ")")
86       .str();
87 }
88 
89 std::string InputSection::getSourceLocation(uint64_t off) const {
90   auto *obj = dyn_cast_or_null<ObjFile>(getFile());
91   if (!obj)
92     return {};
93 
94   DWARFCache *dwarf = obj->getDwarf();
95   if (!dwarf)
96     return std::string();
97 
98   for (const Subsection &subsec : section.subsections) {
99     if (subsec.isec == this) {
100       off += subsec.offset;
101       break;
102     }
103   }
104 
105   auto createMsg = [&](StringRef path, unsigned line) {
106     std::string filename = sys::path::filename(path).str();
107     std::string lineStr = (":" + Twine(line)).str();
108     if (filename == path)
109       return filename + lineStr;
110     return (filename + lineStr + " (" + path + lineStr + ")").str();
111   };
112 
113   // First, look up a function for a given offset.
114   if (std::optional<DILineInfo> li = dwarf->getDILineInfo(
115           section.addr + off, object::SectionedAddress::UndefSection))
116     return createMsg(li->FileName, li->Line);
117 
118   // If it failed, look up again as a variable.
119   if (const Defined *sym = getContainingSymbol(off)) {
120     // Symbols are generally prefixed with an underscore, which is not included
121     // in the debug information.
122     StringRef symName = sym->getName();
123     if (!symName.empty() && symName[0] == '_')
124       symName = symName.substr(1);
125 
126     if (std::optional<std::pair<std::string, unsigned>> fileLine =
127             dwarf->getVariableLoc(symName))
128       return createMsg(fileLine->first, fileLine->second);
129   }
130 
131   // Try to get the source file's name from the DWARF information.
132   if (obj->compileUnit)
133     return obj->sourceFile();
134 
135   return {};
136 }
137 
138 void ConcatInputSection::foldIdentical(ConcatInputSection *copy) {
139   align = std::max(align, copy->align);
140   copy->live = false;
141   copy->wasCoalesced = true;
142   copy->replacement = this;
143   for (auto &copySym : copy->symbols) {
144     copySym->wasIdenticalCodeFolded = true;
145     copySym->size = 0;
146   }
147 
148   symbols.insert(symbols.end(), copy->symbols.begin(), copy->symbols.end());
149   copy->symbols.clear();
150 
151   // Remove duplicate compact unwind info for symbols at the same address.
152   if (symbols.empty())
153     return;
154   for (auto it = symbols.begin() + 1; it != symbols.end(); ++it) {
155     assert((*it)->value == 0);
156     (*it)->unwindEntry = nullptr;
157   }
158 }
159 
160 void ConcatInputSection::writeTo(uint8_t *buf) {
161   assert(!shouldOmitFromOutput());
162 
163   if (getFileSize() == 0)
164     return;
165 
166   memcpy(buf, data.data(), data.size());
167 
168   for (size_t i = 0; i < relocs.size(); i++) {
169     const Reloc &r = relocs[i];
170     uint8_t *loc = buf + r.offset;
171     uint64_t referentVA = 0;
172 
173     const bool needsFixup = config->emitChainedFixups &&
174                             target->hasAttr(r.type, RelocAttrBits::UNSIGNED);
175     if (target->hasAttr(r.type, RelocAttrBits::SUBTRAHEND)) {
176       const Symbol *fromSym = r.referent.get<Symbol *>();
177       const Reloc &minuend = relocs[++i];
178       uint64_t minuendVA;
179       if (const Symbol *toSym = minuend.referent.dyn_cast<Symbol *>())
180         minuendVA = toSym->getVA() + minuend.addend;
181       else {
182         auto *referentIsec = minuend.referent.get<InputSection *>();
183         assert(!::shouldOmitFromOutput(referentIsec));
184         minuendVA = referentIsec->getVA(minuend.addend);
185       }
186       referentVA = minuendVA - fromSym->getVA();
187     } else if (auto *referentSym = r.referent.dyn_cast<Symbol *>()) {
188       if (target->hasAttr(r.type, RelocAttrBits::LOAD) &&
189           !referentSym->isInGot())
190         target->relaxGotLoad(loc, r.type);
191       // For dtrace symbols, do not handle them as normal undefined symbols
192       if (referentSym->getName().startswith("___dtrace_")) {
193         // Change dtrace call site to pre-defined instructions
194         target->handleDtraceReloc(referentSym, r, loc);
195         continue;
196       }
197       referentVA = resolveSymbolVA(referentSym, r.type) + r.addend;
198 
199       if (isThreadLocalVariables(getFlags()) && isa<Defined>(referentSym)) {
200         // References from thread-local variable sections are treated as offsets
201         // relative to the start of the thread-local data memory area, which
202         // is initialized via copying all the TLV data sections (which are all
203         // contiguous).
204         referentVA -= firstTLVDataSection->addr;
205       } else if (needsFixup) {
206         writeChainedFixup(loc, referentSym, r.addend);
207         continue;
208       }
209     } else if (auto *referentIsec = r.referent.dyn_cast<InputSection *>()) {
210       assert(!::shouldOmitFromOutput(referentIsec));
211       referentVA = referentIsec->getVA(r.addend);
212 
213       if (needsFixup) {
214         writeChainedRebase(loc, referentVA);
215         continue;
216       }
217     }
218     target->relocateOne(loc, r, referentVA, getVA() + r.offset);
219   }
220 }
221 
222 ConcatInputSection *macho::makeSyntheticInputSection(StringRef segName,
223                                                      StringRef sectName,
224                                                      uint32_t flags,
225                                                      ArrayRef<uint8_t> data,
226                                                      uint32_t align) {
227   Section &section =
228       *make<Section>(/*file=*/nullptr, segName, sectName, flags, /*addr=*/0);
229   auto isec = make<ConcatInputSection>(section, data, align);
230   section.subsections.push_back({0, isec});
231   return isec;
232 }
233 
234 void CStringInputSection::splitIntoPieces() {
235   size_t off = 0;
236   StringRef s = toStringRef(data);
237   while (!s.empty()) {
238     size_t end = s.find(0);
239     if (end == StringRef::npos)
240       fatal(getLocation(off) + ": string is not null terminated");
241     uint32_t hash = deduplicateLiterals ? xxHash64(s.take_front(end)) : 0;
242     pieces.emplace_back(off, hash);
243     size_t size = end + 1; // include null terminator
244     s = s.substr(size);
245     off += size;
246   }
247 }
248 
249 StringPiece &CStringInputSection::getStringPiece(uint64_t off) {
250   if (off >= data.size())
251     fatal(toString(this) + ": offset is outside the section");
252 
253   auto it =
254       partition_point(pieces, [=](StringPiece p) { return p.inSecOff <= off; });
255   return it[-1];
256 }
257 
258 const StringPiece &CStringInputSection::getStringPiece(uint64_t off) const {
259   return const_cast<CStringInputSection *>(this)->getStringPiece(off);
260 }
261 
262 uint64_t CStringInputSection::getOffset(uint64_t off) const {
263   const StringPiece &piece = getStringPiece(off);
264   uint64_t addend = off - piece.inSecOff;
265   return piece.outSecOff + addend;
266 }
267 
268 WordLiteralInputSection::WordLiteralInputSection(const Section &section,
269                                                  ArrayRef<uint8_t> data,
270                                                  uint32_t align)
271     : InputSection(WordLiteralKind, section, data, align) {
272   switch (sectionType(getFlags())) {
273   case S_4BYTE_LITERALS:
274     power2LiteralSize = 2;
275     break;
276   case S_8BYTE_LITERALS:
277     power2LiteralSize = 3;
278     break;
279   case S_16BYTE_LITERALS:
280     power2LiteralSize = 4;
281     break;
282   default:
283     llvm_unreachable("invalid literal section type");
284   }
285 
286   live.resize(data.size() >> power2LiteralSize, !config->deadStrip);
287 }
288 
289 uint64_t WordLiteralInputSection::getOffset(uint64_t off) const {
290   auto *osec = cast<WordLiteralSection>(parent);
291   const uintptr_t buf = reinterpret_cast<uintptr_t>(data.data());
292   switch (sectionType(getFlags())) {
293   case S_4BYTE_LITERALS:
294     return osec->getLiteral4Offset(buf + (off & ~3LLU)) | (off & 3);
295   case S_8BYTE_LITERALS:
296     return osec->getLiteral8Offset(buf + (off & ~7LLU)) | (off & 7);
297   case S_16BYTE_LITERALS:
298     return osec->getLiteral16Offset(buf + (off & ~15LLU)) | (off & 15);
299   default:
300     llvm_unreachable("invalid literal section type");
301   }
302 }
303 
304 bool macho::isCodeSection(const InputSection *isec) {
305   uint32_t type = sectionType(isec->getFlags());
306   if (type != S_REGULAR && type != S_COALESCED)
307     return false;
308 
309   uint32_t attr = isec->getFlags() & SECTION_ATTRIBUTES_USR;
310   if (attr == S_ATTR_PURE_INSTRUCTIONS)
311     return true;
312 
313   if (isec->getSegName() == segment_names::text)
314     return StringSwitch<bool>(isec->getName())
315         .Cases(section_names::textCoalNt, section_names::staticInit, true)
316         .Default(false);
317 
318   return false;
319 }
320 
321 bool macho::isCfStringSection(const InputSection *isec) {
322   return isec->getName() == section_names::cfString &&
323          isec->getSegName() == segment_names::data;
324 }
325 
326 bool macho::isClassRefsSection(const InputSection *isec) {
327   return isec->getName() == section_names::objcClassRefs &&
328          isec->getSegName() == segment_names::data;
329 }
330 
331 bool macho::isSelRefsSection(const InputSection *isec) {
332   return isec->getName() == section_names::objcSelrefs &&
333          isec->getSegName() == segment_names::data;
334 }
335 
336 bool macho::isEhFrameSection(const InputSection *isec) {
337   return isec->getName() == section_names::ehFrame &&
338          isec->getSegName() == segment_names::text;
339 }
340 
341 bool macho::isGccExceptTabSection(const InputSection *isec) {
342   return isec->getName() == section_names::gccExceptTab &&
343          isec->getSegName() == segment_names::text;
344 }
345 
346 std::string lld::toString(const InputSection *isec) {
347   return (toString(isec->getFile()) + ":(" + isec->getName() + ")").str();
348 }
349