| // Copyright 2016 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package runtime | |
| import "unsafe" | |
| //go:linkname plugin_lastmoduleinit plugin.lastmoduleinit | |
| func plugin_lastmoduleinit() (path string, syms map[string]interface{}) { | |
| md := firstmoduledata.next | |
| if md == nil { | |
| throw("runtime: no plugin module data") | |
| } | |
| for md.next != nil { | |
| md = md.next | |
| } | |
| if md.typemap != nil { | |
| throw("runtime: plugin already initialized") | |
| } | |
| for _, pmd := range activeModules() { | |
| if pmd.pluginpath == md.pluginpath { | |
| println("plugin: plugin", md.pluginpath, "already loaded") | |
| throw("plugin: plugin already loaded") | |
| } | |
| if inRange(pmd.text, pmd.etext, md.text, md.etext) || | |
| inRange(pmd.bss, pmd.ebss, md.bss, md.ebss) || | |
| inRange(pmd.data, pmd.edata, md.data, md.edata) || | |
| inRange(pmd.types, pmd.etypes, md.types, md.etypes) { | |
| println("plugin: new module data overlaps with previous moduledata") | |
| println("\tpmd.text-etext=", hex(pmd.text), "-", hex(pmd.etext)) | |
| println("\tpmd.bss-ebss=", hex(pmd.bss), "-", hex(pmd.ebss)) | |
| println("\tpmd.data-edata=", hex(pmd.data), "-", hex(pmd.edata)) | |
| println("\tpmd.types-etypes=", hex(pmd.types), "-", hex(pmd.etypes)) | |
| println("\tmd.text-etext=", hex(md.text), "-", hex(md.etext)) | |
| println("\tmd.bss-ebss=", hex(md.bss), "-", hex(md.ebss)) | |
| println("\tmd.data-edata=", hex(md.data), "-", hex(md.edata)) | |
| println("\tmd.types-etypes=", hex(md.types), "-", hex(md.etypes)) | |
| throw("plugin: new module data overlaps with previous moduledata") | |
| } | |
| } | |
| // Initialize the freshly loaded module. | |
| modulesinit() | |
| typelinksinit() | |
| lock(&ifaceLock) | |
| for _, i := range md.itablinks { | |
| additab(i, true, false) | |
| } | |
| unlock(&ifaceLock) | |
| // Build a map of symbol names to symbols. Here in the runtime | |
| // we fill out the first word of the interface, the type. We | |
| // pass these zero value interfaces to the plugin package, | |
| // where the symbol value is filled in (usually via cgo). | |
| // | |
| // Because functions are handled specially in the plugin package, | |
| // function symbol names are prefixed here with '.' to avoid | |
| // a dependency on the reflect package. | |
| syms = make(map[string]interface{}, len(md.ptab)) | |
| for _, ptab := range md.ptab { | |
| symName := resolveNameOff(unsafe.Pointer(md.types), ptab.name) | |
| t := (*_type)(unsafe.Pointer(md.types)).typeOff(ptab.typ) | |
| var val interface{} | |
| valp := (*[2]unsafe.Pointer)(unsafe.Pointer(&val)) | |
| (*valp)[0] = unsafe.Pointer(t) | |
| name := symName.name() | |
| if t.kind&kindMask == kindFunc { | |
| name = "." + name | |
| } | |
| syms[name] = val | |
| } | |
| return md.pluginpath, syms | |
| } | |
| // inRange reports whether v0 or v1 are in the range [r0, r1]. | |
| func inRange(r0, r1, v0, v1 uintptr) bool { | |
| return (v0 >= r0 && v0 <= r1) || (v1 >= r0 && v1 <= r1) | |
| } | |
| // A ptabEntry is generated by the compiler for each exported function | |
| // and global variable in the main package of a plugin. It is used to | |
| // initialize the plugin module's symbol map. | |
| type ptabEntry struct { | |
| name nameOff | |
| typ typeOff | |
| } |