feat(asm): symbol-valued DATA, division slash in symbols and plain semicolons
Assisted-by: GLM 5.3 Flash
This commit is contained in:
+68
-3
@@ -103,6 +103,7 @@ const (
|
||||
RelArm64Branch // R_CALLARM64 (BL instruction)
|
||||
RelArm64LDST64 // R_ARM64_PCREL_LDST64 (ADRP + 64-bit LDR/STR pair)
|
||||
RelLoong64Branch // R_CALLLOONG64 (BL instruction)
|
||||
RelAddr // R_ADDR: the absolute address of a symbol held in a DATA field
|
||||
)
|
||||
|
||||
type Reloc struct {
|
||||
@@ -112,13 +113,17 @@ type Reloc struct {
|
||||
// Addend select the target: the symbol plus the byte offset. An
|
||||
// External relocation names a symbol no GLOBL in the file defines;
|
||||
// the object-file emitters carry it into the output's relocation
|
||||
// table.
|
||||
// table. Siz is the width of the patched field and is set only for
|
||||
// data-field relocations (RelAddr, Off relative to the data symbol),
|
||||
// whose width is the DATA line's; code relocations take their width
|
||||
// from the architecture's instruction encoding.
|
||||
Off int
|
||||
After int
|
||||
Name string
|
||||
Addend int64
|
||||
External bool
|
||||
Kind RelocKind
|
||||
Siz uint8
|
||||
}
|
||||
|
||||
// DataSymbol describes one GLOBL symbol laid out in the data section.
|
||||
@@ -130,6 +135,11 @@ type DataSymbol struct {
|
||||
Static bool // the <> marker: file-local, not exported
|
||||
Rodata bool // the RODATA flag: read-only data
|
||||
Dupok bool // the DUPOK flag: duplicate-OK
|
||||
// Relocs carries the symbol-valued DATA initialisers ("DATA s+0(SB)/8,
|
||||
// $other(SB)"): fields of this symbol's data that hold another symbol's
|
||||
// address, resolved by the linker. Off is relative to the symbol's
|
||||
// data start.
|
||||
Relocs []Reloc
|
||||
}
|
||||
|
||||
// Bytes returns the whole image: code, then data.
|
||||
@@ -257,6 +267,22 @@ func AssembleFile(f *ast.File) (*Image, error) {
|
||||
img.Funcs[i].Relocs = append(img.Funcs[i].Relocs, reloc)
|
||||
}
|
||||
}
|
||||
// The data symbols' symbol-valued DATA fields resolve the same way the
|
||||
// code references do: a name the file defines (GLOBL or TEXT) stays an
|
||||
// internal reference the emitters resolve, anything else is external.
|
||||
// img.DataSyms was laid out in dataSyms order, so the indexes line up.
|
||||
for i := range img.DataSyms {
|
||||
for _, r := range dataSyms[i].relocs {
|
||||
reloc := r
|
||||
if _, ok := img.Symbols[reloc.Name]; !ok {
|
||||
if _, ok := textOff[reloc.Name]; !ok {
|
||||
reloc.External = true
|
||||
externals[reloc.Name] = true
|
||||
}
|
||||
}
|
||||
img.DataSyms[i].Relocs = append(img.DataSyms[i].Relocs, reloc)
|
||||
}
|
||||
}
|
||||
for name := range externals {
|
||||
img.Externals = append(img.Externals, name)
|
||||
}
|
||||
@@ -429,6 +455,23 @@ func markExternals(img *Image, dataSyms []dataSym) {
|
||||
}
|
||||
}
|
||||
}
|
||||
// The declared data symbols carry the file's own relocations (the
|
||||
// symbol-valued DATA fields); the layouts appended img.DataSyms in
|
||||
// dataSyms order, so the indexes line up. The trailing entries (the
|
||||
// pooled arm64 literals) have no source relocations.
|
||||
for i := range img.DataSyms {
|
||||
if i >= len(dataSyms) {
|
||||
break
|
||||
}
|
||||
for _, r := range dataSyms[i].relocs {
|
||||
reloc := r
|
||||
if !known[reloc.Name] {
|
||||
reloc.External = true
|
||||
externals[reloc.Name] = true
|
||||
}
|
||||
img.DataSyms[i].Relocs = append(img.DataSyms[i].Relocs, reloc)
|
||||
}
|
||||
}
|
||||
for name := range externals {
|
||||
img.Externals = append(img.Externals, name)
|
||||
}
|
||||
@@ -444,6 +487,9 @@ type dataSym struct {
|
||||
static bool
|
||||
rodata bool
|
||||
dupok bool
|
||||
// relocs are the symbol-valued DATA fields, in declaration order; Off
|
||||
// is relative to the symbol's data start.
|
||||
relocs []Reloc
|
||||
}
|
||||
|
||||
// collectData gathers the file's static symbols (GLOBL) and their initial
|
||||
@@ -511,8 +557,8 @@ func collectData(f *ast.File) ([]dataSym, error) {
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("DATA %q: no matching GLOBL", dd.Name.Name)
|
||||
}
|
||||
if dd.Value == nil || !dd.Value.Imm.HasVal {
|
||||
return nil, fmt.Errorf("DATA %q: value must be an integer immediate", dd.Name.Name)
|
||||
if dd.Value == nil {
|
||||
return nil, fmt.Errorf("DATA %q: missing value", dd.Name.Name)
|
||||
}
|
||||
w := dd.Width
|
||||
switch w {
|
||||
@@ -525,6 +571,25 @@ func collectData(f *ast.File) ([]dataSym, error) {
|
||||
if off < 0 || off+int64(w) > int64(len(buf)) {
|
||||
return nil, fmt.Errorf("DATA %q+%d/%d exceeds GLOBL size %d", dd.Name.Name, off, w, len(buf))
|
||||
}
|
||||
// A symbol value ("DATA s+0(SB)/8, $other(SB)", the rt0 spelling)
|
||||
// leaves the field zero and records a relocation against the named
|
||||
// symbol: the linker patches the absolute address at this data
|
||||
// offset. The toolchain emits the same shape, an R_ADDR of the
|
||||
// DATA width with the value's offset as the addend, on every
|
||||
// architecture.
|
||||
if sym := dd.Value.Imm.Sym; !dd.Value.Imm.HasVal && sym != nil {
|
||||
syms[i].relocs = append(syms[i].relocs, Reloc{
|
||||
Off: int(off),
|
||||
Name: sym.Name,
|
||||
Addend: sym.Offset,
|
||||
Kind: RelAddr,
|
||||
Siz: uint8(w),
|
||||
})
|
||||
continue
|
||||
}
|
||||
if !dd.Value.Imm.HasVal {
|
||||
return nil, fmt.Errorf("DATA %q: value must be an integer immediate or a symbol address", dd.Name.Name)
|
||||
}
|
||||
v := dd.Value.Imm.Val
|
||||
if dd.Value.Imm.Neg {
|
||||
v = -v
|
||||
|
||||
Reference in New Issue
Block a user