Slide 1

Slide 1 text

Interfacing C libraries with GO 11 April 2014 Cheng-Lung Sung Interfacing C libraries with GO

Slide 2

Slide 2 text

About me A software developer, half-retired FreeBSD ports committer. Previously a start-up co-founder. 腸 胃炎,所以 osdc.tw 的名產:美⻝⾷食..... Current working in ... coding ... Interfacing C libraries with GO

Slide 3

Slide 3 text

聽說要有梗? $ google://⾹香蕉 向⽇日葵 Interfacing C libraries with GO

Slide 4

Slide 4 text

What I will not talk about... Introduction to GO Interfacing C++ libraries with GO GO interface to C++ code, or vice versa. Advance cgo topics such as DLL-linking with cgo We're hiring 逐條審查(?) Interfacing C libraries with GO

Slide 5

Slide 5 text

What I will talk about... What is cgo Why use cgo How to use cgo hello world examples using cgo Some openssl examples (Heartbleed Bug (http://heartbleed.com) 正夯!!!) Interfacing C libraries with GO

Slide 6

Slide 6 text

Introduction to cgo Cgo enables the creation of Go packages that call C code. Ability to use existing C code Tool to generate code to access C library functions and global variables Interfacing C libraries with GO

Slide 7

Slide 7 text

C++ The link to the Go FAQ: Do Go programs link with C/C++ programs (http://golang.org/doc/go_faq.html#Do_Go_programs_link_with_Cpp_programs) Interfacing C libraries with GO

Slide 8

Slide 8 text

If you need to work with C++ Use SWIG 22.1 Overview Go is a compiled language, not a scripting language. However, it does not support direct calling of functions written in C/C++. The cgo program may be used to generate wrappers to call C code from Go, but there is no convenient way to call C++ code. SWIG fills this gap. There are (at least) two different Go compilers. One is the gc compiler, normally invoked under the names 6g, 8g, or 5g. The other is the gccgo compiler, which is a frontend to the gcc compiler suite. The interface to C/C++ code is completely different for the two Go compilers. SWIG supports both, selected by a command line option. Reference SWIG and Go (http://www.swig.org/Doc2.0/Go.html) Interfacing C libraries with GO

Slide 9

Slide 9 text

How to use cgo call C from GO $ go run foo.go $ go build call GO from C $ go build; $ ./ Interfacing C libraries with GO

Slide 10

Slide 10 text

A typical `Hello world` example in Go 講 Go 的東⻄西,就是要⽤用 Go present 啦!!! $ present 2014/04/11 14:55:59 Open your web browser and visit http://127.0.0.1:3999/ package main import "fmt" func main() { fmt.Println("Hello World") } Run Interfacing C libraries with GO

Slide 11

Slide 11 text

call C from GO create a new .go embed the C code block you want to interface as comment block following with import "C" write some code $ go build xxxx.go run it $ ./xxxx Interfacing C libraries with GO

Slide 12

Slide 12 text

#cgo directives In .go: `CFLAGS`, `CPPFLAGS`, `CXXFLAGS`, `LDFLAGS` // #cgo CFLAGS: -DPNG_DEBUG=1 // #cgo amd64 386 CFLAGS: -DX86=1 // #cgo LDFLAGS: -lpng If using makefile or ENV `CGO_CFLAGS`, `CGO_CPPFLAGS`, `CGO_CXXFLAGS`, `CGO_LDFLAGS` Interfacing C libraries with GO

Slide 13

Slide 13 text

call C from GO package main // #include // #include import "C" import "unsafe" func main() { str := C.CString("Hello, world!\n") defer C.free(unsafe.Pointer(str)) C.printf(str) } Run Interfacing C libraries with GO

Slide 14

Slide 14 text

call C from GO package main // #include // #include import "C" import "unsafe" import "fmt" func main() { str := C.CString("Hello, world!\n") defer C.free(unsafe.Pointer(str)) fmt.Println(C.GoString(str)) } Run Interfacing C libraries with GO

Slide 15

Slide 15 text

call C code from GO /* # #i in nc cl lu ud de e < > # #i in nc cl lu ud de e < > # #i in nc cl lu ud de e < > c ch ha ar r * * f fo or rm ma at t( (c ch ha ar r* * s s) ) { { char *buf; buf = malloc(strlen(s)); sprintf(buf, "%s", s); return buf; } */ import "C" Interfacing C libraries with GO

Slide 16

Slide 16 text

call C code from GO func main() { c cs s : := = C C. .f fo or rm ma at t( (C C. .C CS St tr ri in ng g( (" "H He el ll lo o w wo or rl ld d\ \n n" ") )) ) defer C.free(unsafe.Pointer(cs)) fmt.Println(C.GoString(cs)) } Hello world Program exited. Run Kill Close Interfacing C libraries with GO

Slide 17

Slide 17 text

common mistake beware the newline between C code and import "C" package main /* #include "stdio.h" */ i im mp po or rt t " "C C" " func main() { C.printf(C.CString("Hello world\n")) } Run Interfacing C libraries with GO

Slide 18

Slide 18 text

call GO from C (.go) extern the function from c code /* #include e ex xt te er rn n v vo oi id d A AC CF Fu un nc ct ti io on n( () ); ; */ add export / // /e ex xp po or rt t A AG Go oF Fu un nc ct ti io on n func AGoFunction() { fmt.Println("Hello GO World") } Interfacing C libraries with GO

Slide 19

Slide 19 text

call GO from C (.c) call from C #include "_cgo_export.h" void ACFunction() { printf("Hello C World\n"); AGoFunction(); } command line $ go build $ ./goc Hello C World Hello GO World Interfacing C libraries with GO

Slide 20

Slide 20 text

Dynamic linked library (OpenSSL) /* #include # #i in nc cl lu ud de e < > #cgo CFLAGS: -I/usr/local/opt/openssl/include #cgo LDFLAGS: -L/usr/local/opt/openssl/lib -lcrypto */ func Version(t C.int) string { return C.GoString( C C. .S SS SL Le ea ay y_ _v ve er rs si io on n( (t t) )) ) } func main() { fmt.Println(Version(0)) } Run Interfacing C libraries with GO

Slide 21

Slide 21 text

Static linked library binding (OpenSSL) /* #include #include #cgo CFLAGS: -I/usr/local/opt/openssl/include # #c cg go o L LD DF FL LA AG GS S: : / /u us sr r/ /l lo oc ca al l/ /o op pt t/ /o op pe en ns ss sl l/ /l li ib b/ /l li ib bc cr ry yp pt to o. .a a # # s st ta at ti ic c l li ib br ra ar ry y */ func main() { fmt.Println(Version(0)) } Run Interfacing C libraries with GO

Slide 22

Slide 22 text

Pkg-config (OpenSSL) /* #include #include # #c cg go o p pk kg g- -c co on nf fi ig g: : o op pe en ns ss sl l # # p pk kg g- -c co on nf fi ig g g gi iv ve es s i in nf fo or rm ma at ti io on n # #c cg go o L LD DF FL LA AG GS S: : - -l lc cr ry yp pt to o # # o om mi it t d di ir re ec ct to or ri ie es s */ func main() { fmt.Println(Version(0)) } Run Interfacing C libraries with GO

Slide 23

Slide 23 text

Show linked libraries dynamic linked $ otool -L openssl openssl: /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1) static-linked $ otool -L openssl_s openssl_s: /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0) pkg-config $ otool -L openssl_pkg /usr/lib/libcrypto.0.9.8.dylib (compatibility version 0.9.8, current version 50.0.0) /usr/lib/libssl.0.9.8.dylib (compatibility version 0.9.8, current version 50.0.0) /usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.5) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1) Interfacing C libraries with GO

