mirror of
https://github.com/golang/go
synced 2024-11-19 13:04:45 -07:00
cmd/link: rewrite pe symbol table generating code
Every go executable has COFF symbol table appended at the end. The table is used by nm and addr2line and contains all symbols present in the executable. The table is quite large. For example, my go.exe has 11736 records. To generate symbol table: 1) we walk "all symbols" list to count symbols we want for the table; 2) we allocate large global array of COFFSym structs (32 bytes each) to fit our symbols; 3) we walk "all symbols" list again to fill our array with contents; 4) we iterate over our global array to write all records to the file. This CL changes all these steps with single step: - walk "all symbols" list and write each COFF symbol table record to the file as we go. I hope new version is faster and uses less garbage, but I don't know how to benchmark this. Change-Id: Ie4870583250131ea4428e0e83a0696c9df1794e0 Reviewed-on: https://go-review.googlesource.com/20580 Reviewed-by: David Crawshaw <crawshaw@golang.org> Run-TryBot: David Crawshaw <crawshaw@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Run-TryBot: Alex Brainman <alex.brainman@gmail.com>
This commit is contained in:
parent
77b527e283
commit
bb48b864b1
@ -375,18 +375,6 @@ var dexport [1024]*LSym
|
|||||||
|
|
||||||
var nexport int
|
var nexport int
|
||||||
|
|
||||||
type COFFSym struct {
|
|
||||||
sym *LSym
|
|
||||||
strtbloff int
|
|
||||||
sect int
|
|
||||||
value int64
|
|
||||||
typ uint16
|
|
||||||
}
|
|
||||||
|
|
||||||
var coffsym []COFFSym
|
|
||||||
|
|
||||||
var ncoffsym int
|
|
||||||
|
|
||||||
func addpesection(name string, sectsize int, filesize int) *IMAGE_SECTION_HEADER {
|
func addpesection(name string, sectsize int, filesize int) *IMAGE_SECTION_HEADER {
|
||||||
if pensect == 16 {
|
if pensect == 16 {
|
||||||
Diag("too many sections")
|
Diag("too many sections")
|
||||||
@ -922,59 +910,73 @@ func newPEDWARFSection(name string, size int64) *IMAGE_SECTION_HEADER {
|
|||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
func addpesym(s *LSym, name string, type_ int, addr int64, size int64, ver int, gotype *LSym) {
|
// writePESymTableRecords writes all COFF symbol table records.
|
||||||
|
// It returns number of records written.
|
||||||
|
func writePESymTableRecords() int {
|
||||||
|
var symcnt int
|
||||||
|
|
||||||
|
put := func(s *LSym, name string, type_ int, addr int64, size int64, ver int, gotype *LSym) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.Sect == nil && type_ != 'U' {
|
if s.Sect == nil && type_ != 'U' {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
switch type_ {
|
switch type_ {
|
||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
|
|
||||||
case 'D', 'B', 'T', 'U':
|
case 'D', 'B', 'T', 'U':
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if coffsym != nil {
|
|
||||||
// only windows/386 requires underscore prefix on external symbols
|
// only windows/386 requires underscore prefix on external symbols
|
||||||
if Thearch.Thechar == '8' && Linkmode == LinkExternal && (s.Type == obj.SHOSTOBJ || s.Attr.CgoExport()) && s.Name == s.Extname {
|
if Thearch.Thechar == '8' && Linkmode == LinkExternal && (s.Type == obj.SHOSTOBJ || s.Attr.CgoExport()) && s.Name == s.Extname {
|
||||||
s.Name = "_" + s.Name
|
s.Name = "_" + s.Name
|
||||||
}
|
}
|
||||||
cs := &coffsym[ncoffsym]
|
|
||||||
cs.sym = s
|
var typ uint16
|
||||||
if len(s.Name) > 8 {
|
var sect int
|
||||||
cs.strtbloff = strtbladd(s.Name)
|
var value int64
|
||||||
}
|
|
||||||
// Note: although address of runtime.edata (type SDATA) is at the start of .bss section
|
// Note: although address of runtime.edata (type SDATA) is at the start of .bss section
|
||||||
// it still belongs to the .data section, not the .bss section.
|
// it still belongs to the .data section, not the .bss section.
|
||||||
if uint64(s.Value) >= Segdata.Vaddr+Segdata.Filelen && s.Type != obj.SDATA && Linkmode == LinkExternal {
|
if uint64(s.Value) >= Segdata.Vaddr+Segdata.Filelen && s.Type != obj.SDATA && Linkmode == LinkExternal {
|
||||||
cs.value = int64(uint64(s.Value) - Segdata.Vaddr - Segdata.Filelen)
|
value = int64(uint64(s.Value) - Segdata.Vaddr - Segdata.Filelen)
|
||||||
cs.sect = bsssect
|
sect = bsssect
|
||||||
} else if uint64(s.Value) >= Segdata.Vaddr {
|
} else if uint64(s.Value) >= Segdata.Vaddr {
|
||||||
cs.value = int64(uint64(s.Value) - Segdata.Vaddr)
|
value = int64(uint64(s.Value) - Segdata.Vaddr)
|
||||||
cs.sect = datasect
|
sect = datasect
|
||||||
} else if uint64(s.Value) >= Segtext.Vaddr {
|
} else if uint64(s.Value) >= Segtext.Vaddr {
|
||||||
cs.value = int64(uint64(s.Value) - Segtext.Vaddr)
|
value = int64(uint64(s.Value) - Segtext.Vaddr)
|
||||||
cs.sect = textsect
|
sect = textsect
|
||||||
} else if type_ == 'U' {
|
} else if type_ == 'U' {
|
||||||
cs.value = 0
|
typ = IMAGE_SYM_DTYPE_FUNCTION
|
||||||
cs.typ = IMAGE_SYM_DTYPE_FUNCTION
|
|
||||||
} else {
|
} else {
|
||||||
cs.value = 0
|
|
||||||
cs.sect = 0
|
|
||||||
Diag("addpesym %#x", addr)
|
Diag("addpesym %#x", addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// write COFF symbol table record
|
||||||
|
if len(s.Name) > 8 {
|
||||||
|
Lputl(0)
|
||||||
|
Lputl(uint32(strtbladd(s.Name)))
|
||||||
|
} else {
|
||||||
|
strnput(s.Name, 8)
|
||||||
|
}
|
||||||
|
Lputl(uint32(value))
|
||||||
|
Wputl(uint16(sect))
|
||||||
|
if typ != 0 {
|
||||||
|
Wputl(typ)
|
||||||
|
} else if Linkmode == LinkExternal {
|
||||||
|
Wputl(0)
|
||||||
|
} else {
|
||||||
|
Wputl(0x0308) // "array of structs"
|
||||||
|
}
|
||||||
|
Cput(2) // storage class: external
|
||||||
|
Cput(0) // no aux entries
|
||||||
|
|
||||||
|
s.Dynid = int32(symcnt)
|
||||||
|
|
||||||
|
symcnt++
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Dynid = int32(ncoffsym)
|
|
||||||
ncoffsym++
|
|
||||||
}
|
|
||||||
|
|
||||||
func pegenasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
|
|
||||||
if Linkmode == LinkExternal {
|
if Linkmode == LinkExternal {
|
||||||
for d := dr; d != nil; d = d.next {
|
for d := dr; d != nil; d = d.next {
|
||||||
for m := d.ms; m != nil; m = m.next {
|
for m := d.ms; m != nil; m = m.next {
|
||||||
@ -983,57 +985,36 @@ func pegenasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
genasmsym(put)
|
genasmsym(put)
|
||||||
|
|
||||||
|
return symcnt
|
||||||
}
|
}
|
||||||
|
|
||||||
func addpesymtable() {
|
func addpesymtable() {
|
||||||
if Debug['s'] == 0 || Linkmode == LinkExternal {
|
symtabStartPos := Cpos()
|
||||||
ncoffsym = 0
|
|
||||||
pegenasmsym(addpesym)
|
|
||||||
coffsym = make([]COFFSym, ncoffsym)
|
|
||||||
ncoffsym = 0
|
|
||||||
pegenasmsym(addpesym)
|
|
||||||
}
|
|
||||||
size := len(strtbl) + 4 + 18*ncoffsym
|
|
||||||
|
|
||||||
|
// write COFF symbol table
|
||||||
|
var symcnt int
|
||||||
|
if Debug['s'] == 0 || Linkmode == LinkExternal {
|
||||||
|
symcnt = writePESymTableRecords()
|
||||||
|
}
|
||||||
|
|
||||||
|
// update COFF file header and section table
|
||||||
|
size := len(strtbl) + 4 + 18*symcnt
|
||||||
var h *IMAGE_SECTION_HEADER
|
var h *IMAGE_SECTION_HEADER
|
||||||
if Linkmode != LinkExternal {
|
if Linkmode != LinkExternal {
|
||||||
// We do not really need .symtab for go.o, and if we have one, ld
|
// We do not really need .symtab for go.o, and if we have one, ld
|
||||||
// will also include it in the exe, and that will confuse windows.
|
// will also include it in the exe, and that will confuse windows.
|
||||||
h = addpesection(".symtab", size, size)
|
h = addpesection(".symtab", size, size)
|
||||||
h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
|
h.Characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE
|
||||||
chksectoff(h, Cpos())
|
chksectoff(h, symtabStartPos)
|
||||||
}
|
}
|
||||||
fh.PointerToSymbolTable = uint32(Cpos())
|
fh.PointerToSymbolTable = uint32(symtabStartPos)
|
||||||
fh.NumberOfSymbols = uint32(ncoffsym)
|
fh.NumberOfSymbols = uint32(symcnt)
|
||||||
|
|
||||||
// put COFF symbol table
|
// write COFF string table
|
||||||
var s *COFFSym
|
|
||||||
for i := 0; i < ncoffsym; i++ {
|
|
||||||
s = &coffsym[i]
|
|
||||||
if s.strtbloff == 0 {
|
|
||||||
strnput(s.sym.Name, 8)
|
|
||||||
} else {
|
|
||||||
Lputl(0)
|
|
||||||
Lputl(uint32(s.strtbloff))
|
|
||||||
}
|
|
||||||
|
|
||||||
Lputl(uint32(s.value))
|
|
||||||
Wputl(uint16(s.sect))
|
|
||||||
if s.typ != 0 {
|
|
||||||
Wputl(s.typ)
|
|
||||||
} else if Linkmode == LinkExternal {
|
|
||||||
Wputl(0)
|
|
||||||
} else {
|
|
||||||
Wputl(0x0308) // "array of structs"
|
|
||||||
}
|
|
||||||
Cput(2) // storage class: external
|
|
||||||
Cput(0) // no aux entries
|
|
||||||
}
|
|
||||||
|
|
||||||
// put COFF string table
|
|
||||||
Lputl(uint32(len(strtbl)) + 4)
|
Lputl(uint32(len(strtbl)) + 4)
|
||||||
|
|
||||||
for i := 0; i < len(strtbl); i++ {
|
for i := 0; i < len(strtbl); i++ {
|
||||||
Cput(uint8(strtbl[i]))
|
Cput(uint8(strtbl[i]))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user