Skip to content

Commit 230b0ba

Browse files
committed
cmd/link: fix up location lists for dsymutil
LLVM tools, particularly lldb and dsymutil, don't support base address selection entries in location lists. When targeting GOOS=darwin, mode, have the linker translate location lists to CU-relative form instead. Technically, this isn't necessary when linking internally, as long as nobody plans to use anything other than Delve to look at the DWARF. But someone might want to use lldb, and it's really confusing when dwarfdump shows gibberish for the location entries. The performance cost isn't noticeable, so enable it even for internal linking. Doing this in the linker is a little weird, but it was more expensive in the compiler, probably because the compiler is much more stressful to the GC. Also, if we decide to only do it for external linking, the compiler can't see the link mode. Benchmark before and after this commit on Mac with -dwarflocationlists=1: name old time/op new time/op delta StdCmd 21.3s ± 1% 21.3s ± 1% ~ (p=0.310 n=27+27) Only StdCmd is relevant, because only StdCmd runs the linker. Whatever the cost is here, it's not very large. Change-Id: I200246dedaee4f824966f7551ac95f8d7123d3b1 Reviewed-on: https://go-review.googlesource.com/89535 Reviewed-by: David Chase <[email protected]>
1 parent 5b21bf6 commit 230b0ba

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

src/cmd/link/internal/ld/dwarf.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,6 +1759,10 @@ func collectlocs(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit) []*sy
17591759
reloc.Sym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable
17601760
syms = append(syms, reloc.Sym)
17611761
empty = false
1762+
// LLVM doesn't support base address entries. Strip them out so LLDB and dsymutil don't get confused.
1763+
if ctxt.HeadType == objabi.Hdarwin {
1764+
removeLocationListBaseAddress(ctxt, fn, reloc.Sym)
1765+
}
17621766
// One location list entry per function, but many relocations to it. Don't duplicate.
17631767
break
17641768
}
@@ -1775,6 +1779,73 @@ func collectlocs(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit) []*sy
17751779
return syms
17761780
}
17771781

1782+
func removeLocationListBaseAddress(ctxt *Link, info, list *sym.Symbol) {
1783+
// The list symbol contains multiple lists, but they're all for the
1784+
// same function, and it's not empty.
1785+
fn := list.R[0].Sym
1786+
1787+
// Discard the relocations for the base address entries.
1788+
list.R = list.R[:0]
1789+
1790+
// Add relocations for each location entry's start and end addresses,
1791+
// so that the base address entries aren't necessary.
1792+
// We could remove them entirely, but that's more work for a relatively
1793+
// small size win. If dsymutil runs it'll throw them away anyway.
1794+
1795+
// relocate adds a CU-relative relocation to fn+addr at offset.
1796+
relocate := func(addr uint64, offset int) {
1797+
list.R = append(list.R, sym.Reloc{
1798+
Off: int32(offset),
1799+
Siz: uint8(ctxt.Arch.PtrSize),
1800+
Type: objabi.R_ADDRCUOFF,
1801+
Add: int64(addr),
1802+
Sym: fn,
1803+
})
1804+
}
1805+
1806+
for i := 0; i < len(list.P); {
1807+
first := readPtr(ctxt, list.P[i:])
1808+
second := readPtr(ctxt, list.P[i+ctxt.Arch.PtrSize:])
1809+
1810+
if first == 0 ||
1811+
first == ^uint64(0) ||
1812+
(ctxt.Arch.PtrSize == 4 && first == uint64(^uint32(0))) {
1813+
// Base address selection entry or end of list. Ignore.
1814+
i += ctxt.Arch.PtrSize * 2
1815+
continue
1816+
}
1817+
1818+
relocate(first, i)
1819+
relocate(second, i+ctxt.Arch.PtrSize)
1820+
1821+
// Skip past the actual location.
1822+
i += ctxt.Arch.PtrSize * 2
1823+
i += 2 + int(ctxt.Arch.ByteOrder.Uint16(list.P[i:]))
1824+
}
1825+
1826+
// Rewrite the DIE's relocations to point to the first location entry,
1827+
// not the now-useless base address selection entry.
1828+
for i := range info.R {
1829+
r := &info.R[i]
1830+
if r.Sym != list {
1831+
continue
1832+
}
1833+
r.Add += int64(2 * ctxt.Arch.PtrSize)
1834+
}
1835+
}
1836+
1837+
// Read a pointer-sized uint from the beginning of buf.
1838+
func readPtr(ctxt *Link, buf []byte) uint64 {
1839+
switch ctxt.Arch.PtrSize {
1840+
case 4:
1841+
return uint64(ctxt.Arch.ByteOrder.Uint32(buf))
1842+
case 8:
1843+
return ctxt.Arch.ByteOrder.Uint64(buf)
1844+
default:
1845+
panic("unexpected pointer size")
1846+
}
1847+
}
1848+
17781849
/*
17791850
* Elf.
17801851
*/

0 commit comments

Comments
 (0)