Slide 24

Slide 24 text

String/Array convension //Go string to C string; result must be freed with C.free func C.CString(goString string) *C.char // C string to Go string func C.GoString(cString *C.char) string // C string, length to Go string func C.GoStringN(cString *C.char, length C.int) string // A new Go byte slice from a C array (pointer) func C.GoBytes(cArray unsafe.Pointer,length C.int) []byte Interfacing C libraries with GO

Slide 25

Slide 25 text

Type mappings strings/array (see previous slide) integers int -> C.int unsigned short -> C.ushort ... pointer unsafe.Pointer -> void * struct see RSA example Interfacing C libraries with GO

Slide 26

Slide 26 text

OpenSSL RSA encrypt/decrypt func main() { m m : := = N Ne ew w( () ) f fm mt t. .P Pr ri in nt tl ln n( (" "M Ma ax x m me es ss sa ag ge e l le en ng gt th h i is s : : " ", , m m. .S Si iz ze e( () )) ) plaintext := "I am plain text" fmt.Println("Plain: ", plaintext) c ci ip ph he er rt te ex xt t : := = m m. .R RS SA A_ _p pu ub bl li ic c_ _e en nc cr ry yp pt t( ([ [] ]b by yt te e( (p pl la ai in nt te ex xt t) )) ) fmt.Println("Cipher: ", string(ciphertext)) fmt.Println("Cipher in bytes: ", ciphertext) p pl la ai in n : := = m m. .R RS SA A_ _p pr ri iv va at te e_ _d de ec cr ry yp pt t( ([ [] ]b by yt te e( (c ci ip ph he er rt te ex xt t) )) ) fmt.Println("Decrypted: ", string(plain)) F Fr re ee e( (m m) ) } Run Interfacing C libraries with GO

Slide 27

Slide 27 text

