Commit 12fc2173 authored by Russ Cox's avatar Russ Cox

cgo checkpoint.

can write all 3 output files and then compile them by hand.

R=r
DELTA=919  (841 added, 16 deleted, 62 changed)
OCL=34954
CL=34973
parent ffe83e58
......@@ -9,6 +9,32 @@ GOFILES=\
ast.go\
gcc.go\
main.go\
out.go\
util.go\
include $(GOROOT)/src/Make.cmd
# Tests
# TODO(rsc): Delete
gmp:
make cgo
cgo gmp.go
gcc -fPIC -O2 -o gcc.o -c _cgo_gcc.c
gcc -shared -o gmp.so gcc.o -L$(GOROOT)/pkg/$(GOOS)_$(GOARCH) -lcgo -lgmp
6c -D_64BIT -I$(GOROOT)/src/pkg/runtime _cgo_c.c
6g _cgo_go.go
gopack grc gmp.a _cgo_c.6 _cgo_go.6
6g pidigits.go
6l pidigits.6
LD_LIBRARY_PATH=.:$(GOROOT)/pkg/$(GOOS)_$(GOARCH) 6.out
stdio:
make cgo
cgo stdio.go
gcc -fPIC -O2 -o gcc.o -c _cgo_gcc.c
gcc -shared -Wl,--rpath -Wl,$(GOROOT)/pkg/$(GOOS)_$(GOARCH) -o main.so gcc.o -L$(GOROOT)/pkg/$(GOOS)_$(GOARCH) -lcgo
6c -D_64BIT -I$(GOROOT)/src/pkg/runtime _cgo_c.c
6g _cgo_go.go
6l _cgo_c.6 _cgo_go.6
LD_LIBRARY_PATH=.:$(GOROOT)/pkg/$(GOOS)_$(GOARCH) 6.out
......@@ -7,13 +7,13 @@
package main
import (
"debug/dwarf";
"fmt";
"go/ast";
"go/doc";
"go/parser";
"go/scanner";
"os";
"strings";
)
// A Cref refers to an expression of the form C.xxx in the AST.
......@@ -22,14 +22,35 @@ type Cref struct {
Expr *ast.Expr;
Context string; // "type", "expr", or "call"
TypeName bool; // whether xxx is a C type name
DebugType dwarf.Type; // the type of xxx
Type *Type; // the type of xxx
FuncType *FuncType;
}
// A Prog collects information about a cgo program.
type Prog struct {
AST *ast.File; // parsed AST
Preamble string; // C preamble (doc comment on import "C")
PackagePath string;
Package string;
Crefs []*Cref;
Typedef map[string]ast.Expr;
Vardef map[string]*Type;
Funcdef map[string]*FuncType;
}
// A Type collects information about a type in both the C and Go worlds.
type Type struct {
Size int64;
Align int64;
C string;
Go ast.Expr;
}
// A FuncType collects information about a function type in both the C and Go worlds.
type FuncType struct {
Params []*Type;
Result *Type;
Go *ast.FuncType;
}
func openProg(name string) *Prog {
......@@ -49,35 +70,64 @@ func openProg(name string) *Prog {
}
fatal("parsing %s: %s", name, err);
}
p.Package = p.AST.Name.Value;
// Find the import "C" line and get any extra C preamble.
found := false;
for _, d := range p.AST.Decls {
d, ok := d.(*ast.GenDecl);
// Delete the import "C" line along the way or convert it
// to an import of "unsafe" (needed for the translation of void*).
sawC := false;
sawUnsafe := false;
rewroteUnsafe := false;
w := 0;
for _, decl := range p.AST.Decls {
d, ok := decl.(*ast.GenDecl);
if !ok {
p.AST.Decls[w] = decl;
w++;
continue;
}
for _, s := range d.Specs {
s, ok := s.(*ast.ImportSpec);
if !ok {
continue;
}
if len(s.Path) != 1 || string(s.Path[0].Value) != `"C"` {
ws := 0;
for _, spec := range d.Specs {
s, ok := spec.(*ast.ImportSpec);
if !ok || len(s.Path) != 1 || string(s.Path[0].Value) != `"C"` {
if s != nil && len(s.Path) == 1 && string(s.Path[0].Value) == `"unsafe"` {
if rewroteUnsafe {
// we rewrote the import "C" into import "unsafe",
// so drop this one.
continue;
}
sawUnsafe = true;
}
d.Specs[ws] = spec;
ws++;
continue;
}
found = true;
sawC = true;
if s.Name != nil {
error(s.Path[0].Pos(), `cannot rename import "C"`);
}
if s.Doc != nil {
p.Preamble += doc.CommentText(s.Doc) + "\n";
}
else if len(d.Specs) == 1 && d.Doc != nil {
} else if len(d.Specs) == 1 && d.Doc != nil {
p.Preamble += doc.CommentText(d.Doc) + "\n";
}
if !sawUnsafe {
rewroteUnsafe = true;
s.Path[0].Value = strings.Bytes(`"unsafe"`);
d.Specs[ws] = spec;
ws++;
}
}
if ws == 0 {
continue;
}
d.Specs = d.Specs[0:ws];
p.AST.Decls[w] = d;
w++;
}
if !found {
p.AST.Decls = p.AST.Decls[0:w];
if !sawC {
error(noPos, `cannot find import "C"`);
}
......@@ -194,9 +244,9 @@ func walk(x interface{}, p *Prog, context string) {
walk(n.Lhs, p, "expr");
walk(n.Rhs, p, "expr");
case *ast.GoStmt:
walk(&n.Call, p, "expr");
walk(n.Call, p, "expr");
case *ast.DeferStmt:
walk(&n.Call, p, "expr");
walk(n.Call, p, "expr");
case *ast.ReturnStmt:
walk(n.Results, p, "expr");
case *ast.BranchStmt:
......@@ -253,7 +303,9 @@ func walk(x interface{}, p *Prog, context string) {
walk(n.Recv, p, "field");
}
walk(n.Type, p, "type");
walk(n.Body, p, "stmt");
if n.Body != nil {
walk(n.Body, p, "stmt");
}
case *ast.File:
walk(n.Decls, p, "decl");
......
This diff is collapsed.
......@@ -184,8 +184,13 @@ GCC structs, the parameters are __mpz_struct* instead of mpz_t.
package gmp
// #include <gmp.h>
// #include <stdlib.h>
import "C"
import (
"os";
"unsafe";
)
/*
* one of a kind
......@@ -200,11 +205,7 @@ type Int struct {
// NewInt returns a new Int initialized to x.
func NewInt(x int64) *Int {
z := new(Int);
z.init = true;
C.mpz_init(&z.i);
C.mpz_set(&z.i, x);
return z;
return new(Int).SetInt64(x);
}
// Int promises that the zero value is a 0, but in gmp
......@@ -218,27 +219,27 @@ func (z *Int) doinit() {
return;
}
z.init = true;
C.mpz_init(&z.i);
C.mpz_init(&z.i[0]);
}
// Bytes returns z's representation as a big-endian byte array.
func (z *Int) Bytes() []byte {
b := make([]byte, (z.Len() + 7) / 8);
n := C.size_t(len(b));
C.mpz_export(&b[0], &n, 1, 1, 1, 0, &z.i);
C.mpz_export(unsafe.Pointer(&b[0]), &n, 1, 1, 1, 0, &z.i[0]);
return b[0:n];
}
// Len returns the length of z in bits. 0 is considered to have length 1.
func (z *Int) Len() int {
z.doinit();
return int(C.mpz_sizeinbase(&z.i, 2));
return int(C.mpz_sizeinbase(&z.i[0], 2));
}
// Set sets z = x and returns z.
func (z *Int) Set(x *Int) *Int {
z.doinit();
C.mpz_set(&z.i, x);
C.mpz_set(&z.i[0], &x.i[0]);
return z;
}
......@@ -249,7 +250,7 @@ func (z *Int) SetBytes(b []byte) *Int {
if len(b) == 0 {
z.SetInt64(0);
} else {
C.mpz_import(&z.i, len(b), 1, 1, 1, 0, &b[0]);
C.mpz_import(&z.i[0], C.size_t(len(b)), 1, 1, 1, 0, unsafe.Pointer(&b[0]));
}
return z;
}
......@@ -258,7 +259,7 @@ func (z *Int) SetBytes(b []byte) *Int {
func (z *Int) SetInt64(x int64) *Int {
z.doinit();
// TODO(rsc): more work on 32-bit platforms
C.mpz_set_si(z, x);
C.mpz_set_si(&z.i[0], C.long(x));
return z;
}
......@@ -270,7 +271,9 @@ func (z *Int) SetString(s string, base int) os.Error {
if base < 2 || base > 36 {
return os.EINVAL;
}
if C.mpz_set_str(&z.i, s, base) < 0 {
p := C.CString(s);
defer C.free(unsafe.Pointer(p));
if C.mpz_set_str(&z.i[0], p, C.int(base)) < 0 {
return os.EINVAL;
}
return z;
......@@ -279,12 +282,15 @@ func (z *Int) SetString(s string, base int) os.Error {
// String returns the decimal representation of z.
func (z *Int) String() string {
z.doinit();
return C.mpz_get_str(nil, 10, &z.i);
p := C.mpz_get_str(nil, 10, &z.i[0]);
s := C.GoString(p);
C.free(unsafe.Pointer(p));
return s;
}
func (z *Int) destroy() {
if z.init {
C.mpz_clear(z);
C.mpz_clear(&z.i[0]);
}
z.init = false;
}
......@@ -299,7 +305,7 @@ func (z *Int) Add(x, y *Int) *Int {
x.doinit();
y.doinit();
z.doinit();
C.mpz_add(&z.i, &x.i, &y.i);
C.mpz_add(&z.i[0], &x.i[0], &y.i[0]);
return z;
}
......@@ -308,7 +314,7 @@ func (z *Int) Sub(x, y *Int) *Int {
x.doinit();
y.doinit();
z.doinit();
C.mpz_sub(&z.i, &x.i, &y.i);
C.mpz_sub(&z.i[0], &x.i[0], &y.i[0]);
return z;
}
......@@ -317,7 +323,7 @@ func (z *Int) Mul(x, y *Int) *Int {
x.doinit();
y.doinit();
z.doinit();
C.mpz_mul(&z.i, &x.i, &y.i);
C.mpz_mul(&z.i[0], &x.i[0], &y.i[0]);
return z;
}
......@@ -326,7 +332,7 @@ func (z *Int) Div(x, y *Int) *Int {
x.doinit();
y.doinit();
z.doinit();
C.mpz_tdiv_q(&z.i, &x.i, &y.i);
C.mpz_tdiv_q(&z.i[0], &x.i[0], &y.i[0]);
return z;
}
......@@ -336,24 +342,24 @@ func (z *Int) Mod(x, y *Int) *Int {
x.doinit();
y.doinit();
z.doinit();
C.mpz_tdiv_r(&z.i, &x.i, &y.i);
C.mpz_tdiv_r(&z.i[0], &x.i[0], &y.i[0]);
return z;
}
// Lsh sets z = x << s and returns z.
func (z *Int) Lsh(x *Int, s uint) *Int {
x.doinit();
y.doinit();
z.doinit();
C.mpz_mul_2exp(&z.i, &x.i, s);
C.mpz_mul_2exp(&z.i[0], &x.i[0], C.ulong(s));
return z;
}
// Rsh sets z = x >> s and returns z.
func (z *Int) Rsh(x *int, s uint) *Int {
func (z *Int) Rsh(x *Int, s uint) *Int {
x.doinit();
y.doinit();
z.doinit();
C.mpz_div_2exp(&z.i, &x.i, s);
C.mpz_div_2exp(&z.i[0], &x.i[0], C.ulong(s));
return z;
}
// Exp sets z = x^y % m and returns z.
......@@ -364,18 +370,26 @@ func (z *Int) Exp(x, y, m *Int) *Int {
y.doinit();
z.doinit();
if m == nil {
C.mpz_pow_ui(&z.i, &x.i, mpz_get_ui(&y.i));
C.mpz_pow_ui(&z.i[0], &x.i[0], C.mpz_get_ui(&y.i[0]));
} else {
C.mpz_powm(&z.i, &x.i, &y.i, &m.i);
C.mpz_powm(&z.i[0], &x.i[0], &y.i[0], &m.i[0]);
}
return z;
}
func (z *Int) Int64() int64 {
if !z.init {
return 0;
}
return int64(C.mpz_get_si(&z.i[0]));
}
// Neg sets z = -x and returns z.
func (z *Int) Neg(x *Int) *Int {
x.doinit();
z.doinit();
C.mpz_neg(&z.i, &x.i);
C.mpz_neg(&z.i[0], &x.i[0]);
return z;
}
......@@ -383,7 +397,7 @@ func (z *Int) Neg(x *Int) *Int {
func (z *Int) Abs(x *Int) *Int {
x.doinit();
z.doinit();
C.mpz_abs(&z.i, &x.i);
C.mpz_abs(&z.i[0], &x.i[0]);
return z;
}
......@@ -401,7 +415,13 @@ func (z *Int) Abs(x *Int) *Int {
func CmpInt(x, y *Int) int {
x.doinit();
y.doinit();
return C.mpz_cmp(&x.i, &y.i);
switch cmp := C.mpz_cmp(&x.i[0], &y.i[0]); {
case cmp < 0:
return -1;
case cmp == 0:
return 0;
}
return +1;
}
// DivModInt sets q = x / y and r = x % y.
......@@ -410,7 +430,7 @@ func DivModInt(q, r, x, y *Int) {
r.doinit();
x.doinit();
y.doinit();
C.mpz_tdiv_qr(&q.i, &r.i, &x.i, &y.i);
C.mpz_tdiv_qr(&q.i[0], &r.i[0], &x.i[0], &y.i[0]);
}
// GcdInt sets d to the greatest common divisor of a and b,
......@@ -423,5 +443,5 @@ func GcdInt(d, x, y, a, b *Int) {
y.doinit();
a.doinit();
b.doinit();
C.mpz_gcdext(&d.i, &x.i, &y.i, &a.i, &b.i);
C.mpz_gcdext(&d.i[0], &x.i[0], &y.i[0], &a.i[0], &b.i[0]);
}
......@@ -2,26 +2,28 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Cgo; see gmp.go for an overview.
// TODO(rsc):
// Emit correct line number annotations.
// Make 6g understand the annotations.
package main
import (
"flag";
"fmt";
"go/ast";
"os";
"tabwriter";
)
// Cgo; see gmp.go for an overview.
// TODO(rsc):
// Emit correct line number annotations.
// Make 6g understand the annotations.
func usage() {
fmt.Fprint(os.Stderr, "usage: cgo file.cgo\n");
flag.PrintDefaults();
}
const ptrSize = 8 // TODO
func main() {
flag.Usage = usage;
flag.Parse();
......@@ -32,15 +34,40 @@ func main() {
os.Exit(2);
}
p := openProg(args[0]);
p.loadDebugInfo();
p.Preamble = p.Preamble + "\n" + builtinProlog;
p.loadDebugInfo(ptrSize);
p.Vardef = make(map[string]*Type);
p.Funcdef = make(map[string]*FuncType);
tw := tabwriter.NewWriter(os.Stdout, 1, 1, ' ', 0);
for _, cref := range p.Crefs {
what := "value";
if cref.TypeName {
what = "type";
switch cref.Context {
case "call":
if !cref.TypeName {
// Is an actual function call.
*cref.Expr = &ast.Ident{Value: "_C_" + cref.Name};
p.Funcdef[cref.Name] = cref.FuncType;
break;
}
*cref.Expr = cref.Type.Go;
case "expr":
if cref.TypeName {
error((*cref.Expr).Pos(), "type C.%s used as expression", cref.Name);
}
// Reference to C variable.
// We declare a pointer and arrange to have it filled in.
*cref.Expr = &ast.StarExpr{X: &ast.Ident{Value: "_C_" + cref.Name}};
p.Vardef[cref.Name] = cref.Type;
case "type":
if !cref.TypeName {
error((*cref.Expr).Pos(), "expression C.%s used as type", cref.Name);
}
*cref.Expr = cref.Type.Go;
}
fmt.Fprintf(tw, "%s:\t%s %s\tC %s\t%s\n", (*cref.Expr).Pos(), cref.Context, cref.Name, what, cref.DebugType);
}
tw.Flush();
if nerrors > 0 {
os.Exit(2);
}
p.PackagePath = p.Package;
p.writeOutput(args[0], "_cgo_go.go", "_cgo_c.c", "_cgo_gcc.c");
}
// Copyright 2009 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.
package main
import (
"fmt";
"go/ast";
"go/printer";
"os";
)
// writeOutput creates output files to be compiled by 6g, 6c, and gcc.
// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
func (p *Prog) writeOutput(srcfile, go_, c, gcc string) {
fgo, err := os.Open(go_, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0666);
if err != nil {
fatal("%s", err);
}
fc, err := os.Open(c, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0666);
if err != nil {
fatal("%s", err);
}
fgcc, err := os.Open(gcc, os.O_WRONLY|os.O_CREAT|os.O_TRUNC, 0666);
if err != nil {
fatal("%s", err);
}
// Write Go output: Go input with rewrites of C.xxx to _C_xxx,
// then append the definitions of the _C_xxx types and vars and funcs.
fmt.Fprintf(fgo, "//line %s:1\n", srcfile);
printer.Fprint(fgo, p.AST, 0, 8);
fmt.Fprintf(fgo, "\n\n// Added by cgo\n");
for name, def := range p.Typedef {
fmt.Fprintf(fgo, "type %s ", name);
printer.Fprint(fgo, def, 0, 8);
fmt.Fprintf(fgo, "\n");
}
fmt.Fprintf(fgo, "type _C_void [0]byte\n");
// While we process the vars and funcs, also write 6c and gcc output.
// Gcc output starts with the preamble.
fmt.Fprintf(fgcc, "%s\n", p.Preamble);
fmt.Fprintf(fgcc, "%s\n", gccProlog);
fmt.Fprintf(fc, cProlog, p.Package, p.Package);
for name, def := range p.Vardef {
fmt.Fprintf(fc, "#pragma dynld %s·_C_%s %s \"%s.so\"\n", p.Package, name, name, p.PackagePath);
fmt.Fprintf(fgo, "var _C_%s ", name);
printer.Fprint(fgo, &ast.StarExpr{X: def.Go}, 0, 8);
fmt.Fprintf(fgo, "\n");
}
fmt.Fprintf(fc, "\n");
for name, def := range p.Funcdef {
// Go func declaration.
d := &ast.FuncDecl{
Name: &ast.Ident{Value: "_C_" + name},
Type: def.Go,
};
printer.Fprint(fgo, d, 0, 8);
fmt.Fprintf(fgo, "\n");
if name == "CString" || name == "GoString" {
// The builtins are already defined in the C prolog.
continue;
}
// Construct a gcc struct matching the 6c argument frame.
// Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
// These assumptions are checked by the gccProlog.
// Also assumes that 6c convention is to word-align the
// input and output parameters.
structType := "struct {\n";
off := int64(0);
npad := 0;
for i, t := range def.Params {
if off%t.Align != 0 {
pad := t.Align - off%t.Align;
structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
off += pad;
npad++;
}
structType += fmt.Sprintf("\t\t%s p%d;\n", t.C, i);
off += t.Size;
}
if off%ptrSize != 0 {
pad := ptrSize - off%ptrSize;
structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
off += pad;
npad++;
}
if t := def.Result; t != nil {
if off%t.Align != 0 {
pad := t.Align - off%t.Align;
structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
off += pad;
npad++;
}
structType += fmt.Sprintf("\t\t%s r;\n", t.C);
off += t.Size;
}
if off%ptrSize != 0 {
pad := ptrSize - off%ptrSize;
structType += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad);
off += pad;
npad++;
}
if len(def.Params) == 0 && def.Result == nil {
structType += "\t\tchar unused;\n"; // avoid empty struct
off++;
}
structType += "\t}";
argSize := off;
// C wrapper calls into gcc, passing a pointer to the argument frame.
// Also emit #pragma to get a pointer to the gcc wrapper.
fmt.Fprintf(fc, "#pragma dynld _cgo_%s _cgo_%s \"%s.so\"\n", name, name, p.PackagePath);
fmt.Fprintf(fc, "void (*_cgo_%s)(void*);\n", name);
fmt.Fprintf(fc, "\n");
fmt.Fprintf(fc, "void\n");
fmt.Fprintf(fc, "%s·_C_%s(struct{uint8 x[%d];}p)\n", p.Package, name, argSize);
fmt.Fprintf(fc, "{\n");
fmt.Fprintf(fc, "\tcgocall(_cgo_%s, &p);\n", name);
fmt.Fprintf(fc, "}\n");
fmt.Fprintf(fc, "\n");
// Gcc wrapper unpacks the C argument struct
// and calls the actual C function.
fmt.Fprintf(fgcc, "void\n");
fmt.Fprintf(fgcc, "_cgo_%s(void *v)\n", name);
fmt.Fprintf(fgcc, "{\n");
fmt.Fprintf(fgcc, "\t%s *a = v;\n", structType);
fmt.Fprintf(fgcc, "\t");
if def.Result != nil {
fmt.Fprintf(fgcc, "a->r = ");
}
fmt.Fprintf(fgcc, "%s(", name);
for i := range def.Params {
if i > 0 {
fmt.Fprintf(fgcc, ", ");
}
fmt.Fprintf(fgcc, "a->p%d", i);
}
fmt.Fprintf(fgcc, ");\n");
fmt.Fprintf(fgcc, "}\n");
fmt.Fprintf(fgcc, "\n");
}
}
const gccProlog = `
// Usual nonsense: if x and y are not equal, the type will be invalid
// (have a negative array count) and an inscrutable error will come
// out of the compiler and hopefully mention "name".
#define __cgo_compile_assert_eq(x, y, name) typedef char name[(x-y)*(x-y)*-2+1];
// Check at compile time that the sizes we use match our expectations.
#define __cgo_size_assert(t, n) __cgo_compile_assert_eq(sizeof(t), n, _cgo_sizeof_##t##_is_not_##n)
__cgo_size_assert(char, 1)
__cgo_size_assert(short, 2)
__cgo_size_assert(int, 4)
typedef long long __cgo_long_long;
__cgo_size_assert(__cgo_long_long, 8)
__cgo_size_assert(float, 4)
__cgo_size_assert(double, 8)
`
const builtinProlog = `
typedef struct { char *p; int n; } _GoString_;
_GoString_ GoString(char *p);
char *CString(_GoString_);
`
const cProlog = `
#include "runtime.h"
#include "cgocall.h"
#pragma dynld initcgo initcgo "libcgo.so"
#pragma dynld cgo cgo "libcgo.so"
#pragma dynld _cgo_malloc _cgo_malloc "libcgo.so"
#pragma dynld _cgo_free free "libcgo.so"
void
%s·_C_GoString(int8 *p, String s)
{
s = gostring((byte*)p);
FLUSH(&s);
}
void
%s·_C_CString(String s, int8 *p)
{
p = cmalloc(s.len+1);
mcpy((byte*)p, s.str, s.len);
p[s.len] = 0;
FLUSH(&p);
}
`
// Copyright 2009 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.
package main
// #include <stdio.h>
// #include <stdlib.h>
import "C"
type File C.FILE;
func (f *File) Putc(c int) {
C.putc(C.int(c), (*C.FILE)(f));
}
func (f *File) Puts(s string) {
p := C.CString(s);
C.fputs(p, (*C.FILE)(f));
C.free(unsafe.Pointer(p));
}
var Stdout = (*File)(C.stdout);
func main() {
Stdout.Puts("hello, world\n");
}
......@@ -294,3 +294,15 @@ wait:
}
}
// Helper.
void
_cgo_malloc(void *p)
{
struct a {
long long n;
void *ret;
} *a = p;
a->ret = malloc(a->n);
}
......@@ -47,3 +47,26 @@ runtime·Cgocalls(int64 ret)
FLUSH(&ret);
}
void (*_cgo_malloc)(void*);
void (*_cgo_free)(void*);
void*
cmalloc(uintptr n)
{
struct a {
uint64 n;
void *ret;
} a;
a.n = n;
a.ret = nil;
cgocall(_cgo_malloc, &a);
return a.ret;
}
void
cfree(void *p)
{
cgocall(_cgo_free, p);
}
......@@ -5,7 +5,8 @@
/*
* Cgo interface.
* Dynamically linked shared libraries compiled with gcc
* know these data structures too. See ../../libcgo/cgocall.c
* know these data structures and functions too.
* See ../../libcgo/cgocall.c
*/
typedef struct CgoWork CgoWork;
......@@ -37,3 +38,5 @@ struct CgoWork
void cgocall(void (*fn)(void*), void*);
void *cmalloc(uintptr);
void cfree(void*);
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