From 2e35fb0d7dfa1bc0c8874c355d67f75843e8f2a7 Mon Sep 17 00:00:00 2001 From: devlights Date: Sun, 24 Mar 2024 17:27:19 +0000 Subject: [PATCH 1/3] Add 16.C_dlopen_dlsym --- 16.C_dlopen_dlsym/.gitignore | 4 +++ 16.C_dlopen_dlsym/Taskfile.yml | 19 +++++++++++++ 16.C_dlopen_dlsym/cfuncs.go | 14 ++++++++++ 16.C_dlopen_dlsym/clib/lib.c | 5 ++++ 16.C_dlopen_dlsym/clib/lib.h | 1 + 16.C_dlopen_dlsym/dlopen/dlopen.go | 45 ++++++++++++++++++++++++++++++ 16.C_dlopen_dlsym/main.c | 6 ++++ 16.C_dlopen_dlsym/main.go | 38 +++++++++++++++++++++++++ 16.C_dlopen_dlsym/trash/main2.go | 24 ++++++++++++++++ 16.C_dlopen_dlsym/trash/sub2.go | 34 ++++++++++++++++++++++ 10 files changed, 190 insertions(+) create mode 100644 16.C_dlopen_dlsym/.gitignore create mode 100644 16.C_dlopen_dlsym/Taskfile.yml create mode 100644 16.C_dlopen_dlsym/cfuncs.go create mode 100644 16.C_dlopen_dlsym/clib/lib.c create mode 100644 16.C_dlopen_dlsym/clib/lib.h create mode 100644 16.C_dlopen_dlsym/dlopen/dlopen.go create mode 100644 16.C_dlopen_dlsym/main.c create mode 100644 16.C_dlopen_dlsym/main.go create mode 100644 16.C_dlopen_dlsym/trash/main2.go create mode 100644 16.C_dlopen_dlsym/trash/sub2.go diff --git a/16.C_dlopen_dlsym/.gitignore b/16.C_dlopen_dlsym/.gitignore new file mode 100644 index 0000000..3b66768 --- /dev/null +++ b/16.C_dlopen_dlsym/.gitignore @@ -0,0 +1,4 @@ +callgolib +libgolib.so +libgolib.h +main.o \ No newline at end of file diff --git a/16.C_dlopen_dlsym/Taskfile.yml b/16.C_dlopen_dlsym/Taskfile.yml new file mode 100644 index 0000000..154f5a4 --- /dev/null +++ b/16.C_dlopen_dlsym/Taskfile.yml @@ -0,0 +1,19 @@ +# https://taskfile.dev + +version: '3' + +tasks: + default: + deps: [ build-clib ] + cmds: + - go build -o libgolib.so -buildmode=c-shared main.go cfuncs.go + - nm libgolib.so | grep -F "T clib_my_strlen" + - gcc -c -o main.o main.c + - gcc -o callgolib main.o -L. -lgolib + - file ./callgolib + - ldd ./callgolib + - LD_LIBRARY_PATH=. ./callgolib + build-clib: + dir: clib + cmds: + - gcc -fPIC -shared -o libclib.so lib.c diff --git a/16.C_dlopen_dlsym/cfuncs.go b/16.C_dlopen_dlsym/cfuncs.go new file mode 100644 index 0000000..dd684fa --- /dev/null +++ b/16.C_dlopen_dlsym/cfuncs.go @@ -0,0 +1,14 @@ +package main + +/* +#include +#include "clib/lib.h" + +size_t call_clib_my_strlen(void *fn, const char *s) { + size_t (*clib_my_strlen_fn)(const char *); + + clib_my_strlen_fn = (size_t (*)(const char *))fn; + return clib_my_strlen_fn(s); +} +*/ +import "C" diff --git a/16.C_dlopen_dlsym/clib/lib.c b/16.C_dlopen_dlsym/clib/lib.c new file mode 100644 index 0000000..f99392b --- /dev/null +++ b/16.C_dlopen_dlsym/clib/lib.c @@ -0,0 +1,5 @@ +#include + +size_t clib_my_strlen(const char *s) { + return 10; +} diff --git a/16.C_dlopen_dlsym/clib/lib.h b/16.C_dlopen_dlsym/clib/lib.h new file mode 100644 index 0000000..507e61b --- /dev/null +++ b/16.C_dlopen_dlsym/clib/lib.h @@ -0,0 +1 @@ +extern size_t clib_my_strlen(const char *s); \ No newline at end of file diff --git a/16.C_dlopen_dlsym/dlopen/dlopen.go b/16.C_dlopen_dlsym/dlopen/dlopen.go new file mode 100644 index 0000000..67beef5 --- /dev/null +++ b/16.C_dlopen_dlsym/dlopen/dlopen.go @@ -0,0 +1,45 @@ +package dlopen + +/* +#cgo LDFLAGS: -ldl + +#include +#include +*/ +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) +} diff --git a/16.C_dlopen_dlsym/main.c b/16.C_dlopen_dlsym/main.c new file mode 100644 index 0000000..bd5259f --- /dev/null +++ b/16.C_dlopen_dlsym/main.c @@ -0,0 +1,6 @@ +#include +#include "clib/lib.h" + +int main() { + printf("%zu\n", clib_my_strlen("helloworld")); +} \ No newline at end of file diff --git a/16.C_dlopen_dlsym/main.go b/16.C_dlopen_dlsym/main.go new file mode 100644 index 0000000..747f129 --- /dev/null +++ b/16.C_dlopen_dlsym/main.go @@ -0,0 +1,38 @@ +package main + +/* +#include + +extern size_t call_clib_my_strlen(void *fn, const char *s); +*/ +import "C" +import ( + "log" + "unsafe" + + "github.com/devlights/try-golang-cgo/16.C_dlopen_dlsym/dlopen" +) + +//export clib_my_strlen +func clib_my_strlen(cStr *C.char) C.size_t { + var ( + handle unsafe.Pointer + symbol unsafe.Pointer + result C.size_t + ) + + println("1") + handle = dlopen.OpenLib("clib/libclib.so") + defer dlopen.CloseLib(handle) + + println("2") + println(handle == nil) + symbol = dlopen.GetSym(handle, "clib_my_strlen") + result = C.call_clib_my_strlen(symbol, cStr) + + log.Printf("[Go][strlen] result=%v", result) + + return result +} + +func main() {} diff --git a/16.C_dlopen_dlsym/trash/main2.go b/16.C_dlopen_dlsym/trash/main2.go new file mode 100644 index 0000000..c849879 --- /dev/null +++ b/16.C_dlopen_dlsym/trash/main2.go @@ -0,0 +1,24 @@ +//go:build run + +package main + +/* +#cgo LDFLAGS: -ldl + +#include +#include + +typedef size_t (*strlen_t)(const char *); + +strlen_t getStrlenFunc(); + +size_t callstrlen(const char *s); +*/ +import "C" + +//export strlen +func strlen(cstr *C.char) C.size_t { + return C.callstrlen(cstr) +} + +func main() {} diff --git a/16.C_dlopen_dlsym/trash/sub2.go b/16.C_dlopen_dlsym/trash/sub2.go new file mode 100644 index 0000000..47ae661 --- /dev/null +++ b/16.C_dlopen_dlsym/trash/sub2.go @@ -0,0 +1,34 @@ +//go:build run + +package main + +/* +#cgo LDFLAGS: -ldl + +#include +#include + +typedef size_t (*strlen_t)(const char *); + +// dlopenでlibc.so.6を開き、strlen関数のアドレスを取得する +strlen_t getStrlenFunc() { + void* handle = dlopen("libc.so.6", RTLD_LAZY); + if (!handle) { + return NULL; + } + dlerror(); // dlerrorの状態をクリア + + strlen_t func = (strlen_t)dlsym(handle, "strlen"); + if (dlerror() != NULL) { + return NULL; + } + + return func; +} + +size_t callstrlen(const char *s) { + strlen_t fn = getStrlenFunc(); + return fn(s); +} +*/ +import "C" From f873c1b0687d9fc33159e5ef006c3e9da645604f Mon Sep 17 00:00:00 2001 From: devlights Date: Mon, 25 Mar 2024 02:16:16 +0000 Subject: [PATCH 2/3] Update --- 16.C_dlopen_dlsym/.gitignore | 2 +- 16.C_dlopen_dlsym/Taskfile.yml | 27 ++++++++++++++++-------- 16.C_dlopen_dlsym/cfuncs.go | 11 ++++------ 16.C_dlopen_dlsym/clib/lib.c | 6 +++--- 16.C_dlopen_dlsym/clib/lib.h | 2 +- 16.C_dlopen_dlsym/gofuncs.go | 31 ++++++++++++++++++++++++++++ 16.C_dlopen_dlsym/main.c | 2 +- 16.C_dlopen_dlsym/main.go | 35 -------------------------------- 16.C_dlopen_dlsym/trash/main2.go | 24 ---------------------- 16.C_dlopen_dlsym/trash/sub2.go | 34 ------------------------------- 10 files changed, 60 insertions(+), 114 deletions(-) create mode 100644 16.C_dlopen_dlsym/gofuncs.go delete mode 100644 16.C_dlopen_dlsym/trash/main2.go delete mode 100644 16.C_dlopen_dlsym/trash/sub2.go diff --git a/16.C_dlopen_dlsym/.gitignore b/16.C_dlopen_dlsym/.gitignore index 3b66768..e8d22c4 100644 --- a/16.C_dlopen_dlsym/.gitignore +++ b/16.C_dlopen_dlsym/.gitignore @@ -1,4 +1,4 @@ -callgolib +capp libgolib.so libgolib.h main.o \ No newline at end of file diff --git a/16.C_dlopen_dlsym/Taskfile.yml b/16.C_dlopen_dlsym/Taskfile.yml index 154f5a4..7338635 100644 --- a/16.C_dlopen_dlsym/Taskfile.yml +++ b/16.C_dlopen_dlsym/Taskfile.yml @@ -2,18 +2,29 @@ version: '3' +vars: + CAPP_NAME: capp + tasks: default: - deps: [ build-clib ] cmds: - - go build -o libgolib.so -buildmode=c-shared main.go cfuncs.go - - nm libgolib.so | grep -F "T clib_my_strlen" - - gcc -c -o main.o main.c - - gcc -o callgolib main.o -L. -lgolib - - file ./callgolib - - ldd ./callgolib - - LD_LIBRARY_PATH=. ./callgolib + - 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 diff --git a/16.C_dlopen_dlsym/cfuncs.go b/16.C_dlopen_dlsym/cfuncs.go index dd684fa..7d9fdff 100644 --- a/16.C_dlopen_dlsym/cfuncs.go +++ b/16.C_dlopen_dlsym/cfuncs.go @@ -1,14 +1,11 @@ package main /* -#include -#include "clib/lib.h" +size_t call_my_strlen(void *fn, const char *s) { + size_t (*my_strlen_fn)(const char *); -size_t call_clib_my_strlen(void *fn, const char *s) { - size_t (*clib_my_strlen_fn)(const char *); - - clib_my_strlen_fn = (size_t (*)(const char *))fn; - return clib_my_strlen_fn(s); + my_strlen_fn = (size_t (*)(const char *))fn; + return my_strlen_fn(s); } */ import "C" diff --git a/16.C_dlopen_dlsym/clib/lib.c b/16.C_dlopen_dlsym/clib/lib.c index f99392b..1168775 100644 --- a/16.C_dlopen_dlsym/clib/lib.c +++ b/16.C_dlopen_dlsym/clib/lib.c @@ -1,5 +1,5 @@ -#include +#include -size_t clib_my_strlen(const char *s) { - return 10; +size_t my_strlen(const char *s) { + return strlen(s); } diff --git a/16.C_dlopen_dlsym/clib/lib.h b/16.C_dlopen_dlsym/clib/lib.h index 507e61b..f3e3b74 100644 --- a/16.C_dlopen_dlsym/clib/lib.h +++ b/16.C_dlopen_dlsym/clib/lib.h @@ -1 +1 @@ -extern size_t clib_my_strlen(const char *s); \ No newline at end of file +extern size_t my_strlen(const char *s); \ No newline at end of file diff --git a/16.C_dlopen_dlsym/gofuncs.go b/16.C_dlopen_dlsym/gofuncs.go new file mode 100644 index 0000000..032ddb1 --- /dev/null +++ b/16.C_dlopen_dlsym/gofuncs.go @@ -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 +} diff --git a/16.C_dlopen_dlsym/main.c b/16.C_dlopen_dlsym/main.c index bd5259f..54d2afe 100644 --- a/16.C_dlopen_dlsym/main.c +++ b/16.C_dlopen_dlsym/main.c @@ -2,5 +2,5 @@ #include "clib/lib.h" int main() { - printf("%zu\n", clib_my_strlen("helloworld")); + printf("clib_my_strlen=%zu\n", my_strlen("helloworld")); } \ No newline at end of file diff --git a/16.C_dlopen_dlsym/main.go b/16.C_dlopen_dlsym/main.go index 747f129..38dd16d 100644 --- a/16.C_dlopen_dlsym/main.go +++ b/16.C_dlopen_dlsym/main.go @@ -1,38 +1,3 @@ package main -/* -#include - -extern size_t call_clib_my_strlen(void *fn, const char *s); -*/ -import "C" -import ( - "log" - "unsafe" - - "github.com/devlights/try-golang-cgo/16.C_dlopen_dlsym/dlopen" -) - -//export clib_my_strlen -func clib_my_strlen(cStr *C.char) C.size_t { - var ( - handle unsafe.Pointer - symbol unsafe.Pointer - result C.size_t - ) - - println("1") - handle = dlopen.OpenLib("clib/libclib.so") - defer dlopen.CloseLib(handle) - - println("2") - println(handle == nil) - symbol = dlopen.GetSym(handle, "clib_my_strlen") - result = C.call_clib_my_strlen(symbol, cStr) - - log.Printf("[Go][strlen] result=%v", result) - - return result -} - func main() {} diff --git a/16.C_dlopen_dlsym/trash/main2.go b/16.C_dlopen_dlsym/trash/main2.go deleted file mode 100644 index c849879..0000000 --- a/16.C_dlopen_dlsym/trash/main2.go +++ /dev/null @@ -1,24 +0,0 @@ -//go:build run - -package main - -/* -#cgo LDFLAGS: -ldl - -#include -#include - -typedef size_t (*strlen_t)(const char *); - -strlen_t getStrlenFunc(); - -size_t callstrlen(const char *s); -*/ -import "C" - -//export strlen -func strlen(cstr *C.char) C.size_t { - return C.callstrlen(cstr) -} - -func main() {} diff --git a/16.C_dlopen_dlsym/trash/sub2.go b/16.C_dlopen_dlsym/trash/sub2.go deleted file mode 100644 index 47ae661..0000000 --- a/16.C_dlopen_dlsym/trash/sub2.go +++ /dev/null @@ -1,34 +0,0 @@ -//go:build run - -package main - -/* -#cgo LDFLAGS: -ldl - -#include -#include - -typedef size_t (*strlen_t)(const char *); - -// dlopenでlibc.so.6を開き、strlen関数のアドレスを取得する -strlen_t getStrlenFunc() { - void* handle = dlopen("libc.so.6", RTLD_LAZY); - if (!handle) { - return NULL; - } - dlerror(); // dlerrorの状態をクリア - - strlen_t func = (strlen_t)dlsym(handle, "strlen"); - if (dlerror() != NULL) { - return NULL; - } - - return func; -} - -size_t callstrlen(const char *s) { - strlen_t fn = getStrlenFunc(); - return fn(s); -} -*/ -import "C" From 93f7837b2d71786f0e665e1f609e2a2f4bb825b4 Mon Sep 17 00:00:00 2001 From: devlights Date: Mon, 25 Mar 2024 02:36:56 +0000 Subject: [PATCH 3/3] Update --- 16.C_dlopen_dlsym/README.md | 19 +++++++++++++++++++ 16.C_dlopen_dlsym/main.c | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 16.C_dlopen_dlsym/README.md diff --git a/16.C_dlopen_dlsym/README.md b/16.C_dlopen_dlsym/README.md new file mode 100644 index 0000000..7f35c9f --- /dev/null +++ b/16.C_dlopen_dlsym/README.md @@ -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 +``` diff --git a/16.C_dlopen_dlsym/main.c b/16.C_dlopen_dlsym/main.c index 54d2afe..22507f5 100644 --- a/16.C_dlopen_dlsym/main.c +++ b/16.C_dlopen_dlsym/main.c @@ -2,5 +2,5 @@ #include "clib/lib.h" int main() { - printf("clib_my_strlen=%zu\n", my_strlen("helloworld")); + printf("my_strlen=%zu\n", my_strlen("helloworld")); } \ No newline at end of file