title: Is there a way to execute functions in a compiled golang binary from another binary without needing any special setup?
body: <p>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 <a href="https://golang.org/pkg/plugin/" rel="nofollow noreferrer">golang plugin</a> because the I want to be able to call functions without needing to create a special binary.</p>
  <p>This is roughly the setup I'm trying to achieve:</p>
  <p>binaryA compiled with <code>go build mainA.go</code>. Somewhere in that binary, this file is compiled:</p>
  <pre><code>package demo
  import &quot;fmt&quot;
  
  func TestFn(){
      fmt.Println(&quot;binaryA&quot;)
      func(){ someFn() }()
  }
  </code></pre>
  <p>I want to be able to call TestFn() and that anonymous function with binaryB.</p>
  <p>Here's what I have so far.</p>
  <pre><code>import (
      &quot;debug/macho&quot;
      &quot;fmt&quot;
      &quot;os&quot;
      &quot;reflect&quot;
      &quot;unsafe&quot;
  )
  
  func main() {
      filename := &quot;binaryA&quot;
      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) &gt;= len(mf.Sections) || 
             mf.Sections[sym.Sect-1].Seg != &quot;__TEXT&quot; { continue }
          value := uintptr(sym.Value)
          sym2Addr[sym.Name] = value
      }
  
      funcType := reflect.TypeOf(func() {})
      if testFnPtr, ok := sym2Addr[&quot;main.TestFn&quot;]; 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{})
      }
  }
  </code></pre>
  <p>Using the code above I'm able to find the symbol <code>main.TestFn</code> but it ultimately fails with:</p>
  <pre><code>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
  </code></pre>
  <p>EDIT:
  I can recompile binaryA with any build flags I want.</p>