feat(asm): emit GOOBJ objects that link directly with the Go toolchain
Assisted-by: Qwen 3.8 Max Preview
This commit is contained in:
+78
-12
@@ -28,13 +28,26 @@ type Image struct {
|
||||
|
||||
// FuncLayout describes one assembled function within an Image.
|
||||
type FuncLayout struct {
|
||||
Name string
|
||||
Pkg string // explicit package prefix ("" = the current package)
|
||||
Static bool // the <> marker: file-local, not exported
|
||||
Offset int // start offset within the image (== offset within Code)
|
||||
Size int
|
||||
Labels map[string]int // local labels, function-relative
|
||||
Relocs []Reloc // static-symbol references, in emission order
|
||||
Name string
|
||||
Pkg string // explicit package prefix ("" = the current package)
|
||||
Static bool // the <> marker: file-local, not exported
|
||||
Offset int // start offset within the image (== offset within Code)
|
||||
Size int
|
||||
Args int // declared argument/result area (the TEXT size suffix)
|
||||
Frame int // local frame size (the TEXT $framesize)
|
||||
NoSplit bool // the NOSPLIT flag
|
||||
SPWrite bool // the SPWRITE flag: writes an arbitrary value to SP
|
||||
Line int // source line of the TEXT directive
|
||||
Labels map[string]int // local labels, function-relative
|
||||
Relocs []Reloc // static-symbol references, in emission order
|
||||
Spadj []SpadjStep // stack-adjustment boundaries, ascending by PC
|
||||
}
|
||||
|
||||
// SpadjStep is one stack-adjustment boundary: Value is the SP delta from the
|
||||
// entry state in effect from PC (function-relative) until the next step.
|
||||
type SpadjStep struct {
|
||||
PC int
|
||||
Value int
|
||||
}
|
||||
|
||||
// Reloc is one static-symbol reference within a function body: the disp32
|
||||
@@ -57,6 +70,8 @@ type DataSymbol struct {
|
||||
Offset int // byte offset within Data
|
||||
Size int
|
||||
Static bool // the <> marker: file-local, not exported
|
||||
Rodata bool // the RODATA flag: read-only data
|
||||
Dupok bool // the DUPOK flag: duplicate-OK
|
||||
}
|
||||
|
||||
// Bytes returns the whole image: code, then data.
|
||||
@@ -95,18 +110,33 @@ func AssembleFile(f *ast.File) (*Image, error) {
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
code, patches, labels, err := assemble(t, link)
|
||||
code, patches, labels, steps, err := assemble(t, link)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", t.Name.Name, err)
|
||||
}
|
||||
img.Funcs = append(img.Funcs, FuncLayout{
|
||||
fl := FuncLayout{
|
||||
Name: t.Name.Name,
|
||||
Pkg: t.Name.Pkg,
|
||||
Static: t.Name.Static,
|
||||
Offset: len(img.Code),
|
||||
Size: len(code),
|
||||
Frame: frameSize(t),
|
||||
Args: argsSize(t),
|
||||
Line: t.Pos().Line,
|
||||
Labels: labels,
|
||||
})
|
||||
}
|
||||
for _, f := range t.Flags {
|
||||
switch f {
|
||||
case "NOSPLIT":
|
||||
fl.NoSplit = true
|
||||
case "SPWRITE":
|
||||
fl.SPWrite = true
|
||||
}
|
||||
}
|
||||
for _, s := range steps {
|
||||
fl.Spadj = append(fl.Spadj, SpadjStep{PC: s.pc, Value: s.value})
|
||||
}
|
||||
img.Funcs = append(img.Funcs, fl)
|
||||
img.Code = append(img.Code, code...)
|
||||
funcs = append(funcs, asmFunc{name: t.Name.Name, patches: patches})
|
||||
}
|
||||
@@ -124,6 +154,8 @@ func AssembleFile(f *ast.File) (*Image, error) {
|
||||
Offset: len(img.Data),
|
||||
Size: len(d.buf),
|
||||
Static: d.static,
|
||||
Rodata: d.rodata,
|
||||
Dupok: d.dupok,
|
||||
})
|
||||
img.Data = append(img.Data, d.buf...)
|
||||
}
|
||||
@@ -163,6 +195,8 @@ type dataSym struct {
|
||||
pkg string
|
||||
buf []byte
|
||||
static bool
|
||||
rodata bool
|
||||
dupok bool
|
||||
}
|
||||
|
||||
// collectData gathers the file's static symbols (GLOBL) and their initial
|
||||
@@ -185,12 +219,28 @@ func collectData(f *ast.File) ([]dataSym, error) {
|
||||
size = int(dd.Size.Imm.Val)
|
||||
}
|
||||
index[name] = len(syms)
|
||||
syms = append(syms, dataSym{
|
||||
ds := dataSym{
|
||||
name: name,
|
||||
pkg: dd.Name.Pkg,
|
||||
buf: make([]byte, size),
|
||||
static: dd.Name.Static,
|
||||
})
|
||||
}
|
||||
for _, f := range dd.Flags {
|
||||
switch f {
|
||||
case "RODATA":
|
||||
ds.rodata = true
|
||||
case "DUPOK":
|
||||
ds.dupok = true
|
||||
case "1":
|
||||
ds.dupok = true
|
||||
case "8":
|
||||
ds.rodata = true
|
||||
case "9":
|
||||
ds.dupok = true
|
||||
ds.rodata = true
|
||||
}
|
||||
}
|
||||
syms = append(syms, ds)
|
||||
|
||||
case *ast.Data:
|
||||
if dd.Name == nil || dd.Name.Pseudo != "SB" {
|
||||
@@ -230,3 +280,19 @@ func collectData(f *ast.File) ([]dataSym, error) {
|
||||
func align16(n int) int {
|
||||
return (n + 15) &^ 15
|
||||
}
|
||||
|
||||
// frameSize returns the local frame size declared on the TEXT directive.
|
||||
func frameSize(t *ast.Text) int {
|
||||
if t.Frame != nil && t.Frame.Imm.HasVal {
|
||||
return int(t.Frame.Imm.Val)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// argsSize returns the argument/result area declared on the TEXT directive.
|
||||
func argsSize(t *ast.Text) int {
|
||||
if t.Args != nil && t.Args.Imm.HasVal {
|
||||
return int(t.Args.Imm.Val)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user