fix(elf): relocation records, DWARF tables and per-architecture frame data
Assisted-by: GLM 5.3
This commit is contained in:
+74
-22
@@ -81,10 +81,15 @@ func (img *Image) ELFAARCH64Object() ([]byte, error) {
|
||||
}
|
||||
|
||||
// Build relocations. Each SB reference is an ADRP pair:
|
||||
// ADRP Rd, 0 → R_AARCH64_ADR_PREL_PG_HI21
|
||||
// ADD → R_AARCH64_ADD_ABS_LO12_NC
|
||||
// LDR/STR X → R_AARCH64_LDST64_ABS_LO12_NC
|
||||
// ADRP Rd, 0 → R_AARCH64_ADR_PREL_PG_HI21 at the ADRP
|
||||
// ADD → R_AARCH64_ADD_ABS_LO12_NC at the ADD word
|
||||
// LDR/STR X → R_AARCH64_LDST64_ABS_LO12_NC at the LDR/STR word
|
||||
// BL → R_AARCH64_CALL26
|
||||
// cmd/link's own conversion emits the HI21 at sectoff and the LO12 at
|
||||
// sectoff+4 (cmd/link/internal/arm64/asm.go), so the ADD or load word
|
||||
// carries the page-offset relocation, never a second HI21. The
|
||||
// assembler records two RelArm64Addr relocs per ADRP+ADD pair (one per
|
||||
// word), so the second of the pair is consumed here.
|
||||
// Addends stay raw: ADR_PREL_PG_HI21 and the ABS_LO12_NC forms resolve
|
||||
// against S+A, and CALL26 branches take the branch instruction's own
|
||||
// place as the PC-relative base, so subtracting the field width (the
|
||||
@@ -97,28 +102,34 @@ func (img *Image) ELFAARCH64Object() ([]byte, error) {
|
||||
}
|
||||
var relas []elfRela
|
||||
for _, fn := range img.Funcs {
|
||||
for _, r := range fn.Relocs {
|
||||
for i := 0; i < len(fn.Relocs); i++ {
|
||||
r := fn.Relocs[i]
|
||||
idx, ok := symIdx[r.Name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("relocation references unknown symbol %q", r.Name)
|
||||
}
|
||||
var typ uint32
|
||||
switch {
|
||||
case r.Kind == RelArm64Branch:
|
||||
typ = rArm64Call26
|
||||
case r.Kind == RelArm64LDST64 && r.Off%4 == 4:
|
||||
typ = rArm64Ldst64Lo12NC
|
||||
case r.Kind == RelArm64Addr && r.Off%4 == 4:
|
||||
typ = rArm64AddAbsLo12NC
|
||||
switch r.Kind {
|
||||
case RelArm64Branch:
|
||||
relas = append(relas, elfRela{
|
||||
off: uint64(fn.Offset + r.Off), typ: rArm64Call26, sym: idx, addend: r.Addend,
|
||||
})
|
||||
case RelArm64Addr:
|
||||
// ADRP+ADD: the pair's second reloc (at Off+4) is the
|
||||
// assembler's twin of the same pair; skip it.
|
||||
relas = append(relas,
|
||||
elfRela{off: uint64(fn.Offset + r.Off), typ: rArm64PrelPgHi21, sym: idx, addend: r.Addend},
|
||||
elfRela{off: uint64(fn.Offset + r.Off + 4), typ: rArm64AddAbsLo12NC, sym: idx, addend: r.Addend},
|
||||
)
|
||||
i++
|
||||
case RelArm64LDST64:
|
||||
// ADRP+LDR/STR: one assembler reloc covers the pair.
|
||||
relas = append(relas,
|
||||
elfRela{off: uint64(fn.Offset + r.Off), typ: rArm64PrelPgHi21, sym: idx, addend: r.Addend},
|
||||
elfRela{off: uint64(fn.Offset + r.Off + 4), typ: rArm64Ldst64Lo12NC, sym: idx, addend: r.Addend},
|
||||
)
|
||||
default:
|
||||
typ = rArm64PrelPgHi21
|
||||
return nil, fmt.Errorf("relocation kind %v unsupported in ELF emission", r.Kind)
|
||||
}
|
||||
relas = append(relas, elfRela{
|
||||
off: uint64(fn.Offset + r.Off),
|
||||
typ: typ,
|
||||
sym: idx,
|
||||
addend: r.Addend,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,15 +204,32 @@ func (img *Image) ELFAARCH64Object() ([]byte, error) {
|
||||
shstrOff := len(out)
|
||||
out = append(out, stSections.bytes()...)
|
||||
|
||||
// DWARF debug sections.
|
||||
// DWARF debug sections; the address placeholders they leave are carried
|
||||
// as .rela.debug_info/.rela.debug_line entries the system linker applies.
|
||||
dwAlign := func(n int) {
|
||||
for len(out)%n != 0 {
|
||||
out = append(out, 0)
|
||||
}
|
||||
}
|
||||
dw := appendDWARFSections(&out, img, "gasm.s", symIdx, dwAlign)
|
||||
dw := appendDWARFSections(&out, img, dwarfSourceName(img), symIdx, dwAlign, cfiARM64)
|
||||
dwarfStart := 0 // section index of .debug_abbrev, set when DWARF is present
|
||||
if dw != nil {
|
||||
nSections += 4
|
||||
// Five DWARF sections: .debug_abbrev, .debug_info, .debug_line,
|
||||
// .debug_line_str and .debug_frame (the CIE is unconditional, so
|
||||
// the frame section is always present), plus the relocation
|
||||
// sections below when they carry entries.
|
||||
dwarfStart = nSections
|
||||
nSections += 5
|
||||
appendDWARFRelas(&out, dw, rAARCH64Abs64, dwAlign)
|
||||
if dw.infoRelaCount > 0 {
|
||||
nSections++
|
||||
}
|
||||
if dw.lineRelaCount > 0 {
|
||||
nSections++
|
||||
}
|
||||
if dw.frameRelaCount > 0 {
|
||||
nSections++
|
||||
}
|
||||
}
|
||||
|
||||
align(8)
|
||||
@@ -230,13 +258,37 @@ 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)
|
||||
// DWARF section headers; their indices follow the write order.
|
||||
if dw != nil {
|
||||
// secIdx is a running section index: each putSh below emits the
|
||||
// next header, and the sh_info of a .rela section names the index
|
||||
// of the section it relocates.
|
||||
secIdx := dwarfStart
|
||||
putSh(".debug_abbrev", shtProgbits, 0, dw.abbrevOff, dw.abbrevSize, 0, 0, 1, 0)
|
||||
secIdx++
|
||||
putSh(".debug_info", shtProgbits, 0, dw.infoOff, dw.infoSize, 0, 0, 1, 0)
|
||||
secInfoIdx := secIdx
|
||||
secIdx++
|
||||
if dw.infoRelaCount > 0 {
|
||||
putSh(".rela.debug_info", shtRela, 0, dw.infoRelaOff, 24*dw.infoRelaCount, secSymtab, secInfoIdx, 8, 24)
|
||||
secIdx++
|
||||
}
|
||||
putSh(".debug_line", shtProgbits, 0, dw.lineOff, dw.lineSize, 0, 0, 1, 0)
|
||||
secLineIdx := secIdx
|
||||
secIdx++
|
||||
if dw.lineRelaCount > 0 {
|
||||
putSh(".rela.debug_line", shtRela, 0, dw.lineRelaOff, 24*dw.lineRelaCount, secSymtab, secLineIdx, 8, 24)
|
||||
secIdx++
|
||||
}
|
||||
putSh(".debug_line_str", shtProgbits, 0, dw.lineStrOff, dw.lineStrSize, 0, 0, 1, 0)
|
||||
secIdx++
|
||||
if dw.frameSize > 0 {
|
||||
putSh(".debug_frame", shtProgbits, 0, dw.frameOff, dw.frameSize, 0, 0, 8, 0)
|
||||
secFrameIdx := secIdx
|
||||
secIdx++
|
||||
if dw.frameRelaCount > 0 {
|
||||
putSh(".rela.debug_frame", shtRela, 0, dw.frameRelaOff, 24*dw.frameRelaCount, secSymtab, secFrameIdx, 8, 24)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user