Tak, poprzez sprawdzenie własnego pliku wykonywalnego (/proc/self/exe
) za pomocą np. libbfd
lub biblioteka parsowania plików ELF, aby przeanalizować rzeczywiste symbole. Zasadniczo, można napisać kod w C, który robi równowartość coś podobnego
env LANG=C LC_ALL=C readelf -s executable | awk '($5 == "LOCAL" && $8 ~ /^[^_]/ && $8 !~ /\./)'
O ile mi wiadomo, dynamiczny interfejs łącznikiem w systemie Linux (<dlfcn.h>
) nie zwraca adresy statyczne (lokalne) symbole.
Prostym i dość solidnym podejściem jest wykonanie z Twojego programu readelf
lub objdump
. Zauważ, że nie możesz podać ścieżki pseudo-pliku /proc/self/exe
, ponieważ zawsze odnosi się ona do własnego pliku wykonywalnego procesu. Zamiast tego musisz użyć np. realpath("/proc/self/exe", NULL)
, aby uzyskać dynamicznie przydzieloną bezwzględną ścieżkę do bieżącego pliku wykonywalnego, który można dostarczyć do polecenia. Zdecydowanie chcesz również, aby środowisko zawierało wartości LANG=C
i LC_ALL=C
, tak aby dane wyjściowe polecenia były łatwo przetwarzalne (i nie były zlokalizowane w języku preferowanym przez bieżącego użytkownika). Może się to wydawać trochę kłopotliwe, ale wymaga tylko zainstalowania pakietu binutils
i nie trzeba aktualizować programu lub biblioteki, aby nadążyć za najnowszymi osiągnięciami, więc uważam, że ogólnie rzecz biorąc to całkiem dobre podejście .
Chcesz na przykład?
Jednym ze sposobów na uproszczenie jest wygenerowanie oddzielnych tablic z informacjami o symbolu w czasie kompilacji. Zasadniczo, po pliki wynikowe są generowane osobny plik źródłowy jest generowana dynamicznie, uruchamiając objdump
lub readelf
nad powiązanych plików obiektowych, tworząc tablicę nazw i wskaźniki podobne do
const struct {
const char *const name;
const void *const addr;
} local_symbol_names[] = {
/* Filled in using objdump or readelf and awk, for example */
{ NULL, NULL }
};
może z prostej funkcji wyszukiwania eksportowanego w pliku nagłówkowym, aby po podłączeniu końcowego pliku wykonywalnego mógł on łatwo i wydajnie uzyskać dostęp do tablicy symboli lokalnych.
Powtarza niektóre dane, ponieważ ta sama informacja znajduje się już w pliku wykonywalnym, a jeśli dobrze pamiętam, musisz najpierw połączyć końcowy plik wykonywalny z tablicą pośrednią, aby uzyskać rzeczywiste adresy symboli, a następnie Połącz ponownie z tablicą symboli, co sprawia, że jest to trochę kłopotliwe podczas kompilacji. Uniknie się jednak zależności od czasu wykonywania na binutils
.