[lld-macho] Fix assertion when two symbols at same addr have unwind info

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
This commit is contained in:
Jez Ng 2022-07-21 09:44:01 -04:00
parent 1da3119025
commit 241f62d8d3
4 changed files with 193 additions and 1 deletions

View 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);

View 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;

View File

@ -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
- ''
...

View File

@ -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