Почему dlsym дает разные результаты в cgo, чем в c? - PullRequest
0 голосов
/ 30 января 2019

У меня есть две реализации одного и того же поведения, которые, я считаю, должны давать одинаковые результаты, но вместо этого дают разные результаты.При компиляции в Go с использованием cgo я получаю другое разрешение адреса символа, чем при компиляции в C. Я хотел бы понять, почему.

Я сократил проблему до пары небольших примеров, один на C иодин на ходу.Я протестировал их в контейнере Ubuntu 18 Docker, работающем на моем ноутбуке Mac.

test.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;
}

test.go:

// go build test.go
// Output: Real: 0x7f264583b7d0 Current: 0x7f2645b1b690
package 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 при компиляции test.c (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: 0x7f2645b1b690
package main

// #cgo CFLAGS: -D_GNU_SOURCE
// #cgo LDFLAGS: -ldl
// #include <dlfcn.h>
// #include <stdio.h>
// int doit() {
//     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;
// }
import "C"

func main() {
    C.doit()
}

Другой момент заключается в том, что я получаю совпадение двух адресов в коде C и Go, если я ищу символ malloc вместо accept.

Ответы [ 2 ]

0 голосов
/ 31 января 2019

Причина в том, что Go ссылается на libpthread, а ваша C-программа - нет.Если я добавлю -lpthread к аргументам gcc, он также печатает разные указатели.Итак, libpthread определяет свой собственный accept и переопределяет libc (что имеет смысл).

Я понял, что я вставил сон в обе программы, а затем перерыл через /proc/$pid/mapsчтобы увидеть, на что ссылаются возвращенные указатели.Это показало, что в случае с Go указатель «current» находится в libpthread.«Настоящий» указатель всегда ссылается на libc.

0 голосов
/ 30 января 2019

Символы не загружаются в фиксированные адреса в памяти;они идут туда, куда их решает погрузчик.

Это результат того, что я запускаю вашу программу 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$

См. Также:

Рандомизация размещения адресного пространства

...