Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: alangpierce/go-forceexport
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: rpcxio/go-forceexport
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Able to merge. These branches can be automatically merged.
  • 2 commits
  • 4 files changed
  • 1 contributor

Commits on Apr 6, 2021

  1. check nil

    chaoyuepan committed Apr 6, 2021
    Copy the full SHA
    0510045 View commit details
  2. upgrade to support go 1.16

    chaoyuepan committed Apr 6, 2021
    Copy the full SHA
    57132a8 View commit details
Showing with 174 additions and 43 deletions.
  1. +3 −36 forceexport.go
  2. +7 −7 forceexport_test.go
  3. +3 −0 go.mod
  4. +161 −0 moduledata.go
39 changes: 3 additions & 36 deletions forceexport.go
Original file line number Diff line number Diff line change
@@ -58,6 +58,9 @@ func CreateFuncForCodePtr(outFuncPtr interface{}, codePtr uintptr) {
func FindFuncWithName(name string) (uintptr, error) {
for moduleData := &Firstmoduledata; moduleData != nil; moduleData = moduleData.next {
for _, ftab := range moduleData.ftab {
if int(ftab.funcoff) >= len(moduleData.pclntable) {
continue
}
f := (*runtime.Func)(unsafe.Pointer(&moduleData.pclntable[ftab.funcoff]))
if f.Name() == name {
return f.Entry(), nil
@@ -72,39 +75,3 @@ func FindFuncWithName(name string) (uintptr, error) {

//go:linkname Firstmoduledata runtime.firstmoduledata
var Firstmoduledata Moduledata

type Moduledata struct {
pclntable []byte
ftab []Functab
filetab []uint32
findfunctab uintptr
minpc, maxpc uintptr

text, etext uintptr
noptrdata, enoptrdata uintptr
data, edata uintptr
bss, ebss uintptr
noptrbss, enoptrbss uintptr
end, gcdata, gcbss uintptr

// Original type was []*_type
typelinks []interface{}

modulename string
// Original type was []modulehash
modulehashes []interface{}

gcdatamask, gcbssmask Bitvector

next *Moduledata
}

type Functab struct {
entry uintptr
funcoff uintptr
}

type Bitvector struct {
n int32 // # of bits
bytedata *uint8
}
14 changes: 7 additions & 7 deletions forceexport_test.go
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ func TestAddOne(t *testing.T) {
}

var addOneFunc func(x int) int
err := GetFunc(&addOneFunc, "github.com/alangpierce/go-forceexport.addOne")
err := GetFunc(&addOneFunc, "github.com/rpcxio/go-forceexport.addOne")
if err != nil {
t.Error("Expected nil error.")
}
@@ -39,21 +39,21 @@ func TestAddOne(t *testing.T) {

func TestGetSelf(t *testing.T) {
var getFunc func(interface{}, string) error
err := GetFunc(&getFunc, "github.com/alangpierce/go-forceexport.GetFunc")
err := GetFunc(&getFunc, "github.com/rpcxio/go-forceexport.GetFunc")
if err != nil {
t.Error("Error: %s", err)
t.Errorf("Error: %v", err)
}
// The two functions should share the same code pointer, so they should
// have the same string representation.
if fmt.Sprint(getFunc) != fmt.Sprint(GetFunc) {
if fmt.Sprintf("%p", getFunc) != fmt.Sprintf("%p", GetFunc) {
t.Errorf("Expected ")
}
// Call it again on itself!
err = getFunc(&getFunc, "github.com/alangpierce/go-forceexport.GetFunc")
err = getFunc(&getFunc, "github.com/rpcxio/go-forceexport.GetFunc")
if err != nil {
t.Error("Error: %s", err)
t.Errorf("Error: %v", err)
}
if fmt.Sprint(getFunc) != fmt.Sprint(GetFunc) {
if fmt.Sprintf("%p", getFunc) != fmt.Sprintf("%p", GetFunc) {
t.Errorf("Expected ")
}
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/rpcxio/go-forceexport

go 1.16
161 changes: 161 additions & 0 deletions moduledata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
package forceexport

import "unsafe"

// pcHeader holds data used by the pclntab lookups.
type pcHeader struct {
magic uint32 // 0xFFFFFFFA
pad1, pad2 uint8 // 0,0
minLC uint8 // min instruction size
ptrSize uint8 // size of a ptr in bytes
nfunc int // number of functions in the module
nfiles uint // number of entries in the file tab.
funcnameOffset uintptr // offset to the funcnametab variable from pcHeader
cuOffset uintptr // offset to the cutab variable from pcHeader
filetabOffset uintptr // offset to the filetab variable from pcHeader
pctabOffset uintptr // offset to the pctab varible from pcHeader
pclnOffset uintptr // offset to the pclntab variable from pcHeader
}

// Moduledata records information about the layout of the executable
// image. It is written by the linker. Any changes here must be
// matched changes to the code in cmd/internal/ld/symtab.go:symtab.
// moduledata is stored in statically allocated non-pointer memory;
// none of the pointers here are visible to the garbage collector.
type Moduledata struct {
pcHeader *pcHeader
funcnametab []byte
cutab []uint32
filetab []byte
pctab []byte
pclntable []byte
ftab []functab
findfunctab uintptr
minpc, maxpc uintptr

text, etext uintptr
noptrdata, enoptrdata uintptr
data, edata uintptr
bss, ebss uintptr
noptrbss, enoptrbss uintptr
end, gcdata, gcbss uintptr
types, etypes uintptr

textsectmap []textsect
typelinks []int32 // offsets from types
itablinks []*itab

ptab []ptabEntry

pluginpath string
pkghashes []modulehash

modulename string
modulehashes []modulehash

hasmain uint8 // 1 if module contains the main function, 0 otherwise

gcdatamask, gcbssmask bitvector

typemap map[int32]*_type // offset to *_rtype in previous module

bad bool // module failed to load and should be ignored

next *Moduledata
}

// initialize the plugin module's symbol map.
type ptabEntry struct {
name int32
typ int32
}

// 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 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
runtimehash *string
}

type functab struct {
entry uintptr
funcoff uintptr
}

// Mapping information for secondary text sections

type textsect struct {
vaddr uintptr // prelinked section vaddr
length uintptr // section length
baseaddr uintptr // relocated section address
}

// Information from the compiler about the layout of stack frames.
// Note: this type must agree with reflect.bitVector.
type bitvector struct {
n int32 // # of bits
bytedata *uint8
}

// layout of Itab known to compilers
// allocated in non-garbage-collected memory
// Needs to be in sync with
// ../cmd/compile/internal/gc/reflect.go:/^func.WriteTabs.
type itab struct {
inter *interfacetype
_type *_type
hash uint32 // copy of _type.hash. Used for type switches.
_ [4]byte
fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}

type interfacetype struct {
typ _type
pkgpath name
mhdr []imethod
}

// name is an encoded type name with optional extra data.
// See reflect/type.go for details.
type name struct {
bytes *byte
}

type imethod struct {
name int32
ityp int32
}

// Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize,
// ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and
// ../reflect/type.go:/^type.rtype.
// ../internal/reflectlite/type.go:/^type.rtype.
type _type struct {
size uintptr
ptrdata uintptr // size of memory prefix holding all pointers
hash uint32
tflag uint8
align uint8
fieldAlign uint8
kind uint8
// function for comparing objects of this type
// (ptr to object A, ptr to object B) -> ==?
equal func(unsafe.Pointer, unsafe.Pointer) bool
// gcdata stores the GC type data for the garbage collector.
// If the KindGCProg bit is set in kind, gcdata is a GC program.
// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
gcdata *byte
str int32
ptrToThis int32
}