[lld-macho] Don't attempt to emit rebase opcodes for debug sections
authorJez Ng <jezng@fb.com>
Wed, 9 Dec 2020 01:47:19 +0000 (17:47 -0800)
committerJez Ng <jezng@fb.com>
Thu, 10 Dec 2020 23:57:51 +0000 (15:57 -0800)
This was causing a crash as we were attempting to look up the
nonexistent parent OutputSection of the debug sections. We didn't detect
it earlier because there was no test for PIEs with debug info (PIEs
require us to emit rebases for X86_64_RELOC_UNSIGNED).

This diff filters out the debug sections while loading the ObjFiles. In
addition to fixing the above problem, it also lets us avoid doing
redundant work -- we no longer parse / apply relocations / attempt to
emit dyld opcodes for these sections that we don't emit.

Fixes llvm.org/PR48392.

Reviewed By: thakis

Differential Revision: https://reviews.llvm.org/D92904

lld/MachO/Dwarf.cpp
lld/MachO/InputFiles.cpp
lld/MachO/InputFiles.h
lld/MachO/Writer.cpp
lld/test/MachO/stabs.s

index 121f54f..3e79492 100644 (file)
@@ -20,26 +20,19 @@ using namespace llvm;
 std::unique_ptr<DwarfObject> DwarfObject::create(ObjFile *obj) {
   auto dObj = std::make_unique<DwarfObject>();
   bool hasDwarfInfo = false;
-  for (SubsectionMap subsecMap : obj->subsections) {
-    for (auto it : subsecMap) {
-      InputSection *isec = it.second;
-      if (!(isDebugSection(isec->flags) &&
-            isec->segname == segment_names::dwarf))
-        continue;
-
-      if (isec->name == "__debug_info") {
-        dObj->infoSection.Data = toStringRef(isec->data);
-        hasDwarfInfo = true;
-        continue;
-      }
-
-      if (StringRef *s = StringSwitch<StringRef *>(isec->name)
-                             .Case("__debug_abbrev", &dObj->abbrevSection)
-                             .Case("__debug_str", &dObj->strSection)
-                             .Default(nullptr)) {
-        *s = toStringRef(isec->data);
-        hasDwarfInfo = true;
-      }
+  // LLD only needs to extract the source file path from the debug info, so we
+  // initialize DwarfObject with just the sections necessary to get that path.
+  // The debugger will locate the debug info via the object file paths that we
+  // emit in our STABS symbols, so we don't need to process & emit them
+  // ourselves.
+  for (InputSection *isec : obj->debugSections) {
+    if (StringRef *s = StringSwitch<StringRef *>(isec->name)
+                           .Case("__debug_info", &dObj->infoSection.Data)
+                           .Case("__debug_abbrev", &dObj->abbrevSection)
+                           .Case("__debug_str", &dObj->strSection)
+                           .Default(nullptr)) {
+      *s = toStringRef(isec->data);
+      hasDwarfInfo = true;
     }
   }
 
index c452648..3e0ad22 100644 (file)
@@ -174,7 +174,18 @@ void ObjFile::parseSections(ArrayRef<section_64> sections) {
     else
       isec->align = 1 << sec.align;
     isec->flags = sec.flags;
-    subsections.push_back({{0, isec}});
+
+    if (!(isDebugSection(isec->flags) &&
+          isec->segname == segment_names::dwarf)) {
+      subsections.push_back({{0, isec}});
+    } else {
+      // Instead of emitting DWARF sections, we emit STABS symbols to the
+      // object files that contain them. We filter them out early to avoid
+      // parsing their relocations unnecessarily. But we must still push an
+      // empty map to ensure the indices line up for the remaining sections.
+      subsections.push_back({});
+      debugSections.push_back(isec);
+    }
   }
 }
 
@@ -307,6 +318,7 @@ void ObjFile::parseSymbols(ArrayRef<structs::nlist_64> nList,
 
     const section_64 &sec = sectionHeaders[sym.n_sect - 1];
     SubsectionMap &subsecMap = subsections[sym.n_sect - 1];
+    assert(!subsecMap.empty());
     uint64_t offset = sym.n_value - sec.addr;
 
     // If the input file does not use subsections-via-symbols, all symbols can
@@ -410,7 +422,8 @@ ObjFile::ObjFile(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName)
   // The relocations may refer to the symbols, so we parse them after we have
   // parsed all the symbols.
   for (size_t i = 0, n = subsections.size(); i < n; ++i)
-    parseRelocations(sectionHeaders[i], subsections[i]);
+    if (!subsections[i].empty())
+      parseRelocations(sectionHeaders[i], subsections[i]);
 
   parseDebugInfo();
 }
index 877ccae..2b49228 100644 (file)
@@ -95,6 +95,7 @@ public:
   llvm::DWARFUnit *compileUnit = nullptr;
   const uint32_t modTime;
   ArrayRef<llvm::MachO::section_64> sectionHeaders;
+  std::vector<InputSection *> debugSections;
 
 private:
   void parseSections(ArrayRef<llvm::MachO::section_64>);
index 45ff11e..2d033fe 100644 (file)
@@ -603,10 +603,6 @@ void Writer::createOutputSections() {
   MapVector<std::pair<StringRef, StringRef>, MergedOutputSection *>
       mergedOutputSections;
   for (InputSection *isec : inputSections) {
-    // Instead of emitting DWARF sections, we emit STABS symbols to the object
-    // files that contain them.
-    if (isDebugSection(isec->flags) && isec->segname == segment_names::dwarf)
-      continue;
     MergedOutputSection *&osec =
         mergedOutputSections[{isec->segname, isec->name}];
     if (osec == nullptr)
index 4457832..9634a95 100644 (file)
 # CHECK-NEXT:  {{[0-9af]+}}     T _no_debug
 # CHECK-EMPTY:
 
+## Check that we don't attempt to emit rebase opcodes for the debug sections
+## when building a PIE (since we have filtered the sections out).
+# RUN: %lld -lSystem -pie %t/test.o %t/foo.a %t/no-debug.o -o %t/test
+# RUN: llvm-objdump --macho --rebase %t/test | FileCheck %s --check-prefix=PIE
+# PIE:       Rebase table:
+# PIE-NEXT:  segment  section            address     type
+# PIE-EMPTY:
+
 #--- test.s
 
 ## Make sure we don't create STABS entries for absolute symbols.