cmd/link: establish dependable package initialization order

(This is a retry of CL 462035 which was reverted at 474976.
The only change from that CL is the aix fix SRODATA->SNOPTRDATA
at inittask.go:141)

As described here:

https://github.com/golang/go/issues/31636#issuecomment-493271830

"Find the lexically earliest package that is not initialized yet,
but has had all its dependencies initialized, initialize that package,
 and repeat."

Simplify the runtime a bit, by just computing the ordering required
in the linker and giving a list to the runtime.

Update #31636
Fixes #57411

RELNOTE=yes

Change-Id: I28c09451d6aa677d7394c179d23c2c02c503fc56
Reviewed-on: https://go-review.googlesource.com/c/go/+/478916
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Keith Randall 2023-01-12 20:25:39 -08:00
parent d4bcfe4e83
commit 2b92c39fe0
14 changed files with 324 additions and 56 deletions

View file

@ -74,7 +74,7 @@ func open(name string) (*Plugin, error) {
if plugins == nil {
plugins = make(map[string]*Plugin)
}
pluginpath, syms, errstr := lastmoduleinit()
pluginpath, syms, initTasks, errstr := lastmoduleinit()
if errstr != "" {
plugins[filepath] = &Plugin{
pluginpath: pluginpath,
@ -92,14 +92,7 @@ func open(name string) (*Plugin, error) {
plugins[filepath] = p
pluginsMu.Unlock()
initStr := make([]byte, len(pluginpath)+len("..inittask")+1) // +1 for terminating NUL
copy(initStr, pluginpath)
copy(initStr[len(pluginpath):], "..inittask")
initTask := C.pluginLookup(h, (*C.char)(unsafe.Pointer(&initStr[0])), &cErr)
if initTask != nil {
doInit(initTask)
}
doInit(initTasks)
// Fill out the value of each plugin symbol.
updatedSyms := map[string]any{}
@ -147,9 +140,14 @@ var (
)
// lastmoduleinit is defined in package runtime.
func lastmoduleinit() (pluginpath string, syms map[string]any, errstr string)
func lastmoduleinit() (pluginpath string, syms map[string]any, inittasks []*initTask, errstr string)
// doInit is defined in package runtime.
//
//go:linkname doInit runtime.doInit
func doInit(t unsafe.Pointer) // t should be a *runtime.initTask
func doInit(t []*initTask)
type initTask struct {
// fields defined in runtime.initTask. We only handle pointers to an initTask
// in this package, so the contents are irrelevant.
}