From: Heschi Kreinick Date: Wed, 24 Jan 2018 18:26:15 +0000 (-0500) Subject: cmd/link: fix up location lists for dsymutil X-Git-Tag: go1.11beta1~1430 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=230b0bad1f9685e824c9096deb4badbe93377733;p=gostls13.git 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 --- diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index ae0d3c07a3..116a8493ff 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -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. */