Commit 3601a1e7 authored by David Crawshaw's avatar David Crawshaw

cmd/link: write DWARF PC table without seeking

This per-symbol table was written with the strategy:

	1. record offset and write fake header
	2. write body
	3. seek back to fake header
	4. write real header

This CL collects the per-symbol body into a []byte, then writes the
real header followed by the body to the output file. This saves two
seeks per-symbol and overwriting the fake header.

Small performance improvement (3.5%) in best-of-ten links of godoc:

tip:  real 0m1.132s user 0m1.256s
this: real 0m1.090s user 0m1.210s

I'm not sure if the performance measured here alone justifies it,
but I think this is an easier to read style of code.

Change-Id: I1663901eb7c2ee330591b8b6550cdff0402ed5dc
Reviewed-on: https://go-review.googlesource.com/20074Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 021e0c5f
...@@ -111,64 +111,47 @@ func addrput(addr int64) { ...@@ -111,64 +111,47 @@ func addrput(addr int64) {
} }
} }
func uleb128enc(v uint64, dst []byte) int { func appendUleb128(b []byte, v uint64) []byte {
var c uint8
length := uint8(0)
for { for {
c = uint8(v & 0x7f) c := uint8(v & 0x7f)
v >>= 7 v >>= 7
if v != 0 { if v != 0 {
c |= 0x80 c |= 0x80
} }
if dst != nil { b = append(b, c)
dst[0] = byte(c)
dst = dst[1:]
}
length++
if c&0x80 == 0 { if c&0x80 == 0 {
break break
} }
} }
return b
return int(length)
} }
func sleb128enc(v int64, dst []byte) int { func appendSleb128(b []byte, v int64) []byte {
var c uint8
var s uint8
length := uint8(0)
for { for {
c = uint8(v & 0x7f) c := uint8(v & 0x7f)
s = uint8(v & 0x40) s := uint8(v & 0x40)
v >>= 7 v >>= 7
if (v != -1 || s == 0) && (v != 0 || s != 0) { if (v != -1 || s == 0) && (v != 0 || s != 0) {
c |= 0x80 c |= 0x80
} }
if dst != nil { b = append(b, c)
dst[0] = byte(c)
dst = dst[1:]
}
length++
if c&0x80 == 0 { if c&0x80 == 0 {
break break
} }
} }
return b
return int(length)
} }
var encbuf [10]byte var encbuf [10]byte
func uleb128put(v int64) { func uleb128put(v int64) {
n := uleb128enc(uint64(v), encbuf[:]) b := appendUleb128(encbuf[:0], uint64(v))
Cwrite(encbuf[:n]) Cwrite(b)
} }
func sleb128put(v int64) { func sleb128put(v int64) {
n := sleb128enc(v, encbuf[:]) b := appendSleb128(encbuf[:0], v)
Cwrite(encbuf[:n]) Cwrite(b)
} }
/* /*
...@@ -892,12 +875,9 @@ func reversetree(list **DWDie) { ...@@ -892,12 +875,9 @@ func reversetree(list **DWDie) {
func newmemberoffsetattr(die *DWDie, offs int32) { func newmemberoffsetattr(die *DWDie, offs int32) {
var block [20]byte var block [20]byte
b := append(block[:0], DW_OP_plus_uconst)
i := 0 b = appendUleb128(b, uint64(offs))
block[i] = DW_OP_plus_uconst newattr(die, DW_AT_data_member_location, DW_CLS_BLOCK, int64(len(b)), b)
i++
i += uleb128enc(uint64(offs), block[i:])
newattr(die, DW_AT_data_member_location, DW_CLS_BLOCK, int64(i), block[:i])
} }
// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a // GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a
...@@ -1462,20 +1442,15 @@ func putpclcdelta(delta_pc int64, delta_lc int64) { ...@@ -1462,20 +1442,15 @@ func putpclcdelta(delta_pc int64, delta_lc int64) {
func newcfaoffsetattr(die *DWDie, offs int32) { func newcfaoffsetattr(die *DWDie, offs int32) {
var block [20]byte var block [20]byte
b := append(block[:0], DW_OP_call_frame_cfa)
i := 0
block[i] = DW_OP_call_frame_cfa
i++
if offs != 0 { if offs != 0 {
block[i] = DW_OP_consts b = append(b, DW_OP_consts)
i++ b = appendSleb128(b, int64(offs))
i += sleb128enc(int64(offs), block[i:]) b = append(b, DW_OP_plus)
block[i] = DW_OP_plus
i++
} }
newattr(die, DW_AT_location, DW_CLS_BLOCK, int64(i), block[:i]) newattr(die, DW_AT_location, DW_CLS_BLOCK, int64(len(b)), b)
} }
func mkvarname(name string, da int) string { func mkvarname(name string, da int) string {
...@@ -1719,22 +1694,25 @@ const ( ...@@ -1719,22 +1694,25 @@ const (
DATAALIGNMENTFACTOR = -4 DATAALIGNMENTFACTOR = -4
) )
func putpccfadelta(deltapc int64, cfa int64) { // appendPCDeltaCFA appends per-PC CFA deltas to b and returns the final slice.
Cput(DW_CFA_def_cfa_offset_sf) func appendPCDeltaCFA(b []byte, deltapc, cfa int64) []byte {
sleb128put(cfa / DATAALIGNMENTFACTOR) b = append(b, DW_CFA_def_cfa_offset_sf)
b = appendSleb128(b, cfa/DATAALIGNMENTFACTOR)
if deltapc < 0x40 {
Cput(uint8(DW_CFA_advance_loc + deltapc)) switch {
} else if deltapc < 0x100 { case deltapc < 0x40:
Cput(DW_CFA_advance_loc1) b = append(b, uint8(DW_CFA_advance_loc+deltapc))
Cput(uint8(deltapc)) case deltapc < 0x100:
} else if deltapc < 0x10000 { b = append(b, DW_CFA_advance_loc1)
Cput(DW_CFA_advance_loc2) b = append(b, uint8(deltapc))
Thearch.Wput(uint16(deltapc)) case deltapc < 0x10000:
} else { b = append(b, DW_CFA_advance_loc2)
Cput(DW_CFA_advance_loc4) b = Thearch.Append16(b, uint16(deltapc))
Thearch.Lput(uint32(deltapc)) default:
b = append(b, DW_CFA_advance_loc4)
b = Thearch.Append32(b, uint32(deltapc))
} }
return b
} }
func writeframes() { func writeframes() {
...@@ -1779,6 +1757,7 @@ func writeframes() { ...@@ -1779,6 +1757,7 @@ func writeframes() {
strnput("", int(pad)) strnput("", int(pad))
var deltaBuf []byte
var pcsp Pciter var pcsp Pciter
for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next { for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
s := Ctxt.Cursym s := Ctxt.Cursym
...@@ -1786,14 +1765,9 @@ func writeframes() { ...@@ -1786,14 +1765,9 @@ func writeframes() {
continue continue
} }
fdeo := Cpos() // Emit a FDE, Section 6.4.1.
// First build the section contents into a byte buffer.
// Emit a FDE, Section 6.4.1, starting wit a placeholder. deltaBuf = deltaBuf[:0]
Thearch.Lput(0) // length, must be multiple of thearch.ptrsize
Thearch.Lput(0) // Pointer to the CIE above, at offset 0
addrput(0) // initial location
addrput(0) // address range
for pciterinit(Ctxt, &pcsp, &s.Pcln.Pcsp); pcsp.done == 0; pciternext(&pcsp) { for pciterinit(Ctxt, &pcsp, &s.Pcln.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
nextpc := pcsp.nextpc nextpc := pcsp.nextpc
...@@ -1807,31 +1781,30 @@ func writeframes() { ...@@ -1807,31 +1781,30 @@ func writeframes() {
} }
if haslinkregister() { if haslinkregister() {
putpccfadelta(int64(nextpc)-int64(pcsp.pc), int64(pcsp.value)) deltaBuf = appendPCDeltaCFA(deltaBuf, int64(nextpc)-int64(pcsp.pc), int64(pcsp.value))
} else { } else {
putpccfadelta(int64(nextpc)-int64(pcsp.pc), int64(Thearch.Ptrsize)+int64(pcsp.value)) deltaBuf = appendPCDeltaCFA(deltaBuf, int64(nextpc)-int64(pcsp.pc), int64(Thearch.Ptrsize)+int64(pcsp.value))
} }
} }
pad := int(Rnd(int64(len(deltaBuf)), int64(Thearch.Ptrsize))) - len(deltaBuf)
deltaBuf = append(deltaBuf, zeros[:pad]...)
fdesize := Cpos() - fdeo - 4 // exclude the length field. // Emit the FDE header, Section 6.4.1.
pad = Rnd(fdesize, int64(Thearch.Ptrsize)) - fdesize // 4 bytes: length, must be multiple of thearch.ptrsize
strnput("", int(pad)) // 4 bytes: Pointer to the CIE above, at offset 0
fdesize += pad // ptrsize: initial location
// ptrsize: address range
// Emit the FDE header for real, Section 6.4.1. Thearch.Lput(uint32(4 + 2*Thearch.Ptrsize + len(deltaBuf))) // length (excludes itself)
Cseek(fdeo)
Thearch.Lput(uint32(fdesize))
if Linkmode == LinkExternal { if Linkmode == LinkExternal {
adddwarfrel(framesec, framesym, frameo, 4, 0) adddwarfrel(framesec, framesym, frameo, 4, 0) // CIE offset
adddwarfrel(framesec, s, frameo, Thearch.Ptrsize, 0) adddwarfrel(framesec, s, frameo, Thearch.Ptrsize, 0) // initial location
} else { } else {
Thearch.Lput(0) Thearch.Lput(0) // CIE offset
addrput(s.Value) addrput(s.Value) // initial location
} }
addrput(s.Size) // address range
addrput(s.Size) Cwrite(deltaBuf)
Cseek(fdeo + 4 + fdesize)
} }
Cflush() Cflush()
......
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