aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cmd/link/internal/ld/lib.go2
-rw-r--r--src/cmd/link/internal/ld/symtab.go35
-rw-r--r--src/plugin/plugin_dlopen.go8
-rw-r--r--src/runtime/plugin.go9
-rw-r--r--src/runtime/symtab.go12
5 files changed, 60 insertions, 6 deletions
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 8c2d31c841..e4c34750c7 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -720,7 +720,7 @@ func objfile(ctxt *Link, lib *Library) {
goto out
}
- if Buildmode == BuildmodeShared {
+ if Buildmode == BuildmodeShared || Buildmode == BuildmodePlugin || ctxt.Syms.ROLookup("plugin.Open", 0) != nil {
before := f.Offset()
pkgdefBytes := make([]byte, atolwhex(arhdr.size))
if _, err := io.ReadFull(f, pkgdefBytes); err != nil {
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index 323136c6f9..98ce3ad79b 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -530,6 +530,20 @@ func (ctxt *Link) symtab() {
Addaddr(ctxt, abihashgostr, hashsym)
adduint(ctxt, abihashgostr, uint64(hashsym.Size))
}
+ if Buildmode == BuildmodePlugin || ctxt.Syms.ROLookup("plugin.Open", 0) != nil {
+ for _, l := range ctxt.Library {
+ s := ctxt.Syms.Lookup("go.link.pkghashbytes."+l.Pkg, 0)
+ s.Attr |= AttrReachable
+ s.Type = obj.SRODATA
+ s.Size = int64(len(l.hash))
+ s.P = []byte(l.hash)
+ str := ctxt.Syms.Lookup("go.link.pkghash."+l.Pkg, 0)
+ str.Attr |= AttrReachable
+ str.Type = obj.SRODATA
+ Addaddr(ctxt, str, s)
+ adduint(ctxt, str, uint64(len(l.hash)))
+ }
+ }
nsections := textsectionmap(ctxt)
@@ -604,7 +618,28 @@ func (ctxt *Link) symtab() {
}
if Buildmode == BuildmodePlugin {
addgostring(ctxt, moduledata, "go.link.thispluginpath", *flagPluginPath)
+
+ pkghashes := ctxt.Syms.Lookup("go.link.pkghashes", 0)
+ pkghashes.Attr |= AttrReachable
+ pkghashes.Attr |= AttrLocal
+ pkghashes.Type = obj.SRODATA
+
+ for i, l := range ctxt.Library {
+ // pkghashes[i].name
+ addgostring(ctxt, pkghashes, fmt.Sprintf("go.link.pkgname.%d", i), l.Pkg)
+ // pkghashes[i].linktimehash
+ addgostring(ctxt, pkghashes, fmt.Sprintf("go.link.pkglinkhash.%d", i), string(l.hash))
+ // pkghashes[i].runtimehash
+ hash := ctxt.Syms.ROLookup("go.link.pkghash."+l.Pkg, 0)
+ Addaddr(ctxt, pkghashes, hash)
+ }
+ Addaddr(ctxt, moduledata, pkghashes)
+ adduint(ctxt, moduledata, uint64(len(ctxt.Library)))
+ adduint(ctxt, moduledata, uint64(len(ctxt.Library)))
} else {
+ adduint(ctxt, moduledata, 0) // pluginpath
+ adduint(ctxt, moduledata, 0)
+ adduint(ctxt, moduledata, 0) // pkghashes slice
adduint(ctxt, moduledata, 0)
adduint(ctxt, moduledata, 0)
}
diff --git a/src/plugin/plugin_dlopen.go b/src/plugin/plugin_dlopen.go
index f4addde74c..c5b0a4721c 100644
--- a/src/plugin/plugin_dlopen.go
+++ b/src/plugin/plugin_dlopen.go
@@ -69,7 +69,11 @@ func open(name string) (*Plugin, error) {
name = name[:len(name)-3]
}
- pluginpath, syms := lastmoduleinit()
+ pluginpath, syms, mismatchpkg := lastmoduleinit()
+ if mismatchpkg != "" {
+ pluginsMu.Unlock()
+ return nil, errors.New("plugin.Open: plugin was built with a different version of package " + mismatchpkg)
+ }
if plugins == nil {
plugins = make(map[string]*Plugin)
}
@@ -131,4 +135,4 @@ var (
)
// lastmoduleinit is defined in package runtime
-func lastmoduleinit() (pluginpath string, syms map[string]interface{})
+func lastmoduleinit() (pluginpath string, syms map[string]interface{}, mismatchpkg string)
diff --git a/src/runtime/plugin.go b/src/runtime/plugin.go
index 7907936e14..845bf76e92 100644
--- a/src/runtime/plugin.go
+++ b/src/runtime/plugin.go
@@ -7,7 +7,7 @@ package runtime
import "unsafe"
//go:linkname plugin_lastmoduleinit plugin.lastmoduleinit
-func plugin_lastmoduleinit() (path string, syms map[string]interface{}) {
+func plugin_lastmoduleinit() (path string, syms map[string]interface{}, mismatchpkg string) {
md := firstmoduledata.next
if md == nil {
throw("runtime: no plugin module data")
@@ -41,6 +41,11 @@ func plugin_lastmoduleinit() (path string, syms map[string]interface{}) {
throw("plugin: new module data overlaps with previous moduledata")
}
}
+ for _, pkghash := range md.pkghashes {
+ if pkghash.linktimehash != *pkghash.runtimehash {
+ return "", nil, pkghash.modulename
+ }
+ }
// Initialize the freshly loaded module.
modulesinit()
@@ -74,7 +79,7 @@ func plugin_lastmoduleinit() (path string, syms map[string]interface{}) {
}
syms[name] = val
}
- return md.pluginpath, syms
+ return md.pluginpath, syms, ""
}
// inRange reports whether v0 or v1 are in the range [r0, r1].
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index bba3ccfc20..686af08ef0 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -202,7 +202,9 @@ type moduledata struct {
ptab []ptabEntry
- pluginpath string
+ pluginpath string
+ pkghashes []modulehash
+
modulename string
modulehashes []modulehash
@@ -213,10 +215,18 @@ type moduledata struct {
next *moduledata
}
+// A modulehash is used to compare the ABI of a new module or a
+// package in a new module with the loaded program.
+//
// For each shared library a module links against, the linker creates an entry in the
// moduledata.modulehashes slice containing the name of the module, the abi hash seen
// at link time and a pointer to the runtime abi hash. These are checked in
// moduledataverify1 below.
+//
+// For each loaded plugin, the the pkghashes slice has a modulehash of the
+// newly loaded package that can be used to check the plugin's version of
+// a package against any previously loaded version of the package.
+// This is done in plugin.lastmoduleinit.
type modulehash struct {
modulename string
linktimehash string