Skip to content

Commit

Permalink
Merge pull request #16 from devlights/add-dlopen-example
Browse files Browse the repository at this point in the history
Add 16.C_dlopen_dlsym
  • Loading branch information
devlights authored Mar 25, 2024
2 parents 790a638 + 93f7837 commit b84748c
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 0 deletions.
4 changes: 4 additions & 0 deletions 16.C_dlopen_dlsym/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
capp
libgolib.so
libgolib.h
main.o
19 changes: 19 additions & 0 deletions 16.C_dlopen_dlsym/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# これは何?

cgoとdlopen関数を使って、既に存在している共有ライブラリ内の既存関数と全く同じ関数書式を持つ関数をcgo側で定義して、呼び出しをフックするサンプルです。

実行すると以下のようになります。

```sh
$ task
task: [build-clib] gcc -fPIC -shared -o libclib.so lib.c
task: [build-golib] go build -o libgolib.so -buildmode=c-shared *.go
task: [build-cprg] gcc -c -o main.o main.c
task: [build-cprg] gcc -o capp main.o -L. -lgolib
task: [default] LD_LIBRARY_PATH=. ./capp
2024/03/25 02:36:06 [Go][インターセプト][my_strlen] result=10
my_strlen=10
task: [build-cprg-original] gcc -o capp main.o -Lclib -lclib
task: [default] LD_LIBRARY_PATH=clib ./capp
my_strlen=10
```
30 changes: 30 additions & 0 deletions 16.C_dlopen_dlsym/Taskfile.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# https://taskfile.dev

version: '3'

vars:
CAPP_NAME: capp

tasks:
default:
cmds:
- task: build-clib
- task: build-golib
- task: build-cprg
- LD_LIBRARY_PATH=. ./{{.CAPP_NAME}}
- task: build-cprg-original
- LD_LIBRARY_PATH=clib ./{{.CAPP_NAME}}
build-clib:
dir: clib
cmds:
- gcc -fPIC -shared -o libclib.so lib.c
build-golib:
cmds:
- go build -o libgolib.so -buildmode=c-shared *.go
build-cprg:
cmds:
- gcc -c -o main.o main.c
- gcc -o {{.CAPP_NAME}} main.o -L. -lgolib
build-cprg-original:
cmds:
- gcc -o {{.CAPP_NAME}} main.o -Lclib -lclib
11 changes: 11 additions & 0 deletions 16.C_dlopen_dlsym/cfuncs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package main

/*
size_t call_my_strlen(void *fn, const char *s) {
size_t (*my_strlen_fn)(const char *);
my_strlen_fn = (size_t (*)(const char *))fn;
return my_strlen_fn(s);
}
*/
import "C"
5 changes: 5 additions & 0 deletions 16.C_dlopen_dlsym/clib/lib.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include <string.h>

size_t my_strlen(const char *s) {
return strlen(s);
}
1 change: 1 addition & 0 deletions 16.C_dlopen_dlsym/clib/lib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
extern size_t my_strlen(const char *s);
45 changes: 45 additions & 0 deletions 16.C_dlopen_dlsym/dlopen/dlopen.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package dlopen

/*
#cgo LDFLAGS: -ldl
#include <dlfcn.h>
#include <stdlib.h>
*/
import "C"
import (
"unsafe"
)

func OpenLib(path string) unsafe.Pointer {
var (
cPath = C.CString(path)
cPathPtr = unsafe.Pointer(cPath)
handle unsafe.Pointer
)
defer C.free(cPathPtr)

handle = C.dlopen(cPath, C.RTLD_LAZY)
return handle
}

func GetSym(handle unsafe.Pointer, symbol string) unsafe.Pointer {
var (
cSymbol = C.CString(symbol)
cSymbolPtr = unsafe.Pointer(cSymbol)
funcPtr unsafe.Pointer
)
defer C.free(cSymbolPtr)

// 本来、dlsym()を呼び出す前に dlerror() を呼び出し、エラー状態をクリアしてから
// dlsym()を呼び出す。その後に、dlerror() でエラーを確認するのが正当な流れであるが割愛

funcPtr = C.dlsym(handle, cSymbol)
return funcPtr
}

func CloseLib(handle unsafe.Pointer) {
// 本来、dlclose()を呼び出す前に dlerror() を呼び出し、エラー状態をクリアしてから
// dlclose()を呼び出す。その後に、dlerror() でエラーを確認するのが正当な流れであるが割愛
C.dlclose(handle)
}
31 changes: 31 additions & 0 deletions 16.C_dlopen_dlsym/gofuncs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package main

/*
extern size_t call_my_strlen(void *fn, const char *s);
*/
import "C"
import (
"log"
"unsafe"

"github.com/devlights/try-golang-cgo/16.C_dlopen_dlsym/dlopen"
)

//export my_strlen
func my_strlen(cStr *C.char) C.size_t {
var (
handle unsafe.Pointer
symbol unsafe.Pointer
result C.size_t
)

handle = dlopen.OpenLib("clib/libclib.so")
defer dlopen.CloseLib(handle)

symbol = dlopen.GetSym(handle, "my_strlen")
result = C.call_my_strlen(symbol, cStr)

log.Printf("[Go][インターセプト][my_strlen] result=%v", result)

return result
}
6 changes: 6 additions & 0 deletions 16.C_dlopen_dlsym/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include <stdio.h>
#include "clib/lib.h"

int main() {
printf("my_strlen=%zu\n", my_strlen("helloworld"));
}
3 changes: 3 additions & 0 deletions 16.C_dlopen_dlsym/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package main

func main() {}

0 comments on commit b84748c

Please sign in to comment.