2016-03-01 22:57:46 +00:00
|
|
|
// Copyright 2013 The Go Authors. All rights reserved.
|
2015-01-19 14:34:58 -05:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
2015-03-05 13:57:36 -05:00
|
|
|
// Writing of Go object files.
|
|
|
|
|
|
2015-01-19 14:34:58 -05:00
|
|
|
package obj
|
|
|
|
|
|
|
|
|
|
import (
|
2016-03-31 12:59:05 +03:00
|
|
|
"bufio"
|
2016-07-28 13:04:41 -04:00
|
|
|
"cmd/internal/dwarf"
|
2017-04-18 12:53:25 -07:00
|
|
|
"cmd/internal/objabi"
|
2016-04-06 12:01:40 -07:00
|
|
|
"cmd/internal/sys"
|
2015-01-19 14:34:58 -05:00
|
|
|
"fmt"
|
|
|
|
|
"log"
|
|
|
|
|
"path/filepath"
|
2016-03-13 10:13:03 -07:00
|
|
|
"sort"
|
2015-01-19 14:34:58 -05:00
|
|
|
)
|
|
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
// objWriter writes Go object files.
|
|
|
|
|
type objWriter struct {
|
|
|
|
|
wr *bufio.Writer
|
|
|
|
|
ctxt *Link
|
|
|
|
|
// Temporary buffer for zigzag int writing.
|
|
|
|
|
varintbuf [10]uint8
|
|
|
|
|
|
2017-03-05 09:14:38 -08:00
|
|
|
// Provide the index of a symbol reference by symbol name.
|
2016-03-31 12:59:05 +03:00
|
|
|
// One map for versioned symbols and one for unversioned symbols.
|
|
|
|
|
// Used for deduplicating the symbol reference list.
|
|
|
|
|
refIdx map[string]int
|
|
|
|
|
vrefIdx map[string]int
|
|
|
|
|
|
|
|
|
|
// Number of objects written of each type.
|
|
|
|
|
nRefs int
|
|
|
|
|
nData int
|
|
|
|
|
nReloc int
|
|
|
|
|
nPcdata int
|
|
|
|
|
nAutom int
|
|
|
|
|
nFuncdata int
|
|
|
|
|
nFile int
|
2016-03-23 00:44:07 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
func (w *objWriter) addLengths(s *LSym) {
|
|
|
|
|
w.nData += len(s.P)
|
|
|
|
|
w.nReloc += len(s.R)
|
2016-03-23 00:44:07 +02:00
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
if s.Type != objabi.STEXT {
|
2016-03-23 00:44:07 +02:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-18 10:18:34 -07:00
|
|
|
pc := &s.Func.Pcln
|
2016-03-23 00:44:07 +02:00
|
|
|
|
|
|
|
|
data := 0
|
|
|
|
|
data += len(pc.Pcsp.P)
|
|
|
|
|
data += len(pc.Pcfile.P)
|
|
|
|
|
data += len(pc.Pcline.P)
|
cmd/compile,link: generate PC-value tables with inlining information
In order to generate accurate tracebacks, the runtime needs to know the
inlined call stack for a given PC. This creates two tables per function
for this purpose. The first table is the inlining tree (stored in the
function's funcdata), which has a node containing the file, line, and
function name for every inlined call. The second table is a PC-value
table that maps each PC to a node in the inlining tree (or -1 if the PC
is not the result of inlining).
To give the appearance that inlining hasn't happened, the runtime also
needs the original source position information of inlined AST nodes.
Previously the compiler plastered over the line numbers of inlined AST
nodes with the line number of the call. This meant that the PC-line
table mapped each PC to line number of the outermost call in its inlined
call stack, with no way to access the innermost line number.
Now the compiler retains line numbers of inlined AST nodes and writes
the innermost source position information to the PC-line and PC-file
tables. Some tools and tests expect to see outermost line numbers, so we
provide the OutermostLine function for displaying line info.
To keep track of the inlined call stack for an AST node, we extend the
src.PosBase type with an index into a global inlining tree. Every time
the compiler inlines a call, it creates a node in the global inlining
tree for the call, and writes its index to the PosBase of every inlined
AST node. The parent of this node is the inlining tree index of the
call. -1 signifies no parent.
For each function, the compiler creates a local inlining tree and a
PC-value table mapping each PC to an index in the local tree. These are
written to an object file, which is read by the linker. The linker
re-encodes these tables compactly by deduplicating function names and
file names.
This change increases the size of binaries by 4-5%. For example, this is
how the go1 benchmark binary is impacted by this change:
section old bytes new bytes delta
.text 3.49M ± 0% 3.49M ± 0% +0.06%
.rodata 1.12M ± 0% 1.21M ± 0% +8.21%
.gopclntab 1.50M ± 0% 1.68M ± 0% +11.89%
.debug_line 338k ± 0% 435k ± 0% +28.78%
Total 9.21M ± 0% 9.58M ± 0% +4.01%
Updates #19348.
Change-Id: Ic4f180c3b516018138236b0c35e0218270d957d3
Reviewed-on: https://go-review.googlesource.com/37231
Run-TryBot: David Lazar <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
|
|
|
data += len(pc.Pcinline.P)
|
2016-03-23 00:44:07 +02:00
|
|
|
for i := 0; i < len(pc.Pcdata); i++ {
|
|
|
|
|
data += len(pc.Pcdata[i].P)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
w.nData += data
|
|
|
|
|
w.nPcdata += len(pc.Pcdata)
|
2016-03-23 00:44:07 +02:00
|
|
|
|
2017-04-18 10:18:34 -07:00
|
|
|
w.nAutom += len(s.Func.Autom)
|
2016-03-31 12:59:05 +03:00
|
|
|
w.nFuncdata += len(pc.Funcdataoff)
|
|
|
|
|
w.nFile += len(pc.File)
|
2016-03-23 00:44:07 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
func (w *objWriter) writeLengths() {
|
|
|
|
|
w.writeInt(int64(w.nData))
|
|
|
|
|
w.writeInt(int64(w.nReloc))
|
|
|
|
|
w.writeInt(int64(w.nPcdata))
|
|
|
|
|
w.writeInt(int64(w.nAutom))
|
|
|
|
|
w.writeInt(int64(w.nFuncdata))
|
|
|
|
|
w.writeInt(int64(w.nFile))
|
2016-03-23 00:44:07 +02:00
|
|
|
}
|
|
|
|
|
|
2016-04-12 17:58:46 -07:00
|
|
|
func newObjWriter(ctxt *Link, b *bufio.Writer) *objWriter {
|
2016-03-31 12:59:05 +03:00
|
|
|
return &objWriter{
|
|
|
|
|
ctxt: ctxt,
|
2016-04-12 17:58:46 -07:00
|
|
|
wr: b,
|
2016-03-31 12:59:05 +03:00
|
|
|
vrefIdx: make(map[string]int),
|
|
|
|
|
refIdx: make(map[string]int),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-12 17:58:46 -07:00
|
|
|
func WriteObjFile(ctxt *Link, b *bufio.Writer) {
|
2016-03-31 12:59:05 +03:00
|
|
|
w := newObjWriter(ctxt, b)
|
2015-01-19 14:34:58 -05:00
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
// Magic header
|
2017-03-06 10:51:37 -08:00
|
|
|
w.wr.WriteString("\x00\x00go19ld")
|
2015-01-19 14:34:58 -05:00
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
// Version
|
|
|
|
|
w.wr.WriteByte(1)
|
|
|
|
|
|
|
|
|
|
// Autolib
|
2015-03-08 22:41:48 -04:00
|
|
|
for _, pkg := range ctxt.Imports {
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeString(pkg)
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeString("")
|
2016-03-23 00:44:07 +02:00
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
// Symbol references
|
2016-03-14 21:51:09 -07:00
|
|
|
for _, s := range ctxt.Text {
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeRefs(s)
|
|
|
|
|
w.addLengths(s)
|
2016-03-14 22:57:58 +02:00
|
|
|
}
|
2016-03-14 21:51:09 -07:00
|
|
|
for _, s := range ctxt.Data {
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeRefs(s)
|
|
|
|
|
w.addLengths(s)
|
2016-03-14 22:57:58 +02:00
|
|
|
}
|
2016-03-31 12:59:05 +03:00
|
|
|
// End symbol references
|
|
|
|
|
w.wr.WriteByte(0xff)
|
2016-03-14 22:57:58 +02:00
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
// Lengths
|
|
|
|
|
w.writeLengths()
|
2016-03-23 00:44:07 +02:00
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
// Data block
|
2016-03-21 10:55:20 +13:00
|
|
|
for _, s := range ctxt.Text {
|
2016-03-31 12:59:05 +03:00
|
|
|
w.wr.Write(s.P)
|
2017-04-18 10:18:34 -07:00
|
|
|
pc := &s.Func.Pcln
|
2016-03-31 12:59:05 +03:00
|
|
|
w.wr.Write(pc.Pcsp.P)
|
|
|
|
|
w.wr.Write(pc.Pcfile.P)
|
|
|
|
|
w.wr.Write(pc.Pcline.P)
|
cmd/compile,link: generate PC-value tables with inlining information
In order to generate accurate tracebacks, the runtime needs to know the
inlined call stack for a given PC. This creates two tables per function
for this purpose. The first table is the inlining tree (stored in the
function's funcdata), which has a node containing the file, line, and
function name for every inlined call. The second table is a PC-value
table that maps each PC to a node in the inlining tree (or -1 if the PC
is not the result of inlining).
To give the appearance that inlining hasn't happened, the runtime also
needs the original source position information of inlined AST nodes.
Previously the compiler plastered over the line numbers of inlined AST
nodes with the line number of the call. This meant that the PC-line
table mapped each PC to line number of the outermost call in its inlined
call stack, with no way to access the innermost line number.
Now the compiler retains line numbers of inlined AST nodes and writes
the innermost source position information to the PC-line and PC-file
tables. Some tools and tests expect to see outermost line numbers, so we
provide the OutermostLine function for displaying line info.
To keep track of the inlined call stack for an AST node, we extend the
src.PosBase type with an index into a global inlining tree. Every time
the compiler inlines a call, it creates a node in the global inlining
tree for the call, and writes its index to the PosBase of every inlined
AST node. The parent of this node is the inlining tree index of the
call. -1 signifies no parent.
For each function, the compiler creates a local inlining tree and a
PC-value table mapping each PC to an index in the local tree. These are
written to an object file, which is read by the linker. The linker
re-encodes these tables compactly by deduplicating function names and
file names.
This change increases the size of binaries by 4-5%. For example, this is
how the go1 benchmark binary is impacted by this change:
section old bytes new bytes delta
.text 3.49M ± 0% 3.49M ± 0% +0.06%
.rodata 1.12M ± 0% 1.21M ± 0% +8.21%
.gopclntab 1.50M ± 0% 1.68M ± 0% +11.89%
.debug_line 338k ± 0% 435k ± 0% +28.78%
Total 9.21M ± 0% 9.58M ± 0% +4.01%
Updates #19348.
Change-Id: Ic4f180c3b516018138236b0c35e0218270d957d3
Reviewed-on: https://go-review.googlesource.com/37231
Run-TryBot: David Lazar <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
|
|
|
w.wr.Write(pc.Pcinline.P)
|
2016-03-21 10:55:20 +13:00
|
|
|
for i := 0; i < len(pc.Pcdata); i++ {
|
2016-03-31 12:59:05 +03:00
|
|
|
w.wr.Write(pc.Pcdata[i].P)
|
2016-03-21 10:55:20 +13:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for _, s := range ctxt.Data {
|
cmd/internal/obj: fix LSym.Type during compilation, not linking
Prior to this CL, the compiler and assembler
were sloppy about the LSym.Type for LSyms
containing static data.
The linker then fixed this up, converting
Sxxx and SBSS to SDATA, and SNOPTRBSS to SNOPTRDATA
if it noticed that the symbol had associated data.
It is preferable to just get this right in cmd/compile
and cmd/asm, because it removes an unnecessary traversal
of the symbol table from the linker (see #14624).
Do this by touching up the LSym.Type fixes in
LSym.prepwrite and Link.Globl.
I have confirmed by instrumenting the linker
that the now-eliminated code paths were unreached.
And an additional check in the object file writing code
will help preserve that invariant.
There was a case in the Windows linker,
with internal linking and cgo,
where we were generating SNOPTRBSS symbols with data.
For now, convert those at the site at which they occur
into SNOPTRDATA, just like they were.
Does not pass toolstash-check,
but does generate identical linked binaries.
No compiler performance changes.
Change-Id: I77b071ab103685ff8e042cee9abb864385488872
Reviewed-on: https://go-review.googlesource.com/40864
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Alex Brainman <alex.brainman@gmail.com>
Reviewed-by: Michael Hudson-Doyle <michael.hudson@canonical.com>
2017-04-16 08:22:44 -07:00
|
|
|
if len(s.P) > 0 {
|
|
|
|
|
switch s.Type {
|
|
|
|
|
case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS:
|
|
|
|
|
ctxt.Diag("cannot provide data for %v sym %v", s.Type, s.Name)
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-31 12:59:05 +03:00
|
|
|
w.wr.Write(s.P)
|
2016-03-21 10:55:20 +13:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
// Symbols
|
2016-03-14 21:51:09 -07:00
|
|
|
for _, s := range ctxt.Text {
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeSym(s)
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
2016-03-14 21:51:09 -07:00
|
|
|
for _, s := range ctxt.Data {
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeSym(s)
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
// Magic footer
|
2017-03-06 10:51:37 -08:00
|
|
|
w.wr.WriteString("\xff\xffgo19ld")
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
// Symbols are prefixed so their content doesn't get confused with the magic footer.
|
|
|
|
|
const symPrefix = 0xfe
|
2016-03-17 13:18:34 +02:00
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
func (w *objWriter) writeRef(s *LSym, isPath bool) {
|
2016-03-14 22:57:58 +02:00
|
|
|
if s == nil || s.RefIdx != 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
2016-03-17 13:18:34 +02:00
|
|
|
var m map[string]int
|
2017-04-20 07:13:02 -07:00
|
|
|
if !s.Static() {
|
2016-03-31 12:59:05 +03:00
|
|
|
m = w.refIdx
|
2017-04-20 07:13:02 -07:00
|
|
|
} else {
|
2016-03-31 12:59:05 +03:00
|
|
|
m = w.vrefIdx
|
2016-03-17 13:18:34 +02:00
|
|
|
}
|
|
|
|
|
|
2017-04-20 07:13:02 -07:00
|
|
|
if idx := m[s.Name]; idx != 0 {
|
2016-03-17 13:18:34 +02:00
|
|
|
s.RefIdx = idx
|
|
|
|
|
return
|
|
|
|
|
}
|
2016-03-31 12:59:05 +03:00
|
|
|
w.wr.WriteByte(symPrefix)
|
2016-03-14 22:57:58 +02:00
|
|
|
if isPath {
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeString(filepath.ToSlash(s.Name))
|
2016-03-14 22:57:58 +02:00
|
|
|
} else {
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeString(s.Name)
|
2016-03-14 22:57:58 +02:00
|
|
|
}
|
2017-04-20 07:13:02 -07:00
|
|
|
// Write "version".
|
|
|
|
|
if s.Static() {
|
|
|
|
|
w.writeInt(1)
|
|
|
|
|
} else {
|
|
|
|
|
w.writeInt(0)
|
|
|
|
|
}
|
2016-03-31 12:59:05 +03:00
|
|
|
w.nRefs++
|
|
|
|
|
s.RefIdx = w.nRefs
|
|
|
|
|
m[s.Name] = w.nRefs
|
2016-03-14 22:57:58 +02:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
func (w *objWriter) writeRefs(s *LSym) {
|
|
|
|
|
w.writeRef(s, false)
|
|
|
|
|
w.writeRef(s.Gotype, false)
|
2016-03-14 22:57:58 +02:00
|
|
|
for i := range s.R {
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeRef(s.R[i].Sym, false)
|
2016-03-14 22:57:58 +02:00
|
|
|
}
|
|
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
if s.Type == objabi.STEXT {
|
2017-04-18 10:18:34 -07:00
|
|
|
for _, a := range s.Func.Autom {
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeRef(a.Asym, false)
|
|
|
|
|
w.writeRef(a.Gotype, false)
|
2016-03-14 22:57:58 +02:00
|
|
|
}
|
2017-04-18 10:18:34 -07:00
|
|
|
pc := &s.Func.Pcln
|
2016-03-14 22:57:58 +02:00
|
|
|
for _, d := range pc.Funcdata {
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeRef(d, false)
|
2016-03-14 22:57:58 +02:00
|
|
|
}
|
|
|
|
|
for _, f := range pc.File {
|
2017-04-20 07:13:02 -07:00
|
|
|
fsym := w.ctxt.Lookup(f)
|
2017-04-03 07:50:56 -07:00
|
|
|
w.writeRef(fsym, true)
|
2016-03-14 22:57:58 +02:00
|
|
|
}
|
cmd/compile,link: generate PC-value tables with inlining information
In order to generate accurate tracebacks, the runtime needs to know the
inlined call stack for a given PC. This creates two tables per function
for this purpose. The first table is the inlining tree (stored in the
function's funcdata), which has a node containing the file, line, and
function name for every inlined call. The second table is a PC-value
table that maps each PC to a node in the inlining tree (or -1 if the PC
is not the result of inlining).
To give the appearance that inlining hasn't happened, the runtime also
needs the original source position information of inlined AST nodes.
Previously the compiler plastered over the line numbers of inlined AST
nodes with the line number of the call. This meant that the PC-line
table mapped each PC to line number of the outermost call in its inlined
call stack, with no way to access the innermost line number.
Now the compiler retains line numbers of inlined AST nodes and writes
the innermost source position information to the PC-line and PC-file
tables. Some tools and tests expect to see outermost line numbers, so we
provide the OutermostLine function for displaying line info.
To keep track of the inlined call stack for an AST node, we extend the
src.PosBase type with an index into a global inlining tree. Every time
the compiler inlines a call, it creates a node in the global inlining
tree for the call, and writes its index to the PosBase of every inlined
AST node. The parent of this node is the inlining tree index of the
call. -1 signifies no parent.
For each function, the compiler creates a local inlining tree and a
PC-value table mapping each PC to an index in the local tree. These are
written to an object file, which is read by the linker. The linker
re-encodes these tables compactly by deduplicating function names and
file names.
This change increases the size of binaries by 4-5%. For example, this is
how the go1 benchmark binary is impacted by this change:
section old bytes new bytes delta
.text 3.49M ± 0% 3.49M ± 0% +0.06%
.rodata 1.12M ± 0% 1.21M ± 0% +8.21%
.gopclntab 1.50M ± 0% 1.68M ± 0% +11.89%
.debug_line 338k ± 0% 435k ± 0% +28.78%
Total 9.21M ± 0% 9.58M ± 0% +4.01%
Updates #19348.
Change-Id: Ic4f180c3b516018138236b0c35e0218270d957d3
Reviewed-on: https://go-review.googlesource.com/37231
Run-TryBot: David Lazar <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
|
|
|
for _, call := range pc.InlTree.nodes {
|
|
|
|
|
w.writeRef(call.Func, false)
|
|
|
|
|
f, _ := linkgetlineFromPos(w.ctxt, call.Pos)
|
2017-04-20 07:13:02 -07:00
|
|
|
fsym := w.ctxt.Lookup(f)
|
2017-04-03 07:50:56 -07:00
|
|
|
w.writeRef(fsym, true)
|
cmd/compile,link: generate PC-value tables with inlining information
In order to generate accurate tracebacks, the runtime needs to know the
inlined call stack for a given PC. This creates two tables per function
for this purpose. The first table is the inlining tree (stored in the
function's funcdata), which has a node containing the file, line, and
function name for every inlined call. The second table is a PC-value
table that maps each PC to a node in the inlining tree (or -1 if the PC
is not the result of inlining).
To give the appearance that inlining hasn't happened, the runtime also
needs the original source position information of inlined AST nodes.
Previously the compiler plastered over the line numbers of inlined AST
nodes with the line number of the call. This meant that the PC-line
table mapped each PC to line number of the outermost call in its inlined
call stack, with no way to access the innermost line number.
Now the compiler retains line numbers of inlined AST nodes and writes
the innermost source position information to the PC-line and PC-file
tables. Some tools and tests expect to see outermost line numbers, so we
provide the OutermostLine function for displaying line info.
To keep track of the inlined call stack for an AST node, we extend the
src.PosBase type with an index into a global inlining tree. Every time
the compiler inlines a call, it creates a node in the global inlining
tree for the call, and writes its index to the PosBase of every inlined
AST node. The parent of this node is the inlining tree index of the
call. -1 signifies no parent.
For each function, the compiler creates a local inlining tree and a
PC-value table mapping each PC to an index in the local tree. These are
written to an object file, which is read by the linker. The linker
re-encodes these tables compactly by deduplicating function names and
file names.
This change increases the size of binaries by 4-5%. For example, this is
how the go1 benchmark binary is impacted by this change:
section old bytes new bytes delta
.text 3.49M ± 0% 3.49M ± 0% +0.06%
.rodata 1.12M ± 0% 1.21M ± 0% +8.21%
.gopclntab 1.50M ± 0% 1.68M ± 0% +11.89%
.debug_line 338k ± 0% 435k ± 0% +28.78%
Total 9.21M ± 0% 9.58M ± 0% +4.01%
Updates #19348.
Change-Id: Ic4f180c3b516018138236b0c35e0218270d957d3
Reviewed-on: https://go-review.googlesource.com/37231
Run-TryBot: David Lazar <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
|
|
|
}
|
2016-03-14 22:57:58 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
func (w *objWriter) writeSymDebug(s *LSym) {
|
|
|
|
|
ctxt := w.ctxt
|
|
|
|
|
fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
|
|
|
|
|
if s.Type != 0 {
|
2017-04-16 14:48:16 -07:00
|
|
|
fmt.Fprintf(ctxt.Bso, "%v ", s.Type)
|
2016-03-31 12:59:05 +03:00
|
|
|
}
|
2017-04-20 07:13:02 -07:00
|
|
|
if s.Static() {
|
|
|
|
|
fmt.Fprint(ctxt.Bso, "static ")
|
|
|
|
|
}
|
2016-10-24 23:15:41 +03:00
|
|
|
if s.DuplicateOK() {
|
2016-03-31 12:59:05 +03:00
|
|
|
fmt.Fprintf(ctxt.Bso, "dupok ")
|
|
|
|
|
}
|
2016-10-24 23:15:41 +03:00
|
|
|
if s.CFunc() {
|
2016-03-31 12:59:05 +03:00
|
|
|
fmt.Fprintf(ctxt.Bso, "cfunc ")
|
|
|
|
|
}
|
2016-10-24 23:15:41 +03:00
|
|
|
if s.NoSplit() {
|
2016-03-31 12:59:05 +03:00
|
|
|
fmt.Fprintf(ctxt.Bso, "nosplit ")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(ctxt.Bso, "size=%d", s.Size)
|
2017-04-18 12:53:25 -07:00
|
|
|
if s.Type == objabi.STEXT {
|
2017-04-18 10:18:34 -07:00
|
|
|
fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Func.Args), uint64(s.Func.Locals))
|
2016-10-24 23:15:41 +03:00
|
|
|
if s.Leaf() {
|
2016-03-31 12:59:05 +03:00
|
|
|
fmt.Fprintf(ctxt.Bso, " leaf")
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
2016-03-31 12:59:05 +03:00
|
|
|
}
|
|
|
|
|
fmt.Fprintf(ctxt.Bso, "\n")
|
2017-04-18 12:53:25 -07:00
|
|
|
if s.Type == objabi.STEXT {
|
2017-04-18 10:18:34 -07:00
|
|
|
for p := s.Func.Text; p != nil; p = p.Link {
|
2017-03-03 16:45:21 -08:00
|
|
|
fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), p)
|
|
|
|
|
}
|
2016-03-31 12:59:05 +03:00
|
|
|
}
|
2017-03-03 16:45:21 -08:00
|
|
|
for i := 0; i < len(s.P); i += 16 {
|
2016-03-31 12:59:05 +03:00
|
|
|
fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
|
2017-03-03 16:45:21 -08:00
|
|
|
j := i
|
2016-03-31 12:59:05 +03:00
|
|
|
for j = i; j < i+16 && j < len(s.P); j++ {
|
|
|
|
|
fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
2016-03-31 12:59:05 +03:00
|
|
|
for ; j < i+16; j++ {
|
|
|
|
|
fmt.Fprintf(ctxt.Bso, " ")
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
2016-03-31 12:59:05 +03:00
|
|
|
fmt.Fprintf(ctxt.Bso, " ")
|
|
|
|
|
for j = i; j < i+16 && j < len(s.P); j++ {
|
2017-03-03 16:45:21 -08:00
|
|
|
c := int(s.P[j])
|
2016-03-31 12:59:05 +03:00
|
|
|
if ' ' <= c && c <= 0x7e {
|
|
|
|
|
fmt.Fprintf(ctxt.Bso, "%c", c)
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Fprintf(ctxt.Bso, ".")
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Fprintf(ctxt.Bso, "\n")
|
2016-03-31 12:59:05 +03:00
|
|
|
}
|
2015-01-19 14:34:58 -05:00
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
sort.Sort(relocByOff(s.R)) // generate stable output
|
|
|
|
|
for _, r := range s.R {
|
|
|
|
|
name := ""
|
|
|
|
|
if r.Sym != nil {
|
|
|
|
|
name = r.Sym.Name
|
2017-04-18 12:53:25 -07:00
|
|
|
} else if r.Type == objabi.R_TLS_LE {
|
2016-04-04 10:49:55 -07:00
|
|
|
name = "TLS"
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
2016-04-06 12:01:40 -07:00
|
|
|
if ctxt.Arch.InFamily(sys.ARM, sys.PPC64) {
|
2016-04-14 19:04:45 -07:00
|
|
|
fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(r.Add))
|
2016-03-31 12:59:05 +03:00
|
|
|
} else {
|
2016-04-14 19:04:45 -07:00
|
|
|
fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, r.Add)
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
}
|
2016-03-31 12:59:05 +03:00
|
|
|
}
|
2015-01-19 14:34:58 -05:00
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
func (w *objWriter) writeSym(s *LSym) {
|
|
|
|
|
ctxt := w.ctxt
|
2017-03-20 15:01:20 -07:00
|
|
|
if ctxt.Debugasm {
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeSymDebug(s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
w.wr.WriteByte(symPrefix)
|
2017-04-28 08:07:56 +12:00
|
|
|
w.wr.WriteByte(byte(s.Type))
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeRefIndex(s)
|
2016-03-28 11:34:37 +02:00
|
|
|
flags := int64(0)
|
2016-10-24 23:15:41 +03:00
|
|
|
if s.DuplicateOK() {
|
2016-03-28 11:34:37 +02:00
|
|
|
flags |= 1
|
|
|
|
|
}
|
2016-10-24 23:15:41 +03:00
|
|
|
if s.Local() {
|
2016-03-28 11:34:37 +02:00
|
|
|
flags |= 1 << 1
|
2015-04-18 08:14:08 +12:00
|
|
|
}
|
2016-10-24 23:15:41 +03:00
|
|
|
if s.MakeTypelink() {
|
2016-10-19 07:33:16 +03:00
|
|
|
flags |= 1 << 2
|
|
|
|
|
}
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeInt(flags)
|
|
|
|
|
w.writeInt(s.Size)
|
|
|
|
|
w.writeRefIndex(s.Gotype)
|
|
|
|
|
w.writeInt(int64(len(s.P)))
|
2015-01-19 14:34:58 -05:00
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeInt(int64(len(s.R)))
|
2015-02-23 16:07:24 -05:00
|
|
|
var r *Reloc
|
|
|
|
|
for i := 0; i < len(s.R); i++ {
|
2015-01-19 14:34:58 -05:00
|
|
|
r = &s.R[i]
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeInt(int64(r.Off))
|
|
|
|
|
w.writeInt(int64(r.Siz))
|
|
|
|
|
w.writeInt(int64(r.Type))
|
|
|
|
|
w.writeInt(r.Add)
|
|
|
|
|
w.writeRefIndex(r.Sym)
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
if s.Type != objabi.STEXT {
|
2016-03-31 12:59:05 +03:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-18 10:18:34 -07:00
|
|
|
w.writeInt(int64(s.Func.Args))
|
|
|
|
|
w.writeInt(int64(s.Func.Locals))
|
2016-10-24 23:15:41 +03:00
|
|
|
if s.NoSplit() {
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeInt(1)
|
|
|
|
|
} else {
|
|
|
|
|
w.writeInt(0)
|
|
|
|
|
}
|
|
|
|
|
flags = int64(0)
|
2016-10-24 23:15:41 +03:00
|
|
|
if s.Leaf() {
|
2016-03-31 12:59:05 +03:00
|
|
|
flags |= 1
|
|
|
|
|
}
|
2016-10-24 23:15:41 +03:00
|
|
|
if s.CFunc() {
|
2016-03-31 12:59:05 +03:00
|
|
|
flags |= 1 << 1
|
|
|
|
|
}
|
2016-10-24 23:15:41 +03:00
|
|
|
if s.ReflectMethod() {
|
2016-03-31 12:59:05 +03:00
|
|
|
flags |= 1 << 2
|
|
|
|
|
}
|
|
|
|
|
w.writeInt(flags)
|
2017-04-18 10:18:34 -07:00
|
|
|
w.writeInt(int64(len(s.Func.Autom)))
|
|
|
|
|
for _, a := range s.Func.Autom {
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeRefIndex(a.Asym)
|
|
|
|
|
w.writeInt(int64(a.Aoffset))
|
|
|
|
|
if a.Name == NAME_AUTO {
|
2017-04-18 12:53:25 -07:00
|
|
|
w.writeInt(objabi.A_AUTO)
|
2016-03-31 12:59:05 +03:00
|
|
|
} else if a.Name == NAME_PARAM {
|
2017-04-18 12:53:25 -07:00
|
|
|
w.writeInt(objabi.A_PARAM)
|
2016-03-28 11:34:37 +02:00
|
|
|
} else {
|
2016-03-31 12:59:05 +03:00
|
|
|
log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name)
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeRefIndex(a.Gotype)
|
|
|
|
|
}
|
2015-01-19 14:34:58 -05:00
|
|
|
|
2017-04-18 10:18:34 -07:00
|
|
|
pc := &s.Func.Pcln
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeInt(int64(len(pc.Pcsp.P)))
|
|
|
|
|
w.writeInt(int64(len(pc.Pcfile.P)))
|
|
|
|
|
w.writeInt(int64(len(pc.Pcline.P)))
|
cmd/compile,link: generate PC-value tables with inlining information
In order to generate accurate tracebacks, the runtime needs to know the
inlined call stack for a given PC. This creates two tables per function
for this purpose. The first table is the inlining tree (stored in the
function's funcdata), which has a node containing the file, line, and
function name for every inlined call. The second table is a PC-value
table that maps each PC to a node in the inlining tree (or -1 if the PC
is not the result of inlining).
To give the appearance that inlining hasn't happened, the runtime also
needs the original source position information of inlined AST nodes.
Previously the compiler plastered over the line numbers of inlined AST
nodes with the line number of the call. This meant that the PC-line
table mapped each PC to line number of the outermost call in its inlined
call stack, with no way to access the innermost line number.
Now the compiler retains line numbers of inlined AST nodes and writes
the innermost source position information to the PC-line and PC-file
tables. Some tools and tests expect to see outermost line numbers, so we
provide the OutermostLine function for displaying line info.
To keep track of the inlined call stack for an AST node, we extend the
src.PosBase type with an index into a global inlining tree. Every time
the compiler inlines a call, it creates a node in the global inlining
tree for the call, and writes its index to the PosBase of every inlined
AST node. The parent of this node is the inlining tree index of the
call. -1 signifies no parent.
For each function, the compiler creates a local inlining tree and a
PC-value table mapping each PC to an index in the local tree. These are
written to an object file, which is read by the linker. The linker
re-encodes these tables compactly by deduplicating function names and
file names.
This change increases the size of binaries by 4-5%. For example, this is
how the go1 benchmark binary is impacted by this change:
section old bytes new bytes delta
.text 3.49M ± 0% 3.49M ± 0% +0.06%
.rodata 1.12M ± 0% 1.21M ± 0% +8.21%
.gopclntab 1.50M ± 0% 1.68M ± 0% +11.89%
.debug_line 338k ± 0% 435k ± 0% +28.78%
Total 9.21M ± 0% 9.58M ± 0% +4.01%
Updates #19348.
Change-Id: Ic4f180c3b516018138236b0c35e0218270d957d3
Reviewed-on: https://go-review.googlesource.com/37231
Run-TryBot: David Lazar <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
|
|
|
w.writeInt(int64(len(pc.Pcinline.P)))
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeInt(int64(len(pc.Pcdata)))
|
|
|
|
|
for i := 0; i < len(pc.Pcdata); i++ {
|
|
|
|
|
w.writeInt(int64(len(pc.Pcdata[i].P)))
|
|
|
|
|
}
|
|
|
|
|
w.writeInt(int64(len(pc.Funcdataoff)))
|
|
|
|
|
for i := 0; i < len(pc.Funcdataoff); i++ {
|
|
|
|
|
w.writeRefIndex(pc.Funcdata[i])
|
|
|
|
|
}
|
|
|
|
|
for i := 0; i < len(pc.Funcdataoff); i++ {
|
|
|
|
|
w.writeInt(pc.Funcdataoff[i])
|
|
|
|
|
}
|
|
|
|
|
w.writeInt(int64(len(pc.File)))
|
|
|
|
|
for _, f := range pc.File {
|
2017-04-20 07:13:02 -07:00
|
|
|
fsym := ctxt.Lookup(f)
|
2017-04-03 07:50:56 -07:00
|
|
|
w.writeRefIndex(fsym)
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
cmd/compile,link: generate PC-value tables with inlining information
In order to generate accurate tracebacks, the runtime needs to know the
inlined call stack for a given PC. This creates two tables per function
for this purpose. The first table is the inlining tree (stored in the
function's funcdata), which has a node containing the file, line, and
function name for every inlined call. The second table is a PC-value
table that maps each PC to a node in the inlining tree (or -1 if the PC
is not the result of inlining).
To give the appearance that inlining hasn't happened, the runtime also
needs the original source position information of inlined AST nodes.
Previously the compiler plastered over the line numbers of inlined AST
nodes with the line number of the call. This meant that the PC-line
table mapped each PC to line number of the outermost call in its inlined
call stack, with no way to access the innermost line number.
Now the compiler retains line numbers of inlined AST nodes and writes
the innermost source position information to the PC-line and PC-file
tables. Some tools and tests expect to see outermost line numbers, so we
provide the OutermostLine function for displaying line info.
To keep track of the inlined call stack for an AST node, we extend the
src.PosBase type with an index into a global inlining tree. Every time
the compiler inlines a call, it creates a node in the global inlining
tree for the call, and writes its index to the PosBase of every inlined
AST node. The parent of this node is the inlining tree index of the
call. -1 signifies no parent.
For each function, the compiler creates a local inlining tree and a
PC-value table mapping each PC to an index in the local tree. These are
written to an object file, which is read by the linker. The linker
re-encodes these tables compactly by deduplicating function names and
file names.
This change increases the size of binaries by 4-5%. For example, this is
how the go1 benchmark binary is impacted by this change:
section old bytes new bytes delta
.text 3.49M ± 0% 3.49M ± 0% +0.06%
.rodata 1.12M ± 0% 1.21M ± 0% +8.21%
.gopclntab 1.50M ± 0% 1.68M ± 0% +11.89%
.debug_line 338k ± 0% 435k ± 0% +28.78%
Total 9.21M ± 0% 9.58M ± 0% +4.01%
Updates #19348.
Change-Id: Ic4f180c3b516018138236b0c35e0218270d957d3
Reviewed-on: https://go-review.googlesource.com/37231
Run-TryBot: David Lazar <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
|
|
|
w.writeInt(int64(len(pc.InlTree.nodes)))
|
|
|
|
|
for _, call := range pc.InlTree.nodes {
|
|
|
|
|
w.writeInt(int64(call.Parent))
|
|
|
|
|
f, l := linkgetlineFromPos(w.ctxt, call.Pos)
|
2017-04-20 07:13:02 -07:00
|
|
|
fsym := ctxt.Lookup(f)
|
2017-04-03 07:50:56 -07:00
|
|
|
w.writeRefIndex(fsym)
|
cmd/compile,link: generate PC-value tables with inlining information
In order to generate accurate tracebacks, the runtime needs to know the
inlined call stack for a given PC. This creates two tables per function
for this purpose. The first table is the inlining tree (stored in the
function's funcdata), which has a node containing the file, line, and
function name for every inlined call. The second table is a PC-value
table that maps each PC to a node in the inlining tree (or -1 if the PC
is not the result of inlining).
To give the appearance that inlining hasn't happened, the runtime also
needs the original source position information of inlined AST nodes.
Previously the compiler plastered over the line numbers of inlined AST
nodes with the line number of the call. This meant that the PC-line
table mapped each PC to line number of the outermost call in its inlined
call stack, with no way to access the innermost line number.
Now the compiler retains line numbers of inlined AST nodes and writes
the innermost source position information to the PC-line and PC-file
tables. Some tools and tests expect to see outermost line numbers, so we
provide the OutermostLine function for displaying line info.
To keep track of the inlined call stack for an AST node, we extend the
src.PosBase type with an index into a global inlining tree. Every time
the compiler inlines a call, it creates a node in the global inlining
tree for the call, and writes its index to the PosBase of every inlined
AST node. The parent of this node is the inlining tree index of the
call. -1 signifies no parent.
For each function, the compiler creates a local inlining tree and a
PC-value table mapping each PC to an index in the local tree. These are
written to an object file, which is read by the linker. The linker
re-encodes these tables compactly by deduplicating function names and
file names.
This change increases the size of binaries by 4-5%. For example, this is
how the go1 benchmark binary is impacted by this change:
section old bytes new bytes delta
.text 3.49M ± 0% 3.49M ± 0% +0.06%
.rodata 1.12M ± 0% 1.21M ± 0% +8.21%
.gopclntab 1.50M ± 0% 1.68M ± 0% +11.89%
.debug_line 338k ± 0% 435k ± 0% +28.78%
Total 9.21M ± 0% 9.58M ± 0% +4.01%
Updates #19348.
Change-Id: Ic4f180c3b516018138236b0c35e0218270d957d3
Reviewed-on: https://go-review.googlesource.com/37231
Run-TryBot: David Lazar <lazard@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
2017-02-17 12:28:05 -05:00
|
|
|
w.writeInt(int64(l))
|
|
|
|
|
w.writeRefIndex(call.Func)
|
|
|
|
|
}
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
func (w *objWriter) writeInt(sval int64) {
|
2015-01-19 14:34:58 -05:00
|
|
|
var v uint64
|
2016-04-14 19:04:45 -07:00
|
|
|
uv := (uint64(sval) << 1) ^ uint64(sval>>63)
|
2016-03-31 12:59:05 +03:00
|
|
|
p := w.varintbuf[:]
|
2015-01-19 14:34:58 -05:00
|
|
|
for v = uv; v >= 0x80; v >>= 7 {
|
|
|
|
|
p[0] = uint8(v | 0x80)
|
|
|
|
|
p = p[1:]
|
|
|
|
|
}
|
|
|
|
|
p[0] = uint8(v)
|
|
|
|
|
p = p[1:]
|
2016-03-31 12:59:05 +03:00
|
|
|
w.wr.Write(w.varintbuf[:len(w.varintbuf)-len(p)])
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
func (w *objWriter) writeString(s string) {
|
|
|
|
|
w.writeInt(int64(len(s)))
|
|
|
|
|
w.wr.WriteString(s)
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 12:59:05 +03:00
|
|
|
func (w *objWriter) writeRefIndex(s *LSym) {
|
2015-01-19 14:34:58 -05:00
|
|
|
if s == nil {
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeInt(0)
|
2015-01-19 14:34:58 -05:00
|
|
|
return
|
|
|
|
|
}
|
2016-03-14 22:57:58 +02:00
|
|
|
if s.RefIdx == 0 {
|
|
|
|
|
log.Fatalln("writing an unreferenced symbol", s.Name)
|
|
|
|
|
}
|
2016-03-31 12:59:05 +03:00
|
|
|
w.writeInt(int64(s.RefIdx))
|
2015-01-19 14:34:58 -05:00
|
|
|
}
|
2016-03-13 10:13:03 -07:00
|
|
|
|
|
|
|
|
// relocByOff sorts relocations by their offsets.
|
|
|
|
|
type relocByOff []Reloc
|
|
|
|
|
|
|
|
|
|
func (x relocByOff) Len() int { return len(x) }
|
|
|
|
|
func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off }
|
|
|
|
|
func (x relocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
2016-07-28 13:04:41 -04:00
|
|
|
|
|
|
|
|
// implement dwarf.Context
|
|
|
|
|
type dwCtxt struct{ *Link }
|
|
|
|
|
|
|
|
|
|
func (c dwCtxt) PtrSize() int {
|
|
|
|
|
return c.Arch.PtrSize
|
|
|
|
|
}
|
|
|
|
|
func (c dwCtxt) AddInt(s dwarf.Sym, size int, i int64) {
|
|
|
|
|
ls := s.(*LSym)
|
|
|
|
|
ls.WriteInt(c.Link, ls.Size, size, i)
|
|
|
|
|
}
|
|
|
|
|
func (c dwCtxt) AddBytes(s dwarf.Sym, b []byte) {
|
|
|
|
|
ls := s.(*LSym)
|
|
|
|
|
ls.WriteBytes(c.Link, ls.Size, b)
|
|
|
|
|
}
|
|
|
|
|
func (c dwCtxt) AddString(s dwarf.Sym, v string) {
|
|
|
|
|
ls := s.(*LSym)
|
|
|
|
|
ls.WriteString(c.Link, ls.Size, len(v), v)
|
|
|
|
|
ls.WriteInt(c.Link, ls.Size, 1, 0)
|
|
|
|
|
}
|
|
|
|
|
func (c dwCtxt) SymValue(s dwarf.Sym) int64 {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
func (c dwCtxt) AddAddress(s dwarf.Sym, data interface{}, value int64) {
|
2017-04-07 19:50:31 +00:00
|
|
|
rsym := data.(*LSym)
|
2016-07-28 13:04:41 -04:00
|
|
|
ls := s.(*LSym)
|
|
|
|
|
size := c.PtrSize()
|
2017-04-07 19:50:31 +00:00
|
|
|
ls.WriteAddr(c.Link, ls.Size, size, rsym, value)
|
2016-07-28 13:04:41 -04:00
|
|
|
}
|
|
|
|
|
func (c dwCtxt) AddSectionOffset(s dwarf.Sym, size int, t interface{}, ofs int64) {
|
|
|
|
|
ls := s.(*LSym)
|
|
|
|
|
rsym := t.(*LSym)
|
|
|
|
|
ls.WriteAddr(c.Link, ls.Size, size, rsym, ofs)
|
|
|
|
|
r := &ls.R[len(ls.R)-1]
|
2017-04-18 12:53:25 -07:00
|
|
|
r.Type = objabi.R_DWARFREF
|
2016-07-28 13:04:41 -04:00
|
|
|
}
|
|
|
|
|
|
2017-04-13 05:57:59 -07:00
|
|
|
// dwarfSym returns the DWARF symbol for TEXT symbol.
|
|
|
|
|
func (ctxt *Link) dwarfSym(s *LSym) *LSym {
|
2017-04-18 12:53:25 -07:00
|
|
|
if s.Type != objabi.STEXT {
|
2017-04-13 05:57:59 -07:00
|
|
|
ctxt.Diag("dwarfSym of non-TEXT %v", s)
|
|
|
|
|
}
|
2017-04-18 10:18:34 -07:00
|
|
|
if s.Func.dwarfSym == nil {
|
2017-04-20 07:13:02 -07:00
|
|
|
s.Func.dwarfSym = ctxt.LookupDerived(s, dwarf.InfoPrefix+s.Name)
|
2017-04-13 08:00:09 -07:00
|
|
|
}
|
2017-04-18 10:18:34 -07:00
|
|
|
return s.Func.dwarfSym
|
2017-04-13 05:57:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// populateDWARF fills in the DWARF Debugging Information Entry for TEXT symbol s.
|
|
|
|
|
// The DWARF symbol must already have been initialized in InitTextSym.
|
|
|
|
|
func (ctxt *Link) populateDWARF(curfn interface{}, s *LSym) {
|
|
|
|
|
dsym := ctxt.dwarfSym(s)
|
2017-03-06 07:32:37 -08:00
|
|
|
if dsym.Size != 0 {
|
2017-04-13 05:57:59 -07:00
|
|
|
ctxt.Diag("makeFuncDebugEntry double process %v", s)
|
2017-03-06 07:32:37 -08:00
|
|
|
}
|
2017-04-07 19:50:31 +00:00
|
|
|
var vars []*dwarf.Var
|
2017-03-06 07:32:37 -08:00
|
|
|
if ctxt.DebugInfo != nil {
|
2017-04-07 19:50:31 +00:00
|
|
|
vars = ctxt.DebugInfo(s, curfn)
|
2016-07-28 13:04:41 -04:00
|
|
|
}
|
2017-04-20 07:13:02 -07:00
|
|
|
dwarf.PutFunc(dwCtxt{ctxt}, dsym, s.Name, !s.Static(), s, s.Size, vars)
|
2016-07-28 13:04:41 -04:00
|
|
|
}
|