[lld-macho] Fix assertion when two symbols at same addr have unwind info
authorJez Ng <jezng@fb.com>
Thu, 21 Jul 2022 13:44:01 +0000 (09:44 -0400)
committerJez Ng <jezng@fb.com>
Thu, 21 Jul 2022 13:44:49 +0000 (09:44 -0400)
If there are multiple symbols at the same address, our unwind info
implementation assumes that we always register unwind entries to a
single canonical symbol.

This assumption was violated by the `registerEhFrame` code.

Fixes #56570.

Reviewed By: #lld-macho, thakis

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

lld/MachO/InputFiles.cpp
lld/MachO/UnwindInfoSection.cpp
lld/test/MachO/Inputs/double-unwind-info.yaml [new file with mode: 0644]
lld/test/MachO/double-unwind-info.s [new file with mode: 0644]

index 5bc333f..a2c27f1 100644 (file)
@@ -1528,6 +1528,13 @@ void ObjFile::registerEhFrames(Section &ehFrameSection) {
     Defined *funcSym;
     if (funcAddrRelocIt != isec->relocs.end()) {
       funcSym = targetSymFromCanonicalSubtractor(isec, funcAddrRelocIt);
+      // Canonicalize the symbol. If there are multiple symbols at the same
+      // address, we want both `registerEhFrame` and `registerCompactUnwind`
+      // to register the unwind entry under same symbol.
+      // This is not particularly efficient, but we should run into this case
+      // infrequently (only when handling the output of `ld -r`).
+      funcSym = findSymbolAtOffset(cast<ConcatInputSection>(funcSym->isec),
+                                   funcSym->value);
     } else {
       funcSym = findSymbolAtAddress(sections, funcAddr);
       ehRelocator.makePcRel(funcAddrOff, funcSym, target->p2WordSize);
index 8c3425a..3220579 100644 (file)
@@ -211,7 +211,7 @@ void UnwindInfoSection::addSymbol(const Defined *d) {
   // we use that as the key here.
   auto p = symbols.insert({{d->isec, d->value}, d});
   // If we have multiple symbols at the same address, only one of them can have
-  // an associated CUE.
+  // an associated unwind entry.
   if (!p.second && d->unwindEntry) {
     assert(!p.first->second->unwindEntry);
     p.first->second = d;
diff --git a/lld/test/MachO/Inputs/double-unwind-info.yaml b/lld/test/MachO/Inputs/double-unwind-info.yaml
new file mode 100644 (file)
index 0000000..077f334
--- /dev/null
@@ -0,0 +1,159 @@
+--- !mach-o
+FileHeader:
+  magic:           0xFEEDFACF
+  cputype:         0x1000007
+  cpusubtype:      0x3
+  filetype:        0x1
+  ncmds:           4
+  sizeofcmds:      384
+  flags:           0x2000
+  reserved:        0x0
+LoadCommands:
+  - cmd:             LC_SEGMENT_64
+    cmdsize:         312
+    segname:         ''
+    vmaddr:          0
+    vmsize:          96
+    fileoff:         448
+    filesize:        96
+    maxprot:         7
+    initprot:        7
+    nsects:          3
+    flags:           0
+    Sections:
+      - sectname:        __text
+        segname:         __TEXT
+        addr:            0x0
+        size:            2
+        offset:          0x1C0
+        align:           0
+        reloff:          0x0
+        nreloc:          0
+        flags:           0x80000400
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         '9090'
+      - sectname:        __eh_frame
+        segname:         __TEXT
+        addr:            0x8
+        size:            56
+        offset:          0x1C8
+        align:           3
+        reloff:          0x220
+        nreloc:          4
+        flags:           0x0
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         1400000000000000017A520001781001100C0708900100001C00000004000000F8FFFFFFFFFFFFFF0100000000000000000E080000000000
+        relocations:
+          - address:         0x1C
+            symbolnum:       3
+            pcrel:           false
+            length:          2
+            extern:          true
+            type:            5
+            scattered:       false
+            value:           0
+          - address:         0x1C
+            symbolnum:       4
+            pcrel:           false
+            length:          2
+            extern:          true
+            type:            0
+            scattered:       false
+            value:           0
+          - address:         0x20
+            symbolnum:       4
+            pcrel:           false
+            length:          3
+            extern:          true
+            type:            5
+            scattered:       false
+            value:           0
+          - address:         0x20
+            symbolnum:       2
+            pcrel:           false
+            length:          3
+            extern:          true
+            type:            0
+            scattered:       false
+            value:           0
+      - sectname:        __compact_unwind
+        segname:         __LD
+        addr:            0x40
+        size:            32
+        offset:          0x200
+        align:           3
+        reloff:          0x240
+        nreloc:          1
+        flags:           0x2000000
+        reserved1:       0x0
+        reserved2:       0x0
+        reserved3:       0x0
+        content:         '0000000000000000010000000000010200000000000000000000000000000000'
+        relocations:
+          - address:         0x0
+            symbolnum:       2
+            pcrel:           false
+            length:          3
+            extern:          true
+            type:            0
+            scattered:       false
+            value:           0
+  - cmd:             LC_SYMTAB
+    cmdsize:         24
+    symoff:          584
+    nsyms:           5
+    stroff:          664
+    strsize:         40
+  - cmd:             LC_BUILD_VERSION
+    cmdsize:         32
+    platform:        1
+    minos:           659200
+    sdk:             0
+    ntools:          1
+    Tools:
+      - tool:            3
+        version:         50069504
+  - cmd:             LC_DATA_IN_CODE
+    cmdsize:         16
+    dataoff:         584
+    datasize:        0
+LinkEditData:
+  NameList:
+    - n_strx:          2
+      n_type:          0xE
+      n_sect:          1
+      n_desc:          0
+      n_value:         0
+    - n_strx:          10
+      n_type:          0xE
+      n_sect:          1
+      n_desc:          0
+      n_value:         1
+    - n_strx:          16
+      n_type:          0xE
+      n_sect:          1
+      n_desc:          0
+      n_value:         1
+    - n_strx:          21
+      n_type:          0xE
+      n_sect:          2
+      n_desc:          0
+      n_value:         8
+    - n_strx:          31
+      n_type:          0xE
+      n_sect:          2
+      n_desc:          0
+      n_value:         32
+  StringTable:
+    - ' '
+    - _spacer
+    - ltmp1
+    - _foo
+    - EH_Frame1
+    - func.eh
+    - ''
+...
diff --git a/lld/test/MachO/double-unwind-info.s b/lld/test/MachO/double-unwind-info.s
new file mode 100644 (file)
index 0000000..d1301cb
--- /dev/null
@@ -0,0 +1,26 @@
+## When changing the assembly input, uncomment these lines to re-generate the
+## YAML.
+# COM: llvm-mc --emit-dwarf-unwind=always -filetype=obj -triple=x86_64-apple-macos10.15 %s -o %t.o
+# COM: ld -r %t.o -o %t-r.o
+# COM: obj2yaml %t-r.o > %S/Inputs/double-unwind-info.yaml
+
+# RUN: yaml2obj %S/Inputs/double-unwind-info.yaml > %t-r.o
+# RUN: %lld -dylib -lSystem %t-r.o -o /dev/null
+
+.text
+## eh_frame function address relocations are only emitted if the function isn't
+## at address 0x0.
+_spacer:
+  nop
+
+## Check that we perform unwind info registration correctly when there are
+## multiple symbols at the same address. This would previously hit an assertion
+## error (PR56570).
+_foo:
+ltmp1:
+  .cfi_startproc
+  .cfi_def_cfa_offset 8
+  nop
+  .cfi_endproc
+
+.subsections_via_symbols