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 
go:linkname plugin_lastmoduleinit plugin.lastmoduleinit
func () ( string,  map[string]interface{},  string) {
	var  *moduledata
	for  := firstmoduledata.next;  != nil;  = .next {
		if .bad {
			 = nil // we only want the last module
			continue
		}
		 = 
	}
	if  == nil {
		throw("runtime: no plugin module data")
	}
	if .pluginpath == "" {
		throw("runtime: plugin has empty pluginpath")
	}
	if .typemap != nil {
		return "", nil, "plugin already loaded"
	}

	for ,  := range activeModules() {
		if .pluginpath == .pluginpath {
			.bad = true
			return "", nil, "plugin already loaded"
		}

		if inRange(.text, .etext, .text, .etext) ||
			inRange(.bss, .ebss, .bss, .ebss) ||
			inRange(.data, .edata, .data, .edata) ||
			inRange(.types, .etypes, .types, .etypes) {
			println("plugin: new module data overlaps with previous moduledata")
			println("\tpmd.text-etext=", hex(.text), "-", hex(.etext))
			println("\tpmd.bss-ebss=", hex(.bss), "-", hex(.ebss))
			println("\tpmd.data-edata=", hex(.data), "-", hex(.edata))
			println("\tpmd.types-etypes=", hex(.types), "-", hex(.etypes))
			println("\tmd.text-etext=", hex(.text), "-", hex(.etext))
			println("\tmd.bss-ebss=", hex(.bss), "-", hex(.ebss))
			println("\tmd.data-edata=", hex(.data), "-", hex(.edata))
			println("\tmd.types-etypes=", hex(.types), "-", hex(.etypes))
			throw("plugin: new module data overlaps with previous moduledata")
		}
	}
	for ,  := range .pkghashes {
		if .linktimehash != *.runtimehash {
			.bad = true
			return "", nil, "plugin was built with a different version of package " + .modulename
		}
	}
Initialize the freshly loaded module.
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.
	 = make(map[string]interface{}, len(.ptab))
	for ,  := range .ptab {
		 := resolveNameOff(unsafe.Pointer(.types), .name)
		 := (*_type)(unsafe.Pointer(.types)).typeOff(.typ)
		var  interface{}
		 := (*[2]unsafe.Pointer)(unsafe.Pointer(&))
		(*)[0] = unsafe.Pointer()

		 := .name()
		if .kind&kindMask == kindFunc {
			 = "." + 
		}
		[] = 
	}
	return .pluginpath, , ""
}

func ( *moduledata) {
	 := false
	for  := 0;  < len(.ftab); ++ {
		 := .ftab[].entry
		if .minpc <=  &&  <= .maxpc {
			continue
		}

		 := funcInfo{(*_func)(unsafe.Pointer(&.pclntable[.ftab[].funcoff])), }
		 := funcname()
A common bug is f.entry has a relocation to a duplicate function symbol, meaning if we search for its PC we get a valid entry with a name that is useful for debugging.
		 := "none"
		 := uintptr(0)
		 := findfunc()
		if .valid() {
			 = funcname()
			 = .entry
		}
		 = true
		println("ftab entry outside pc range: ", hex(), "/", hex(), ": ", , "/", )
	}
	if  {
		throw("runtime: plugin has bad symbol table")
	}
}
inRange reports whether v0 or v1 are in the range [r0, r1].
func (, , ,  uintptr) bool {
	return ( >=  &&  <= ) || ( >=  &&  <= )
}
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.