为了账号安全,请及时绑定邮箱和手机立即绑定

为什么 dlsym 在 cgo 中产生的结果与在 c 中产生的结果不同?

为什么 dlsym 在 cgo 中产生的结果与在 c 中产生的结果不同?

Go
拉风的咖菲猫 2023-06-05 13:23:51
我有两个相同行为的实现,我认为它们应该产生相同的结果,但却产生了不同的结果。在 Go 中使用 编译时cgo,我得到的符号地址解析与在 C 中编译时不同。我想了解原因。我将问题简化为几个小例子,一个用 C 语言,一个用 Go 语言。我在我的 Mac 笔记本电脑上运行的 Ubuntu 18 Docker 容器中测试了这些。测试.c:// gcc test.c -D_GNU_SOURCE -ldl// Output: Real: 0x7fd05559d7d0 Current: 0x7fd05559d7d0#include <dlfcn.h>#include <stdio.h>int main() {    void * fd = dlopen("libc.so.6", RTLD_LAZY);    void * real_sym = dlsym(fd, "accept");    void * curr_sym = dlsym(RTLD_NEXT, "accept");    printf("Real: %p Current: %p\n", real_sym, curr_sym);    return 0;}测试去:// go build test.go// Output: Real: 0x7f264583b7d0 Current: 0x7f2645b1b690package main// #cgo CFLAGS: -D_GNU_SOURCE// #cgo LDFLAGS: -ldl// #include <dlfcn.h>import "C"import "fmt"func main() {    fp := C.dlopen(C.CString("libc.so.6"), C.RTLD_LAZY)    real_sym := C.dlsym(fp, C.CString("accept"))    curr_sym := C.dlsym(C.RTLD_NEXT, C.CString("accept"))    fmt.Printf("Real: %p Current: %p\n", real_sym, curr_sym)}Real: 0x7fd05559d7d0 Current: 0x7fd05559d7d0我得到了when test.cgets compiled ( )的输出gcc test.c -D_GNU_SOURCE -ldl。但是,当我构建时,test.go我看到了Real: 0x7f264583b7d0 Current: 0x7f2645b1b690.我假设 go 本身正在包装一些符号,但我想知道到底发生了什么。谢谢!看到一些最初的评论后,再补充几件。我更改test.c如下,然后循环运行(while [ 1 ]; do   ./a.out; done)。它一直为我获得相同的地址(虽然每次运行都不同)。// gcc test.c -D_GNU_SOURCE -ldl// Output: Real: 0x7fd05559d7d0 Current: 0x7fd05559d7d0#include <dlfcn.h>#include <stdio.h>    int main() {    void * fd = dlopen("libc.so.6", RTLD_LAZY);    void * real_sym = dlsym(fd, "accept");    void * curr_sym = dlsym(RTLD_NEXT, "accept");    if(real_sym != curr_sym) {        printf("Real: %p Current: %p\n", real_sym, curr_sym);    }    return 0;}我还尝试修改 Go 代码以检查它是否与 Go 调用 C 的方式有关,但地址仍然不匹配:// go build dos.go// Output: Real: 0x7f264583b7d0 Current: 0x7f2645b1b690package main另一点是,如果我查找符号而malloc不是accept.
查看完整描述

2 回答

?
慕侠2389804

TA贡献1719条经验 获得超6个赞

原因是 Go 链接到 libpthread,但你的 C 程序没有。如果我添加-lpthread到 gcc 参数,它也会打印不同的指针。因此,libpthread 定义了它自己的accept并覆盖了 libc 的(这是有道理的)。

我想出来的方法是,我在两个程序中都插入了一个睡眠,然后翻查/proc/$pid/maps以查看返回的指针引用的内容。这表明在 Go 的例子中,“当前”指针驻留在 libpthread 中。“真正的”指针总是引用 libc。


查看完整回答
反对 回复 2023-06-05
?
小怪兽爱吃肉

TA贡献1852条经验 获得超1个赞

符号不会加载到内存中的固定地址;他们去装载机决定放置它们的任何地方。


这是我在我的机器上多次运行你的 C 程序的输出。


govind@Govind-PC:/mnt/c/Temp$ ./dlst

Real: 0x7f4b5f3127d0 Current: 0x7f4b5f26ee30

govind@Govind-PC:/mnt/c/Temp$ ./dlst

Real: 0x7f45727127d0 Current: 0x7f457266ee30

govind@Govind-PC:/mnt/c/Temp$ ./dlst

Real: 0x7fc3373127d0 Current: 0x7fc33726ee30

govind@Govind-PC:/mnt/c/Temp$ ./dlst

Real: 0x7f0e555127d0 Current: 0x7f0e5546ee30

govind@Govind-PC:/mnt/c/Temp$ ./dlst

Real: 0x7f2fdd9127d0 Current: 0x7f2fdd86ee30

govind@Govind-PC:/mnt/c/Temp$ ./dlst

Real: 0x7fec7db127d0 Current: 0x7fec7da6ee30

govind@Govind-PC:/mnt/c/Temp$ ./dlst

Real: 0x7f07de1127d0 Current: 0x7f07de06ee30

govind@Govind-PC:/mnt/c/Temp$

查看完整回答
反对 回复 2023-06-05
  • 2 回答
  • 0 关注
  • 131 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信