Giter VIP home page Giter VIP logo

goloader's Introduction

Goloader

Build Status

Goloader can load and run Golang code at runtime.

How does it work?

Goloader works like a linker: it relocates the address of symbols in an object file, generates runnable code, and then reuses the runtime function and the type pointer of the loader.

Goloader provides some information to the runtime and gc of Go, which allows it to work correctly with them.

Please note that Goloader is not a scripting engine. It reads the output of Go compiler and makes them runnable. All features of Go are supported, and run just as fast and lightweight as native Go code.

Comparison with plugin

Goloader reuses the Go runtime, which makes it much smaller. And code loaded by Goloader is unloadable.

Goloader is debuggable, and supports pprof tool(Yes, you can see code loaded by Goloader in pprof).

Build

Make sure you're using go >= 1.8.

First, execute the following command, then do build and test. This is because Goloader relies on the internal package, which is forbidden by the Go compiler.

cp -r $GOROOT/src/cmd/internal $GOROOT/src/cmd/objfile

Examples

go build github.com/dearplain/goloader/examples/loader

go tool compile $GOPATH/src/github.com/dearplain/goloader/examples/schedule/schedule.go
./loader -o schedule.o -run main.main -times 10

go tool compile $GOPATH/src/github.com/dearplain/goloader/examples/base/base.go
./loader -o base.o -run main.main

go tool compile $GOPATH/src/github.com/dearplain/goloader/examples/http/http.go
./loader -o http.o -run main.main

#build multiple go files
go tool compile -I $GOPATH/pkg/darwin_amd64 1.go 2.go

#build for arm32
GOOS=linux GOARCH=arm GOARM=5 go install fmt runtime sync net/http time
GOOS=linux GOARCH=arm GOARM=5 go build github.com/dearplain/goloader/examples/loader
GOOS=linux GOARCH=arm GOARM=5 go tool compile $GOPATH/src/github.com/dearplain/goloader/examples/base/base.go
#test on arm32 linux
./loader -o base.o -run main.main

Warning

This has currently only been tested and developed on Golang 1.8, 1.9, and 1.10 (x64/x86, darwin, linux, windows). Be aware of Golang's internal structs change, especially the moduledata struct.

goloader's People

Contributors

dearplain avatar inklit avatar paralax avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

goloader's Issues

Stacktraces result in panic

Trying to call debug.PrintStack() from runtime/debug results in runtime panic:
code:

func main2(a int) error {
        fmt.Println(a)
        debug.PrintStack()
        return nil
}
Load error: unresolve external: runtime/debug.PrintStack
unresolve external: runtime/debug.init

322
unexpected fault address 0xc420065f78
fatal error: fault
[signal SIGBUS: bus error code=0x2 addr=0xc420065f78 pc=0xc420065f78]

goroutine 1 [running]:
runtime.throw(0x1350dcd, 0x5)
	/usr/local/go/src/runtime/panic.go:616 +0x81 fp=0xc420065d68 sp=0xc420065d48 pc=0x102ac11
runtime.sigpanic()
	/usr/local/go/src/runtime/signal_unix.go:385 +0x273 fp=0xc420065db8 sp=0xc420065d68 pc=0x103f6d3
main.main()
	/Users/dobegor/go/src/github.com/dearplain/goloader/examples/loader/loader.go:75 +0x763 fp=0xc420065f88 sp=0xc420065db8 pc=0x1299863
runtime.main()
	/usr/local/go/src/runtime/proc.go:198 +0x212 fp=0xc420065fe0 sp=0xc420065f88 pc=0x102c482
runtime.goexit()
	/usr/local/go/src/runtime/asm_amd64.s:2361 +0x1 fp=0xc420065fe8 sp=0xc420065fe0 pc=0x1055c01

Type assertions error.

DEMO

When call func with map[string]interface{}args, type assertion inside method failed.

map[string]interface{} => map[string]interface {}

Run

cd $GOPATH/src/github.com/nzlov/goloader
go tool compile -I $GOPATH/pkg/darwin_amd64/ -o c.o typeassertion/c.go
go run typeassertion/main.go c.o

Error

Plugin Init Params Error:agrs need 1 is map[string]interface{} but it's map[string]interface {}

getitab panic runtime error

DEMO

ENV:

GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/nzlov/Library/Caches/go-build"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/nzlov/workspace/go"
GORACE=""
GOROOT="/Users/nzlov/program/go"
GOTMPDIR=""
GOTOOLDIR="/Users/nzlov/program/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/8j/s77lh5993lj9y98_mm7f3mmr0000gn/T/go-build898165777=/tmp/go-build -gno-record-gcc-switches -fno-common"

Run:

go tool compile -I $GOPATH/pkg/darwin_amd64/ a.go
go run main.go a.o

Panic:

panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x13 pc=0x100eb3f]

goroutine 1 [running]:
github.com/dearplain/goloader.Load(0xc4200c4e00, 0xc4201829f0, 0x0, 0x0, 0x0)
	/Users/nzlov/workspace/go/src/github.com/dearplain/goloader/dymcode.go:503 +0x296c
github.com/nzlov/testgoloader/engine.(*Plugin).Load(0xc4200a0180, 0xc4201829f0, 0xc42029c960, 0x1, 0x1, 0x0, 0x0)
	/Users/nzlov/workspace/go/src/github.com/nzlov/testgoloader/engine/engine.go:55 +0xd9
main.reload(0x1694ae0, 0xc4200a0180)
	/Users/nzlov/workspace/go/src/github.com/nzlov/testgoloader/main.go:59 +0x8c
main.main()
	/Users/nzlov/workspace/go/src/github.com/nzlov/testgoloader/main.go:26 +0xb3
exit status 2

Errors on Go 1.11

As you probably saw in the Travis builds, something isn't quite right when using Goloader with Go 1.11. Here is the output of running the 'base' example with the example loader:


unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

unknown gcobj: 

Load error: offset overflow sym: runtime.writeBarrier 

{1 2}

{1 2} &{1 2} {1 0} {0 0}

main.Vertex{X:1, Y:2} &main.Vertex{X:1, Y:2} main.Vertex{X:1, Y:0} main.Vertex{X:0, Y:0}

print &{1 2}

[John Paul George Ringo]

[{2 true} {3 false}]

map[Bell Labs:{40 -74} Google:{37 -122}]

Don't know type string

I'm a bool

runtime stack:

runtime.Stack.func1()

	/home/travis/.gimme/versions/go1.11.2.linux.amd64/src/runtime/mprof.go:798 +0xdd

goroutine 1 [running]:

runtime.systemstack_switch()

	/home/travis/.gimme/versions/go1.11.2.linux.amd64/src/runtime/asm_amd64.s:311 fp=0xc000381528 sp=0xc000381520 pc=0x4560e0

runtime.Stack(0xc0000e8400, 0x400, 0x400, 0xc0000e8400, 0x400)

	/home/travis/.gimme/versions/go1.11.2.linux.amd64/src/runtime/mprof.go:790 +0xec fp=0xc000381598 sp=0xc000381528 pc=0x42746c

<autogenerated>(...)

	/home/travis/gopath/src/github.com/dearplain/goloader/examples/base/base.go:115

fatal error: index out of range

panic during panic

runtime stack:

runtime.Stack.func1()

	/home/travis/.gimme/versions/go1.11.2.linux.amd64/src/runtime/mprof.go:798 +0xdd

I'm posting the log from the Travis build because I'm on mobile atm, but I have tried it on my own box with Go 1.11 on Windows and gotten exactly the same result.

How to register third-party library variables?

DEMO

Run

go run main.go a.o

Panic

panic: unresolve external: github.com/nzlov/testgoloader/engine.Var1

goroutine 1 [running]:
main.main()
	/Users/nzlov/workspace/go/src/github.com/nzlov/testgoloader/main.go:28 +0x1d0
exit status 2

unresolve external mgo.v2

Load error: unresolve external: type.projectA/vendor/gopkg.in/mgo%2ev2.Database
unresolve external: type.*projectA/vendor/gopkg.in/mgo%2ev2.Session

When load goloadr on goloadr have panic

DEMO

ENV:

GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/nzlov/Library/Caches/go-build"
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/nzlov/workspace/go"
GORACE=""
GOROOT="/Users/nzlov/program/go"
GOTMPDIR=""
GOTOOLDIR="/Users/nzlov/program/go/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/8j/s77lh5993lj9y98_mm7f3mmr0000gn/T/go-build898165777=/tmp/go-build -gno-record-gcc-switches -fno-common"

Run:

go tool compile -I $GOPATH/pkg/darwin_amd64/ b1.go
go tool compile -I $GOPATH/pkg/darwin_amd64/ b.go
go run main.go b.o

Panic:

unexpected fault address 0x86f2e316a
fatal error: fault
[signal SIGSEGV: segmentation violation code=0x1 addr=0x86f2e316a pc=0x100d0bf]

goroutine 1 [running]:
runtime.throw(0x171795a, 0x5)
	/Users/nzlov/program/go/src/runtime/panic.go:616 +0x81 fp=0xc4206ed958 sp=0xc4206ed938 pc=0x102b2d1
runtime.sigpanic()
	/Users/nzlov/program/go/src/runtime/signal_unix.go:395 +0x211 fp=0xc4206ed9a8 sp=0xc4206ed958 pc=0x103fe31
runtime.mapassign_faststr(0x1639c00, 0x86f2e3162, 0xc420295848, 0x8, 0x3)
	/Users/nzlov/program/go/src/runtime/hashmap_fast.go:702 +0x2f fp=0xc4206eda18 sp=0xc4206ed9a8 pc=0x100d0bf
github.com/dearplain/goloader.regTypeInfo(0x86f2e3162, 0x1609e40, 0x17a5f38, 0x82)
	/Users/nzlov/workspace/go/src/github.com/dearplain/goloader/type.go:144 +0x211 fp=0xc4206edac8 sp=0xc4206eda18 pc=0x119efc1
github.com/dearplain/goloader.RegTypes(0x86f2e3162, 0xc4206edcb8, 0x13, 0x13)
	/Users/nzlov/workspace/go/src/github.com/dearplain/goloader/type.go:105 +0xa4 fp=0xc4206edb30 sp=0xc4206edac8 pc=0x119ed34
github.com/dearplain/goloader.RegSymbol(0x86f2e3162)
	/Users/nzlov/workspace/go/src/github.com/dearplain/goloader/register.go:40 +0x408 fp=0xc4206eddf8 sp=0xc4206edb30 pc=0x119e1d8
main.PluginLoad(0xc420095170, 0x1, 0x1, 0xf, 0xc420185d00, 0x1, 0x10125b8, 0x10, 0x160f760)
	/Users/nzlov/workspace/go/src/github.com/nzlov/testgoloader/b.go:26 +0x6c fp=0xc4206ede78 sp=0xc4206eddf8 pc=0x1dd40da
github.com/nzlov/testgoloader/engine.(*Plugin).Load(0xc4200a0180, 0xc42016e8a0, 0xc420095170, 0x1, 0x1, 0x0, 0x0)
	/Users/nzlov/workspace/go/src/github.com/nzlov/testgoloader/engine/engine.go:66 +0x180 fp=0xc4206edee0 sp=0xc4206ede78 pc=0x119fe30
main.reload(0x1694aa0, 0xc4200a0180)
	/Users/nzlov/workspace/go/src/github.com/nzlov/testgoloader/main.go:58 +0x8c fp=0xc4206edf28 sp=0xc4206edee0 pc=0x159f3ec
main.main()
	/Users/nzlov/workspace/go/src/github.com/nzlov/testgoloader/main.go:25 +0x8a fp=0xc4206edf88 sp=0xc4206edf28 pc=0x159f0fa
runtime.main()
	/Users/nzlov/program/go/src/runtime/proc.go:198 +0x212 fp=0xc4206edfe0 sp=0xc4206edf88 pc=0x102cb42
runtime.goexit()
	/Users/nzlov/program/go/src/runtime/asm_amd64.s:2361 +0x1 fp=0xc4206edfe8 sp=0xc4206edfe0 pc=0x1056561
exit status 2

Load error: unresolve external: type..importpath.main.

When using the examples given (HTTP example specifically, haven't tested the others) - this error appears.
Load error: unresolve external: type..importpath.main.
The program appears to run just fine, but the error is concerning nonetheless.
I am unsure as to what causes it or how to fix it.

Windows ?

This is quite useful.
Does this work on Windows ?

unresolve external: strconv.init

a.o

package main
   
import "strconv"

func StringToInt(a string) int64 {
    b, _ := strconv.ParseInt(a, 10, 64)
    return b
}

main.go

goloader.RegTypes(symPtr,strconv.ParseInt)

Out:

Load error: unresolve external: runtime.morestack_noctxt
unresolve external: runtime.throwinit
unresolve external: strconv.init

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.