feat(asm): integrate DWARF5 sections into all ELF emitters
Assisted-by: MiMo V2.5 Pro
This commit is contained in:
+23
@@ -48,6 +48,7 @@ const (
|
||||
shnUndef = 0
|
||||
|
||||
rX8664PC32 = 2
|
||||
rX8664_64 = 1 // R_X86_64_64 (absolute 64-bit)
|
||||
)
|
||||
|
||||
// elfSym is one symbol-table entry in construction.
|
||||
@@ -160,6 +161,9 @@ func (img *Image) ELFObject() ([]byte, error) {
|
||||
for _, n := range []string{".text", ".data", ".symtab", ".strtab", ".rela.text", ".shstrtab"} {
|
||||
stSections.add(n)
|
||||
}
|
||||
for _, n := range dwarfSectionNames {
|
||||
stSections.add(n)
|
||||
}
|
||||
|
||||
// Section presence: .rela.text only when there are relocations.
|
||||
hasRela := len(relas) > 0
|
||||
@@ -220,6 +224,17 @@ func (img *Image) ELFObject() ([]byte, error) {
|
||||
shstrOff := len(out)
|
||||
out = append(out, stSections.bytes()...)
|
||||
|
||||
// DWARF debug sections (no relocations — the linker resolves DWARF fixups).
|
||||
dwAlign := func(n int) {
|
||||
for len(out)%n != 0 {
|
||||
out = append(out, 0)
|
||||
}
|
||||
}
|
||||
dw := appendDWARFSections(&out, img, "gasm.s", symIdx, dwAlign)
|
||||
if dw != nil {
|
||||
nSections += 4 // .debug_abbrev, .debug_info, .debug_line, .debug_line_str
|
||||
}
|
||||
|
||||
align(8)
|
||||
shoff := len(out)
|
||||
|
||||
@@ -248,6 +263,14 @@ func (img *Image) ELFObject() ([]byte, error) {
|
||||
}
|
||||
putSh(".shstrtab", shtStrtab, 0, shstrOff, len(stSections.bytes()), 0, 0, 1, 0)
|
||||
|
||||
// DWARF section headers.
|
||||
if dw != nil {
|
||||
putSh(".debug_abbrev", shtProgbits, 0, dw.abbrevOff, dw.abbrevSize, 0, 0, 1, 0)
|
||||
putSh(".debug_info", shtProgbits, 0, dw.infoOff, dw.infoSize, 0, 0, 1, 0)
|
||||
putSh(".debug_line", shtProgbits, 0, dw.lineOff, dw.lineSize, 0, 0, 1, 0)
|
||||
putSh(".debug_line_str", shtProgbits, 0, dw.lineStrOff, dw.lineStrSize, 0, 0, 1, 0)
|
||||
}
|
||||
|
||||
// The ELF header.
|
||||
hdr := out[:64]
|
||||
copy(hdr[0:], []byte{0x7f, 'E', 'L', 'F', elfClass64, elfDataLSB, elfVersion, 0})
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
package asm
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// dwarfELFSections holds the laid-out DWARF sections ready for inclusion
|
||||
// in an ELF file.
|
||||
type dwarfELFSections struct {
|
||||
abbrevOff, abbrevSize int
|
||||
infoOff, infoSize int
|
||||
lineOff, lineSize int
|
||||
lineStrOff, lineStrSize int
|
||||
// Relocations for .debug_info address references.
|
||||
infoRelocs []elfDwarfReloc
|
||||
// Relocations for .debug_line address references.
|
||||
lineRelocs []elfDwarfReloc
|
||||
}
|
||||
|
||||
type elfDwarfReloc struct {
|
||||
off uint64
|
||||
sym int // symbol index in .symtab
|
||||
addend int64
|
||||
}
|
||||
|
||||
// appendDWARFSections generates and appends DWARF5 debug sections to the ELF
|
||||
// output. It returns the section offsets/sizes and relocations for the caller
|
||||
// to emit section headers and relocation records.
|
||||
//
|
||||
// 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 {
|
||||
// Build a lookup from bare function name to symbol index.
|
||||
nameToIdx := make(map[string]int, len(symIdx))
|
||||
for name, idx := range symIdx {
|
||||
// Strip package prefix: "pkg.name" → "name".
|
||||
if i := len(name) - 1; i >= 0 {
|
||||
for j := len(name) - 1; j >= 0; j-- {
|
||||
if name[j] == '.' {
|
||||
nameToIdx[name[j+1:]] = idx
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
nameToIdx[name] = idx
|
||||
}
|
||||
ds := emitDWARF(img, srcFile)
|
||||
if ds == nil || len(ds.debugAbbrev) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := &dwarfELFSections{}
|
||||
|
||||
// .debug_abbrev
|
||||
align(1)
|
||||
result.abbrevOff = len(*out)
|
||||
result.abbrevSize = len(ds.debugAbbrev)
|
||||
*out = append(*out, ds.debugAbbrev...)
|
||||
|
||||
// .debug_line_str
|
||||
align(1)
|
||||
result.lineStrOff = len(*out)
|
||||
result.lineStrSize = len(ds.debugLineStr)
|
||||
*out = append(*out, ds.debugLineStr...)
|
||||
|
||||
// .debug_line
|
||||
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,
|
||||
sym: idx,
|
||||
addend: dr.addend,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// .debug_info
|
||||
align(1)
|
||||
result.infoOff = len(*out)
|
||||
result.infoSize = len(ds.debugInfo)
|
||||
infoBase := len(*out)
|
||||
*out = append(*out, ds.debugInfo...)
|
||||
|
||||
// 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,
|
||||
sym: idx,
|
||||
addend: dr.addend,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// dwarfRelaRecords returns the ELF RELA records for DWARF address fixups.
|
||||
// Each record uses R_X86_64_64 (absolute 64-bit) relocation type.
|
||||
func dwarfRelaRecords(dw *dwarfELFSections, relType uint32) []byte {
|
||||
le := binary.LittleEndian
|
||||
var out []byte
|
||||
for _, r := range dw.infoRelocs {
|
||||
var b [24]byte
|
||||
le.PutUint64(b[0:], r.off)
|
||||
le.PutUint64(b[8:], uint64(r.sym)<<32|uint64(relType))
|
||||
le.PutUint64(b[16:], uint64(r.addend))
|
||||
out = append(out, b[:]...)
|
||||
}
|
||||
for _, r := range dw.lineRelocs {
|
||||
var b [24]byte
|
||||
le.PutUint64(b[0:], r.off)
|
||||
le.PutUint64(b[8:], uint64(r.sym)<<32|uint64(relType))
|
||||
le.PutUint64(b[16:], uint64(r.addend))
|
||||
out = append(out, b[:]...)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// dwarfSectionNames returns the DWARF section names for the string table.
|
||||
var dwarfSectionNames = []string{
|
||||
".debug_abbrev", ".debug_info", ".debug_line", ".debug_line_str",
|
||||
".rela.debug_info", ".rela.debug_line",
|
||||
}
|
||||
@@ -122,6 +122,9 @@ func (img *Image) ELFAARCH64Object() ([]byte, error) {
|
||||
for _, n := range []string{".text", ".data", ".symtab", ".strtab", ".rela.text", ".shstrtab"} {
|
||||
stSections.add(n)
|
||||
}
|
||||
for _, n := range dwarfSectionNames {
|
||||
stSections.add(n)
|
||||
}
|
||||
|
||||
hasRela := len(relas) > 0
|
||||
nSections := 6
|
||||
@@ -181,6 +184,17 @@ func (img *Image) ELFAARCH64Object() ([]byte, error) {
|
||||
shstrOff := len(out)
|
||||
out = append(out, stSections.bytes()...)
|
||||
|
||||
// DWARF debug sections.
|
||||
dwAlign := func(n int) {
|
||||
for len(out)%n != 0 {
|
||||
out = append(out, 0)
|
||||
}
|
||||
}
|
||||
dw := appendDWARFSections(&out, img, "gasm.s", symIdx, dwAlign)
|
||||
if dw != nil {
|
||||
nSections += 4
|
||||
}
|
||||
|
||||
align(8)
|
||||
shoff := len(out)
|
||||
|
||||
@@ -207,6 +221,12 @@ func (img *Image) ELFAARCH64Object() ([]byte, error) {
|
||||
putSh(".rela.text", shtRela, 0, relaOff, 24*len(relas), secSymtab, secText, 8, 24)
|
||||
}
|
||||
putSh(".shstrtab", shtStrtab, 0, shstrOff, len(stSections.bytes()), 0, 0, 1, 0)
|
||||
if dw != nil {
|
||||
putSh(".debug_abbrev", shtProgbits, 0, dw.abbrevOff, dw.abbrevSize, 0, 0, 1, 0)
|
||||
putSh(".debug_info", shtProgbits, 0, dw.infoOff, dw.infoSize, 0, 0, 1, 0)
|
||||
putSh(".debug_line", shtProgbits, 0, dw.lineOff, dw.lineSize, 0, 0, 1, 0)
|
||||
putSh(".debug_line_str", shtProgbits, 0, dw.lineStrOff, dw.lineStrSize, 0, 0, 1, 0)
|
||||
}
|
||||
|
||||
// ELF header.
|
||||
hdr := out[:64]
|
||||
|
||||
@@ -116,6 +116,9 @@ func (img *Image) ELFLOONG64Object() ([]byte, error) {
|
||||
for _, n := range []string{".text", ".data", ".symtab", ".strtab", ".rela.text", ".shstrtab"} {
|
||||
stSections.add(n)
|
||||
}
|
||||
for _, n := range dwarfSectionNames {
|
||||
stSections.add(n)
|
||||
}
|
||||
|
||||
hasRela := len(relas) > 0
|
||||
nSections := 6
|
||||
@@ -175,6 +178,16 @@ func (img *Image) ELFLOONG64Object() ([]byte, error) {
|
||||
shstrOff := len(out)
|
||||
out = append(out, stSections.bytes()...)
|
||||
|
||||
dwAlign := func(n int) {
|
||||
for len(out)%n != 0 {
|
||||
out = append(out, 0)
|
||||
}
|
||||
}
|
||||
dw := appendDWARFSections(&out, img, "gasm.s", symIdx, dwAlign)
|
||||
if dw != nil {
|
||||
nSections += 4
|
||||
}
|
||||
|
||||
align(8)
|
||||
shoff := len(out)
|
||||
|
||||
@@ -201,6 +214,12 @@ func (img *Image) ELFLOONG64Object() ([]byte, error) {
|
||||
putSh(".rela.text", shtRela, 0, relaOff, 24*len(relas), secSymtab, secText, 8, 24)
|
||||
}
|
||||
putSh(".shstrtab", shtStrtab, 0, shstrOff, len(stSections.bytes()), 0, 0, 1, 0)
|
||||
if dw != nil {
|
||||
putSh(".debug_abbrev", shtProgbits, 0, dw.abbrevOff, dw.abbrevSize, 0, 0, 1, 0)
|
||||
putSh(".debug_info", shtProgbits, 0, dw.infoOff, dw.infoSize, 0, 0, 1, 0)
|
||||
putSh(".debug_line", shtProgbits, 0, dw.lineOff, dw.lineSize, 0, 0, 1, 0)
|
||||
putSh(".debug_line_str", shtProgbits, 0, dw.lineStrOff, dw.lineStrSize, 0, 0, 1, 0)
|
||||
}
|
||||
|
||||
// ELF header.
|
||||
hdr := out[:64]
|
||||
|
||||
@@ -129,6 +129,9 @@ func (img *Image) ELFRISCVObject() ([]byte, error) {
|
||||
for _, n := range []string{".text", ".data", ".symtab", ".strtab", ".rela.text", ".shstrtab"} {
|
||||
stSections.add(n)
|
||||
}
|
||||
for _, n := range dwarfSectionNames {
|
||||
stSections.add(n)
|
||||
}
|
||||
|
||||
hasRela := len(relas) > 0
|
||||
nSections := 6
|
||||
@@ -188,6 +191,16 @@ func (img *Image) ELFRISCVObject() ([]byte, error) {
|
||||
shstrOff := len(out)
|
||||
out = append(out, stSections.bytes()...)
|
||||
|
||||
dwAlign := func(n int) {
|
||||
for len(out)%n != 0 {
|
||||
out = append(out, 0)
|
||||
}
|
||||
}
|
||||
dw := appendDWARFSections(&out, img, "gasm.s", symIdx, dwAlign)
|
||||
if dw != nil {
|
||||
nSections += 4
|
||||
}
|
||||
|
||||
align(8)
|
||||
shoff := len(out)
|
||||
|
||||
@@ -214,6 +227,12 @@ func (img *Image) ELFRISCVObject() ([]byte, error) {
|
||||
putSh(".rela.text", shtRela, 0, relaOff, 24*len(relas), secSymtab, secText, 8, 24)
|
||||
}
|
||||
putSh(".shstrtab", shtStrtab, 0, shstrOff, len(stSections.bytes()), 0, 0, 1, 0)
|
||||
if dw != nil {
|
||||
putSh(".debug_abbrev", shtProgbits, 0, dw.abbrevOff, dw.abbrevSize, 0, 0, 1, 0)
|
||||
putSh(".debug_info", shtProgbits, 0, dw.infoOff, dw.infoSize, 0, 0, 1, 0)
|
||||
putSh(".debug_line", shtProgbits, 0, dw.lineOff, dw.lineSize, 0, 0, 1, 0)
|
||||
putSh(".debug_line_str", shtProgbits, 0, dw.lineStrOff, dw.lineStrSize, 0, 0, 1, 0)
|
||||
}
|
||||
|
||||
// ELF header.
|
||||
hdr := out[:64]
|
||||
|
||||
Reference in New Issue
Block a user