Skip to content

Commit eda01de

Browse files
authored
Merge pull request #1688 from cpunion/exp/plan9asm-llvm-cabi
Remove cabi allowlist with plan9asm-compatible asm lowering
2 parents b7d1de5 + 4ab8056 commit eda01de

24 files changed

+1011
-1201
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ require (
1717
)
1818

1919
require (
20-
github.com/goplus/plan9asm v0.0.0-20260212064924-71ea5584065b
20+
github.com/goplus/plan9asm v0.0.0-20260307134905-822503d6bf44
2121
github.com/marcinbor85/gohex v0.0.0-20210308104911-55fb1c624d84
2222
github.com/mattn/go-tty v0.0.7
2323
github.com/sigurn/crc16 v0.0.0-20240131213347-83fcde1e29d1

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ github.com/goplus/mod v0.19.5 h1:36sbRxKie2Or9aSfWT06X6WV37sBwARXYfKfGfHzEQs=
1616
github.com/goplus/mod v0.19.5/go.mod h1:T6Ta3xPXx8NQaRb8h632P5iBgIB77zXfh9vLNRFqMqk=
1717
github.com/goplus/plan9asm v0.0.0-20260212064924-71ea5584065b h1:DFZ0n92lGC3ogziCvtAHK8TKJf7oqiT4U576TIENiyk=
1818
github.com/goplus/plan9asm v0.0.0-20260212064924-71ea5584065b/go.mod h1:nnr49+IlbnOI5c0yb1fkbilBRcr50RPX0JAreDdYTUI=
19+
github.com/goplus/plan9asm v0.0.0-20260306151730-9203c54dfd4c h1:1S6F8dDxAnRiZAhqKjzLhAdx71jOaB5YdlHzfwCkdH8=
20+
github.com/goplus/plan9asm v0.0.0-20260306151730-9203c54dfd4c/go.mod h1:nnr49+IlbnOI5c0yb1fkbilBRcr50RPX0JAreDdYTUI=
21+
github.com/goplus/plan9asm v0.0.0-20260307044640-a5f1e3b27fc1 h1:hlVAtc3x34x6CQoOPnkOtz9p4juJ+cEZzgDyJpWnit4=
22+
github.com/goplus/plan9asm v0.0.0-20260307044640-a5f1e3b27fc1/go.mod h1:nnr49+IlbnOI5c0yb1fkbilBRcr50RPX0JAreDdYTUI=
23+
github.com/goplus/plan9asm v0.0.0-20260307134905-822503d6bf44 h1:zZXTz5CBO1uZIJGZSGWov5gE1CbulJ1QH6ruTMv3UdY=
24+
github.com/goplus/plan9asm v0.0.0-20260307134905-822503d6bf44/go.mod h1:gpS4VVNoRykYTtc8kPFBowraN5SrBj8lIjW8/lNjaG4=
1925
github.com/marcinbor85/gohex v0.0.0-20210308104911-55fb1c624d84 h1:hyAgCuG5nqTMDeUD8KZs7HSPs6KprPgPP8QmGV8nyvk=
2026
github.com/marcinbor85/gohex v0.0.0-20210308104911-55fb1c624d84/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
2127
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=

internal/build/build.go

Lines changed: 73 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
"path/filepath"
3232
"runtime"
3333
"slices"
34+
"sort"
3435
"strings"
3536
"sync"
3637
"sync/atomic"
@@ -247,6 +248,9 @@ func Do(args []string, conf *Config) ([]Package, error) {
247248
verbose := conf.Verbose
248249
patterns := args
249250
tags := "llgo,math_big_pure_go,purego"
251+
if conf.AbiMode == cabi.ModeAllFunc {
252+
tags += ",llgo_abi_2"
253+
}
250254
if conf.Tags != "" {
251255
tags += "," + conf.Tags
252256
}
@@ -547,10 +551,9 @@ type context struct {
547551
// go list derived file lists (SFiles, etc.)
548552
sfilesCache map[string][]string // pkg.ID -> absolute .s/.S file paths
549553

550-
// plan9asm package allowlist parsed from env.
554+
// plan9asm package policy parsed from env.
551555
plan9asmOnce sync.Once
552-
plan9asmAll bool
553-
// when plan9asmAll=false: enabled set; when plan9asmAll=true: excluded set.
556+
plan9asmMode plan9asmPkgsEnvMode
554557
plan9asmPkgs map[string]bool
555558
}
556559

@@ -903,13 +906,24 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, outputPa
903906
for _, v := range pkgs {
904907
allPkgs = append(allPkgs, v.Package)
905908
}
906-
// linkInputs contains .a archives from all packages and .o files from main module
907-
var linkInputs []string
909+
visitRoots := allPkgs
910+
if ctx.mode == ModeTest {
911+
visitRoots = []*packages.Package{pkg}
912+
for _, p := range allPkgs {
913+
if isRuntimePkg(p.PkgPath) {
914+
visitRoots = append(visitRoots, p)
915+
}
916+
}
917+
}
918+
// archiveInputs contains package .a files. Object files are prepended later so
919+
// archive extraction can see their undefined references in a single linker pass.
920+
var archiveInputs []string
908921
var linkArgs []string
909922
var rtLinkInputs []string
910923
var rtLinkArgs []string
911924
linkedPkgs := make(map[string]bool) // Track linked packages by ID to avoid duplicates
912-
packages.Visit(allPkgs, nil, func(p *packages.Package) {
925+
var linkedOrder []Package
926+
packages.Visit(visitRoots, nil, func(p *packages.Package) {
913927
// Skip if already linked this package (by ID)
914928
if linkedPkgs[p.ID] {
915929
return
@@ -921,53 +935,62 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, outputPa
921935
}
922936
if p.ExportFile != "" && aPkg != nil { // skip packages that only contain declarations
923937
linkedPkgs[p.ID] = true
938+
linkedOrder = append(linkedOrder, aPkg)
939+
}
940+
})
924941

925-
// Defer linking runtime packages unless we actually need the runtime.
926-
if isRuntimePkg(p.PkgPath) {
927-
rtLinkArgs = append(rtLinkArgs, aPkg.LinkArgs...)
928-
if aPkg.ArchiveFile != "" {
929-
rtLinkInputs = append(rtLinkInputs, aPkg.ArchiveFile)
930-
}
931-
return
932-
} else {
933-
// Only let non-runtime packages influence whether runtime is needed.
934-
need1, need2 := aPkg.isNeedRuntimeOrPyInit()
935-
needRuntime = needRuntime || need1
936-
needPyInit = needPyInit || need2
937-
}
938-
if aPkg.LPkg.NeedAbiInit {
939-
needAbiInit = true
940-
}
941-
942-
linkArgs = append(linkArgs, aPkg.LinkArgs...)
942+
// packages.Visit with a post callback yields dependencies before importers.
943+
// Reverse that order so static archives are linked after the objects that use them.
944+
for i := len(linkedOrder) - 1; i >= 0; i-- {
945+
aPkg := linkedOrder[i]
946+
p := aPkg.Package
947+
// Defer linking runtime packages unless we actually need the runtime.
948+
if isRuntimePkg(p.PkgPath) {
949+
rtLinkArgs = append(rtLinkArgs, aPkg.LinkArgs...)
943950
if aPkg.ArchiveFile != "" {
944-
linkInputs = append(linkInputs, aPkg.ArchiveFile)
951+
rtLinkInputs = append(rtLinkInputs, aPkg.ArchiveFile)
945952
}
953+
continue
946954
}
947-
})
955+
// Only let non-runtime packages influence whether runtime is needed.
956+
need1, need2 := aPkg.isNeedRuntimeOrPyInit()
957+
needRuntime = needRuntime || need1
958+
needPyInit = needPyInit || need2
959+
if aPkg.LPkg.NeedAbiInit {
960+
needAbiInit = true
961+
}
962+
963+
linkArgs = append(linkArgs, aPkg.LinkArgs...)
964+
if aPkg.ArchiveFile != "" {
965+
archiveInputs = append(archiveInputs, aPkg.ArchiveFile)
966+
}
967+
}
948968

949969
// Only link runtime objects when needed (or for host builds where runtime is always required).
950970
if needRuntime || needPyInit || ctx.buildConf.Target == "" {
951971
linkArgs = append(linkArgs, rtLinkArgs...)
952-
linkInputs = append(linkInputs, rtLinkInputs...)
972+
archiveInputs = append(archiveInputs, rtLinkInputs...)
953973
}
954974

975+
abiSymbols := linkedModuleGlobals(linkedOrder)
976+
955977
// Generate main module file (needed for global variables even in library modes)
956978
// This is compiled directly to .o and added to linkInputs (not cached)
957979
// Use a stable synthetic name to avoid confusing it with the real main package in traces/logs.
958-
entryPkg := genMainModule(ctx, llssa.PkgRuntime, pkg, needRuntime, needPyInit, needAbiInit)
980+
entryPkg := genMainModule(ctx, llssa.PkgRuntime, pkg, needRuntime, needPyInit, needAbiInit, abiSymbols)
959981
entryObjFile, err := exportObject(ctx, "entry_main", entryPkg.ExportFile, []byte(entryPkg.LPkg.String()))
960982
if err != nil {
961983
return err
962984
}
963-
linkInputs = append(linkInputs, entryObjFile)
985+
linkInputs := []string{entryObjFile}
964986

965987
// Compile extra files from target configuration
966988
extraObjFiles, err := compileExtraFiles(ctx, verbose)
967989
if err != nil {
968990
return err
969991
}
970992
linkInputs = append(linkInputs, extraObjFiles...)
993+
linkInputs = append(linkInputs, archiveInputs...)
971994

972995
if IsFullRpathEnabled() {
973996
// Treat every link-time library search path, specified by the -L parameter, as a runtime search path as well.
@@ -994,6 +1017,27 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, outputPa
9941017
return nil
9951018
}
9961019

1020+
func linkedModuleGlobals(pkgs []Package) []string {
1021+
if len(pkgs) == 0 {
1022+
return nil
1023+
}
1024+
seen := make(map[string]struct{})
1025+
for _, pkg := range pkgs {
1026+
if pkg == nil || pkg.LPkg == nil {
1027+
continue
1028+
}
1029+
for g := pkg.LPkg.Module().FirstGlobal(); !g.IsNil(); g = gllvm.NextGlobal(g) {
1030+
seen[g.Name()] = struct{}{}
1031+
}
1032+
}
1033+
names := make([]string, 0, len(seen))
1034+
for name := range seen {
1035+
names = append(names, name)
1036+
}
1037+
sort.Strings(names)
1038+
return names
1039+
}
1040+
9971041
// isRuntimePkg reports whether the package path belongs to the llgo runtime tree.
9981042
func isRuntimePkg(pkgPath string) bool {
9991043
rtRoot := env.LLGoRuntimePkg

internal/build/main_module.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ import (
4141
// The module contains argc/argv globals and, for executable build modes,
4242
// the entry function that wires initialization and main. For C archive or
4343
// shared library modes, only the globals are emitted.
44-
func genMainModule(ctx *context, rtPkgPath string, pkg *packages.Package, needRuntime, needPyInit, needAbiInit bool) Package {
44+
func genMainModule(ctx *context, rtPkgPath string, pkg *packages.Package, needRuntime, needPyInit, needAbiInit bool, abiSymbols []string) Package {
4545
prog := ctx.prog
4646
mainPkg := prog.NewPackage("", pkg.ID+".main")
4747

@@ -84,7 +84,7 @@ func genMainModule(ctx *context, rtPkgPath string, pkg *packages.Package, needRu
8484

8585
var abiInit llssa.Function
8686
if needAbiInit {
87-
abiInit = mainPkg.InitAbiTypes("init$abitypes")
87+
abiInit = mainPkg.InitAbiTypesFor("init$abitypes", abiSymbols)
8888
}
8989

9090
mainInit := declareNoArgFunc(mainPkg, pkg.PkgPath+".init")

internal/build/main_module_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func TestGenMainModuleExecutable(t *testing.T) {
2929
},
3030
}
3131
pkg := &packages.Package{PkgPath: "example.com/foo", ExportFile: "foo.a"}
32-
mod := genMainModule(ctx, llssa.PkgRuntime, pkg, true, true, true)
32+
mod := genMainModule(ctx, llssa.PkgRuntime, pkg, true, true, true, nil)
3333
if mod.ExportFile != "foo.a-main" {
3434
t.Fatalf("unexpected export file: %s", mod.ExportFile)
3535
}
@@ -59,7 +59,7 @@ func TestGenMainModuleLibrary(t *testing.T) {
5959
},
6060
}
6161
pkg := &packages.Package{PkgPath: "example.com/foo", ExportFile: "foo.a"}
62-
mod := genMainModule(ctx, llssa.PkgRuntime, pkg, false, false, false)
62+
mod := genMainModule(ctx, llssa.PkgRuntime, pkg, false, false, false, nil)
6363
ir := mod.LPkg.String()
6464
if strings.Contains(ir, "define i32 @main") {
6565
t.Fatalf("library mode should not emit main function:\n%s", ir)

0 commit comments

Comments
 (0)