OpenSSL RSA declaration // #include // #include // #include // #cgo CFLAGS: -I/usr/local/opt/openssl/include // #cgo LDFLAGS: -L/usr/local/opt/openssl/lib -lcrypto import "C" import ( "fmt" "unsafe" ) type M struct { c ct tx x * *C C. .R RS SA A } Interfacing C libraries with GO

Slide 28

Slide 28 text

OpenSSL RSA initial and final functions func New() *M { m := &M{} m.ctx = C.RSA_generate_key(2048, 3, nil, nil) return m } func Free(m *M) { C.RSA_free(m.ctx) C.CRYPTO_cleanup_all_ex_data() } func (m *M) Size() int { return int(C.RSA_size(m.ctx)) } Interfacing C libraries with GO

Slide 29

Slide 29 text

OpenSSL RSA RSA_public_encrypt in C int RSA_public_encrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa, int padding); in GO func (m *M) RSA_public_encrypt(plain []byte) []byte { cipher := (unsafe.Pointer)(C.malloc(C.size_t(C.RSA_size(m.ctx)))) defer C.free(unsafe.Pointer(cipher)) ret := C.RSA_public_encrypt( C C. .i in nt t( (l le en n( (p pl la ai in n) )) ), , / // / f fl le en n ( (* *C C. .u uc ch ha ar r) )( (& &p pl la ai in n[ [0 0] ]) ), , / // / f fr ro om m ( (* *C C. .u uc ch ha ar r) )( (c ci ip ph he er r) ), , / // / t to o m m. .c ct tx x, , / // / R RS SA A * *r rs sa a C C. .R RS SA A_ _P PK KC CS S1 1_ _P PA AD DD DI IN NG G) ) / // / p pa ad dd di in ng g return C.GoBytes(cipher, ret) } Interfacing C libraries with GO

Slide 30

Slide 30 text

OpenSSL RSA RSA_private_decrypt in C int RSA_private_decrypt(int flen, unsigned char *from, unsigned char *to, RSA *rsa, int padding); in GO func (m *M) RSA_private_decrypt(cipher []byte) []byte { p pl la ai in n : := = ( (u un ns sa af fe e. .P Po oi in nt te er r) )( (C C. .m ma al ll lo oc c( (C C. .s si iz ze e_ _t t( (C C. .R RS SA A_ _s si iz ze e( (m m. .c ct tx x) )) )) )) ) d de ef fe er r C C. .f fr re ee e( (u un ns sa af fe e. .P Po oi in nt te er r( (p pl la ai in n) )) ) ret := C.RSA_private_decrypt( C.int(len(cipher)), (*C.uchar)(&cipher[0]), (*C.uchar)(plain), m.ctx, C.RSA_PKCS1_PADDING) return C.GoBytes(plain, ret) } Interfacing C libraries with GO

Slide 31

Slide 31 text

OpenSSL RSA encrypt/decrypt func main() { m m : := = N Ne ew w( () ) f fm mt t. .P Pr ri in nt tl ln n( (" "M Ma ax x m me es ss sa ag ge e l le en ng gt th h i is s : : " ", , m m. .S Si iz ze e( () )) ) plaintext := "I am plain text" fmt.Println("Plain: ", plaintext) c ci ip ph he er rt te ex xt t : := = m m. .R RS SA A_ _p pu ub bl li ic c_ _e en nc cr ry yp pt t( ([ [] ]b by yt te e( (p pl la ai in nt te ex xt t) )) ) fmt.Println("Cipher: ", string(ciphertext)) fmt.Println("Cipher in bytes: ", ciphertext) p pl la ai in n : := = m m. .R RS SA A_ _p pr ri iv va at te e_ _d de ec cr ry yp pt t( ([ [] ]b by yt te e( (c ci ip ph he er rt te ex xt t) )) ) fmt.Println("Decrypted: ", string(plain)) F Fr re ee e( (m m) ) } Max message length is : 256 Plain: I am plain text Cipher: u��"�E��ժ`�0<�^C���7��H|��P�\?���Xĩ��gS��$RY`�MpH���px�M� [�����L��|�������c������dV��t"�j��w���A��A��-�=h�q�� zY�s#��~-��� �K���3�4��qP��ny'��0�̠ A��p�=0��-rAĞ�1G�leB�Y���p}\�@U�/ʨS���4�5�I?Y[ Cipher in bytes: [117 25 19 248 190 34 195 69 135 212 213 170 96 Decrypted: I am plain text Program exited. Run Kill Close Interfacing C libraries with GO

Slide 32

Slide 32 text

Useful links Command cgo doc (http://golang.org/cmd/cgo/) Search "cgo" in A list of Go projects (http://code.google.com/p/go-wiki/wiki/Projects) Cgo examples (http://golang.org/misc/cgo/) Interfacing C libraries with GO

Slide 33

Slide 33 text

Thank you Cheng-Lung Sung http://dev.clsung.tw/ (http://dev.clsung.tw/) @clsung (http://twitter.com/clsung) Interfacing C libraries with GO