Commit 5005a339 authored by Ian Lance Taylor's avatar Ian Lance Taylor

cmd/cgo: put the real C function in the dynamic symbol table

In the past, cgo generated Go code and C code.  The C code was linked
into a shared library.  The Go code was built into an executable that
dynamically linked against that shared library.  C wrappers were
exported from the shared library, and the Go code called them.

It was all a long time ago, but in order to permit C code to call back
into Go, somebody implemented #pragma dynexport (https://golang.org/cl/661043)
to export a Go symbol into the dynamic symbol table.  Then that same
person added code to cgo to recognize //export comments
(https://golang.org/cl/853042).  The //export comments were implemented
by generating C code, to be compiled by GCC, that would refer to C code,
to be compiled by 6c, that would call the Go code.  The GCC code would
go into a shared library.  The code compiled by 6c would be in the Go
executable.  The GCC code needed to refer to the 6c code, so the 6c
function was marked with #pragma dynexport.  The important point here is
that #pragma dynexport was used to expose an internal detail of the
implementation of an exported function, because at the time it was
necessary.

Moving forward to today, cgo no longer generates a shared library and 6c
no longer exists.  It's still true that we have a function compiled by
GCC that refers to a wrapper function now written in Go.  In the normal
case today we are doing an external link, and we use a
//go:cgo_export_static function to make the Go wrapper function visible
to the C code under a known name.

The #pragma dynexport statement has become a //go:cgo_export_dynamic
comment on the Go code.  That comment only takes effect when doing
internal linking.  The comment tells the linker to put the symbol in the
dynamic symbol table.  That still makes sense for the now unusual case
of using internal linking with a shared library.

However, all the changes to this code have carefully preserved the
property that the //go:cgo_export_dynamic comment refers to an internal
detail of the implementation of an exported function.  That was
necessary a long time ago, but no longer makes sense.

This CL changes the code to put the actual C-callable function into the
dynamic symbol table.  I considered dropping the comment entirely, but
it turns out that there is even a test for this, so I preserved it.

Change-Id: I66a7958e366e5974363099bfaa6ba862ca327849
Reviewed-on: https://go-review.googlesource.com/17061
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: 's avatarMinux Ma <minux@golang.org>
parent 23791ee1
// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !windows
void call4029(void *arg) {
void (*fn)(void) = arg;
fn();
}
......@@ -9,32 +9,35 @@ package cgotest
/*
#include <dlfcn.h>
#cgo linux LDFLAGS: -ldl
extern void call4029(void *arg);
*/
import "C"
import (
"fmt"
"testing"
)
var callbacks int
//export IMPIsOpaque
func IMPIsOpaque() {
fmt.Println("isOpaque")
callbacks++
}
//export IMPInitWithFrame
func IMPInitWithFrame() {
fmt.Println("IInitWithFrame")
callbacks++
}
//export IMPDrawRect
func IMPDrawRect() {
fmt.Println("drawRect:")
callbacks++
}
//export IMPWindowResize
func IMPWindowResize() {
fmt.Println("windowDidResize:")
callbacks++
}
func test4029(t *testing.T) {
......@@ -42,6 +45,9 @@ func test4029(t *testing.T) {
loadThySelf(t, "IMPDrawRect")
loadThySelf(t, "IMPInitWithFrame")
loadThySelf(t, "IMPIsOpaque")
if callbacks != 4 {
t.Errorf("got %d callbacks, expected 4", callbacks)
}
}
func loadThySelf(t *testing.T, symbol string) {
......@@ -58,4 +64,5 @@ func loadThySelf(t *testing.T, symbol string) {
return
}
t.Log(symbol, symbol_address)
C.call4029(symbol_address)
}
......@@ -817,7 +817,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
goname += fn.Recv.List[0].Names[0].Name + "_"
}
goname += exp.Func.Name.Name
fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.Func.Name.Name)
fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName)
fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment