Commit 230b0bad authored by Heschi Kreinick's avatar Heschi Kreinick

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/89535Reviewed-by: 's avatarDavid Chase <drchase@google.com>
parent 5b21bf6f
......@@ -1759,6 +1759,10 @@ func collectlocs(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit) []*sy
reloc.Sym.Attr |= sym.AttrReachable | sym.AttrNotInSymbolTable
syms = append(syms, reloc.Sym)
empty = false
// LLVM doesn't support base address entries. Strip them out so LLDB and dsymutil don't get confused.
if ctxt.HeadType == objabi.Hdarwin {
removeLocationListBaseAddress(ctxt, fn, reloc.Sym)
}
// One location list entry per function, but many relocations to it. Don't duplicate.
break
}
......@@ -1775,6 +1779,73 @@ func collectlocs(ctxt *Link, syms []*sym.Symbol, units []*compilationUnit) []*sy
return syms
}
func removeLocationListBaseAddress(ctxt *Link, info, list *sym.Symbol) {
// The list symbol contains multiple lists, but they're all for the
// same function, and it's not empty.
fn := list.R[0].Sym
// Discard the relocations for the base address entries.
list.R = list.R[:0]
// Add relocations for each location entry's start and end addresses,
// so that the base address entries aren't necessary.
// We could remove them entirely, but that's more work for a relatively
// small size win. If dsymutil runs it'll throw them away anyway.
// relocate adds a CU-relative relocation to fn+addr at offset.
relocate := func(addr uint64, offset int) {
list.R = append(list.R, sym.Reloc{
Off: int32(offset),
Siz: uint8(ctxt.Arch.PtrSize),
Type: objabi.R_ADDRCUOFF,
Add: int64(addr),
Sym: fn,
})
}
for i := 0; i < len(list.P); {
first := readPtr(ctxt, list.P[i:])
second := readPtr(ctxt, list.P[i+ctxt.Arch.PtrSize:])
if first == 0 ||
first == ^uint64(0) ||
(ctxt.Arch.PtrSize == 4 && first == uint64(^uint32(0))) {
// Base address selection entry or end of list. Ignore.
i += ctxt.Arch.PtrSize * 2
continue
}
relocate(first, i)
relocate(second, i+ctxt.Arch.PtrSize)
// Skip past the actual location.
i += ctxt.Arch.PtrSize * 2
i += 2 + int(ctxt.Arch.ByteOrder.Uint16(list.P[i:]))
}
// Rewrite the DIE's relocations to point to the first location entry,
// not the now-useless base address selection entry.
for i := range info.R {
r := &info.R[i]
if r.Sym != list {
continue
}
r.Add += int64(2 * ctxt.Arch.PtrSize)
}
}
// Read a pointer-sized uint from the beginning of buf.
func readPtr(ctxt *Link, buf []byte) uint64 {
switch ctxt.Arch.PtrSize {
case 4:
return uint64(ctxt.Arch.ByteOrder.Uint32(buf))
case 8:
return ctxt.Arch.ByteOrder.Uint64(buf)
default:
panic("unexpected pointer size")
}
}
/*
* Elf.
*/
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment