Trampoline example

271 views
Skip to first unread message

Gert

unread,
May 9, 2020, 6:15:45 AM5/9/20
to golang-nuts
Hi, this is the smallest example I can think of but I have know idea how I am suppose to do the syscall and trampoline part?

./c/hello.c
---------
#include <stdio.h>
#include <string.h>


int hello(char *s) {
  char c[80];
  strcpy (c, s);
  sprintf(s, "hello %s", c);
  return 0;
}

clang -shared -fpic hello.c -o hello.dylib

./trampoline.s
-----------------

#include "textflag.h"

TEXT ·hello_trampoline(SB),NOSPLIT,$0-0
  JMP hello(SB)

./main.go
-----------

package main

import "unsafe"

//go:linkname hello_c hello_c
//go:cgo_import_dynamic hello_c hello "./c/hello.dylib"
func hello_c(s unsafe.Pointer) uintptr {
return syscall(funcPC(hello_trampoline), uintptr(s), uintptr(0), 0, 0, uintptr(s), 0)
}

func hello_trampoline()

func syscall(fn, a1, a2, a3, a4, a5, a6 uintptr) uintptr

//go:nosplit
func funcPC(f func()) uintptr {
   return **(**uintptr)(unsafe.Pointer(&f))
}

func main() {
  s := "test"
  hello_c(unsafe.Pointer(&s))
  print(s)
}

(go version devel +98d20fb235 Fri May 8 02:31:13 2020 +0000 darwin/amd64)

main.main: relocation target main.syscall not defined
main.hello_trampoline: relocation target hello not defined

Gert

unread,
May 9, 2020, 10:30:41 AM5/9/20
to golang-nuts
I am getting it to compile and run with this but I am struggling how you send a string pointer across a syscall that c can send back. Also not sure about the //go:nosplit I sprinkel around which one is actually right?

package main

import (
 
"syscall"
 
"unsafe"

 
"golang.org/x/sys/unix"
)

//go:linkname hello_t hello_c

//go:cgo_import_dynamic hello_c hello "./c/hello.dylib"
//go:nosplit
func hello_t
(s unsafe.Pointer) (uintptr, uintptr, syscall.Errno) {
 
return unix.Syscall6(funcPC(hello_trampoline), uintptr(s), uintptr(0),

 
0, 0, uintptr(s), 0)
}

func hello_trampoline
()

//go:nosplit
func funcPC
(f func()) uintptr {
 
return **(**uintptr)(unsafe.Pointer(&f))
}

func main
() {
 s
:= "test    "

 hello_t
(unsafe.Pointer(&s))
 
print(s)
}

> go build    
> ./trampoline
> test        %
>                                                                        









Gert

unread,
May 9, 2020, 3:55:47 PM5/9/20
to golang-nuts
This is the closest I get, I am out of ideas. Don't know why it runs but doesn't update the string.

go run .
test [116 101 115 116 0 0 0 0 0 0] 4 0 0

#include <stdio.h>
#include <string.h>

int hello(char *s) {
 
char c[80];
 strcpy
(c, s);
 sprintf
(s, "hello %s", c);

 printf
("------\n");
 
return 0;
}

#include "textflag.h"

TEXT
·hello_trampoline(SB),NOSPLIT,$0-0
 JMP hello_c
(SB)

package main

import (
 
"fmt"

 
"unsafe"

 
"golang.org/x/sys/unix"
)

//go:linkname hello_t hello_c
//go:cgo_import_dynamic hello_c hello "./c/hello.dylib"

//go:nosplit

func hello_t
(s unsafe.Pointer) (uintptr, uintptr, unix.Errno) {
 
return unix.Syscall(funcPC(hello_trampoline), uintptr(s), 0, 0)

}

func hello_trampoline
()

//go:nosplit
func funcPC
(f func()) uintptr {
 
return **(**uintptr)(unsafe.Pointer(&f))
}

func main
() {

 b
:= make([]byte, 10, 10)
 copy
(b, []byte("test"))
 r1
, r2, err := hello_t(unsafe.Pointer(&b[0]))
 fmt
.Printf("%s %v %d %d %d\n", b, b, r1, r2, err)
}

Ian Lance Taylor

unread,
May 9, 2020, 6:33:08 PM5/9/20
to Gert, golang-nuts
On Sat, May 9, 2020 at 12:56 PM Gert <gert.c...@gmail.com> wrote:
>
> This is the closest I get, I am out of ideas. Don't know why it runs but doesn't update the string.

I don't know what you are really trying to do, but I want to be clear
that this code is not supported. The supported way to call from Go to
C is to use cgo. See https://golang.org/cmd/cgo and
https://blog.golang.org/cgo.

One big problem I see in your code is that you are assuming that Go
and C use the same ABI. That is, that the arguments passed to the Go
function will be seen as the arguments passed to the C function. That
is not the case. When using the gc compiler, Go and C pass arguments
in different locations.

Ian
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/68003925-1a44-4b7c-8cec-21849784bee5%40googlegroups.com.

Gert

unread,
May 9, 2020, 7:17:36 PM5/9/20
to golang-nuts


On Sunday, May 10, 2020 at 12:33:08 AM UTC+2, Ian Lance Taylor wrote:
On Sat, May 9, 2020 at 12:56 PM Gert <gert....@gmail.com> wrote:
>
> This is the closest I get, I am out of ideas. Don't know why it runs but doesn't update the string.

I don't know what you are really trying to do, but I want to be clear
that this code is not supported.  The supported way to call from Go to
C is to use cgo.  See https://golang.org/cmd/cgo and
https://blog.golang.org/cgo.

One big problem I see in your code is that you are assuming that Go
and C use the same ABI.  That is, that the arguments passed to the Go
function will be seen as the arguments passed to the C function.  That
is not the case.  When using the gc compiler, Go and C pass arguments
in different locations.

Ian


The attempt was based on this aprouch https://go-review.googlesource.com/c/go/+/227037/17/src/crypto/x509/internal/macOS/corefoundation.go but trying to apply it to the most simple example I can think. Filippo Valsorda believes its possible to link sqlite into go without using cgo. I made the assumption a trampoline assembler jump is the only way to do that?

> To unsubscribe from this group and stop receiving emails from it, send an email to golan...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages