简体   繁体   中英

Is there a way to execute functions in a compiled golang binary from another binary without needing any special setup?

I have a RPC type of setup where one binary (binaryA) is requesting work to be done from another binary (binaryB). They're both compiled the same way and are on the same system. I can't shell out to binaryA because the task involved involves a lot of data which would take too long to serialize and I can't use a golang plugin because the I want to be able to call functions without needing to create a special binary.

This is roughly the setup I'm trying to achieve:

binaryA compiled with go build mainA.go . Somewhere in that binary, this file is compiled:

package demo
import "fmt"

func TestFn(){
    fmt.Println("binaryA")
    func(){ someFn() }()
}

I want to be able to call TestFn() and that anonymous function with binaryB.

Here's what I have so far.

import (
    "debug/macho"
    "fmt"
    "os"
    "reflect"
    "unsafe"
)

func main() {
    filename := "binaryA"
    f, _ := os.Open(filename)
    defer f.Close()

    mf, _ := macho.NewFile(f)

    sym2Addr := make(map[string]uintptr)
    for _, sym := range mf.Symtab.Syms {
        if int(sym.Sect-1) >= len(mf.Sections) || 
           mf.Sections[sym.Sect-1].Seg != "__TEXT" { continue }
        value := uintptr(sym.Value)
        sym2Addr[sym.Name] = value
    }

    funcType := reflect.TypeOf(func() {})
    if testFnPtr, ok := sym2Addr["main.TestFn"]; ok {
        TestFn := reflect.New(funcType).Elem()
        p := new(uintptr)
        *p = testFnPtr
        *(*unsafe.Pointer)(unsafe.Pointer(TestFn.Addr().Pointer())) = unsafe.Pointer(p)
        TestFn.Call([]reflect.Value{})
    }
}

Using the code above I'm able to find the symbol main.TestFn but it ultimately fails with:

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

goroutine 1 [running]:
runtime.throw(...)
        .asdf/installs/golang/1.15/go/src/runtime/panic.go:1116 
runtime.sigpanic()
        .asdf/installs/golang/1.15/go/src/runtime/signal_unix.go:717
runtime.call32(...)
        .asdf/installs/golang/1.15/go/src/runtime/asm_amd64.s:540 
reflect.Value.call(...)
        .asdf/installs/golang/1.15/go/src/reflect/value.go:475 
reflect.Value.Call(...)
        .asdf/installs/golang/1.15/go/src/reflect/value.go:336
main.main()
        plugin_demo.go:106
runtime.main()
        .asdf/installs/golang/1.15/go/src/runtime/proc.go:204
runtime.goexit()
        .asdf/installs/golang/1.15/go/src/runtime/asm_amd64.s:1374
exit status 2

EDIT: I can recompile binaryA with any build flags I want.

Is there a way to execute functions in a compiled golang binary from another binary without needing any special setup?

No, that simply is not how compiled (to machine code) programs work (in any language).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM