fix(elf): relocation records, DWARF tables and per-architecture frame data
Assisted-by: GLM 5.3
This commit is contained in:
+84
-24
@@ -3,6 +3,17 @@
|
||||
|
||||
package asm
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// Absolute 64-bit relocation types for the DWARF address fixups, one per
|
||||
// supported architecture (the numbers debug/elf carries).
|
||||
const (
|
||||
rX8664Abs64 = 1 // R_X86_64_64
|
||||
rAARCH64Abs64 = 257 // R_AARCH64_ABS64
|
||||
rRISCVAbs64 = 2 // R_RISCV_64
|
||||
rLarchAbs64 = 2 // R_LARCH_64
|
||||
)
|
||||
|
||||
// dwarfELFSections holds the laid-out DWARF sections ready for inclusion
|
||||
// in an ELF file.
|
||||
type dwarfELFSections struct {
|
||||
@@ -11,15 +22,23 @@ type dwarfELFSections struct {
|
||||
lineOff, lineSize int
|
||||
lineStrOff, lineStrSize int
|
||||
frameOff, frameSize int
|
||||
// Relocations for .debug_info address references.
|
||||
// .rela.debug_info and .rela.debug_line contents: file offsets and
|
||||
// entry counts (zero count: the section is absent).
|
||||
infoRelaOff, infoRelaCount int
|
||||
lineRelaOff, lineRelaCount int
|
||||
frameRelaOff, frameRelaCount int
|
||||
// Relocations for .debug_info address references, offsets relative to
|
||||
// the section start (what an r_offset in .rela.debug_info means).
|
||||
infoRelocs []elfDwarfReloc
|
||||
// Relocations for .debug_line address references.
|
||||
// Relocations for .debug_line address references, section-relative.
|
||||
lineRelocs []elfDwarfReloc
|
||||
// Relocations for .debug_frame FDE initial locations, section-relative.
|
||||
frameRelocs []elfDwarfReloc
|
||||
}
|
||||
|
||||
type elfDwarfReloc struct {
|
||||
off uint64
|
||||
sym int // symbol index in .symtab
|
||||
off uint64 // offset within the target section
|
||||
sym int // symbol index in .symtab
|
||||
addend int64
|
||||
}
|
||||
|
||||
@@ -29,8 +48,9 @@ type elfDwarfReloc struct {
|
||||
//
|
||||
// symIdx maps function names to their .symtab indices (needed for relocations
|
||||
// against .text symbols). The map uses objectName format (pkg.name); the
|
||||
// DWARF code uses bare function names, so we build a reverse lookup.
|
||||
func appendDWARFSections(out *[]byte, img *Image, srcFile string, symIdx map[string]int, align func(int)) *dwarfELFSections {
|
||||
// DWARF code uses bare function names, so we build a reverse lookup. cfi
|
||||
// carries the architecture's .debug_frame register conventions.
|
||||
func appendDWARFSections(out *[]byte, img *Image, srcFile string, symIdx map[string]int, align func(int), cfi cfiArch) *dwarfELFSections {
|
||||
// Build a lookup from bare function name to symbol index.
|
||||
nameToIdx := make(map[string]int, len(symIdx))
|
||||
for name, idx := range symIdx {
|
||||
@@ -45,7 +65,7 @@ func appendDWARFSections(out *[]byte, img *Image, srcFile string, symIdx map[str
|
||||
}
|
||||
nameToIdx[name] = idx
|
||||
}
|
||||
ds := emitDWARF(img, srcFile)
|
||||
ds := emitDWARF(img, srcFile, cfi)
|
||||
if ds == nil || len(ds.debugAbbrev) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -68,15 +88,11 @@ func appendDWARFSections(out *[]byte, img *Image, srcFile string, symIdx map[str
|
||||
align(1)
|
||||
result.lineOff = len(*out)
|
||||
result.lineSize = len(ds.debugLine)
|
||||
lineBase := len(*out)
|
||||
*out = append(*out, ds.debugLine...)
|
||||
|
||||
// Patch .debug_line relocations: replace placeholder addresses with
|
||||
// actual .text offsets via symbol lookup.
|
||||
for _, dr := range ds.lineRelocs {
|
||||
if idx, ok := nameToIdx[dr.name]; ok {
|
||||
result.lineRelocs = append(result.lineRelocs, elfDwarfReloc{
|
||||
off: uint64(lineBase) + dr.off,
|
||||
off: dr.off,
|
||||
sym: idx,
|
||||
addend: dr.addend,
|
||||
})
|
||||
@@ -87,33 +103,77 @@ func appendDWARFSections(out *[]byte, img *Image, srcFile string, symIdx map[str
|
||||
align(1)
|
||||
result.infoOff = len(*out)
|
||||
result.infoSize = len(ds.debugInfo)
|
||||
infoBase := len(*out)
|
||||
*out = append(*out, ds.debugInfo...)
|
||||
|
||||
// .debug_frame
|
||||
if len(ds.debugFrame) > 0 {
|
||||
align(1)
|
||||
result.frameOff = len(*out)
|
||||
result.frameSize = len(ds.debugFrame)
|
||||
*out = append(*out, ds.debugFrame...)
|
||||
}
|
||||
|
||||
// Patch .debug_info relocations.
|
||||
for _, dr := range ds.infoRelocs {
|
||||
if idx, ok := nameToIdx[dr.name]; ok {
|
||||
result.infoRelocs = append(result.infoRelocs, elfDwarfReloc{
|
||||
off: uint64(infoBase) + dr.off,
|
||||
off: dr.off,
|
||||
sym: idx,
|
||||
addend: dr.addend,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// .debug_frame: the section header declares alignment 8, so the data is
|
||||
// padded to 8, matching it.
|
||||
if len(ds.debugFrame) > 0 {
|
||||
align(8)
|
||||
result.frameOff = len(*out)
|
||||
result.frameSize = len(ds.debugFrame)
|
||||
*out = append(*out, ds.debugFrame...)
|
||||
for _, dr := range ds.frameRelocs {
|
||||
if idx, ok := nameToIdx[dr.name]; ok {
|
||||
result.frameRelocs = append(result.frameRelocs, elfDwarfReloc{
|
||||
off: dr.off,
|
||||
sym: idx,
|
||||
addend: dr.addend,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// appendDWARFRelas writes the .rela.debug_info and .rela.debug_line section
|
||||
// bodies from the relocations appendDWARFSections recorded, with the
|
||||
// architecture's absolute 64-bit relocation type, and records their file
|
||||
// offsets and entry counts on dw. Called after the DWARF sections
|
||||
// themselves so the r_offsets (section-relative) need no adjustment.
|
||||
func appendDWARFRelas(out *[]byte, dw *dwarfELFSections, abs64 uint32, align func(int)) {
|
||||
le := binary.LittleEndian
|
||||
write := func(relas []elfDwarfReloc) (off, count int) {
|
||||
if len(relas) == 0 {
|
||||
return 0, 0
|
||||
}
|
||||
align(8)
|
||||
off = len(*out)
|
||||
for _, r := range relas {
|
||||
var b [24]byte
|
||||
le.PutUint64(b[0:], r.off)
|
||||
le.PutUint64(b[8:], uint64(r.sym)<<32|uint64(abs64))
|
||||
le.PutUint64(b[16:], uint64(r.addend))
|
||||
*out = append(*out, b[:]...)
|
||||
}
|
||||
return off, len(relas)
|
||||
}
|
||||
dw.infoRelaOff, dw.infoRelaCount = write(dw.infoRelocs)
|
||||
dw.lineRelaOff, dw.lineRelaCount = write(dw.lineRelocs)
|
||||
dw.frameRelaOff, dw.frameRelaCount = write(dw.frameRelocs)
|
||||
}
|
||||
|
||||
// dwarfSourceName returns the source name the DWARF sections record: the
|
||||
// image's source path when the assembler captured one, "gasm.s" otherwise.
|
||||
func dwarfSourceName(img *Image) string {
|
||||
if img.SourcePath != "" {
|
||||
return img.SourcePath
|
||||
}
|
||||
return "gasm.s"
|
||||
}
|
||||
|
||||
// dwarfSectionNames returns the DWARF section names for the string table.
|
||||
var dwarfSectionNames = []string{
|
||||
".debug_abbrev", ".debug_info", ".debug_line", ".debug_line_str",
|
||||
".debug_frame", ".rela.debug_info", ".rela.debug_line",
|
||||
".rela.debug_frame",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user