2017-01-08 11 views
4

Я не могу получить расширение gnu для эльфа с косвенными функциями для работы с dladdr.Как получить имя косвенной функции gnu с помощью dladdr?

В приведенном ниже примере fabs и sin представлены две динамические функции в libm, где sin также является косвенной функцией. Глядя вверх fabs от его указателя хорошо работает, но sin не найден. Я пробовал различные флаги до dlopen и -rdynamic без успеха.

Отладчик показывает, как sin оценивается от gnu-indirect-function variable до __sin_avx.

Я пропустил что-то здесь или косвенные функции, не поддерживаемые dladdr?

/* 
    compiled with g++-5 -fPIC -ldl 
*/ 

#include <cmath> 
#include <dlfcn.h> 
#include <iostream> 

char const * name (void * arg) 
{ 
    void * h = dlopen (NULL, RTLD_LAZY); 

    if (h) 
    { 
     Dl_info res; 
     int status = dladdr (arg, & res); 
     dlclose (h); 

     if (status && res.dli_sname && arg == res.dli_saddr) 
      return res.dli_sname; 
    } 

    return ""; 
} 

int main() 
{ 
    std::cout << fabs (0.0) << " " << name ((void *) fabs) << std::endl; // found 
    std::cout << sin (0.0) << " " << name ((void *) sin) << std::endl; // not found 
} 
+0

Интересно, что удается работать, если вы удалите '-fPIC'. – yugr

ответ

3

Am Я-то здесь отсутствует или косвенные функции не поддерживаются dladdr?

Хорошо, это было интересно.

Так что ifuncs работает, заменив исходный адрес функции (в данном случае sin) с той, на которую он разрешен динамическим компоновщиком на текущей платформе. sin может быть решен в один из 4 реализаций в зависимости от возможностей процессора:

libm_ifunc (__sin, (HAS_ARCH_FEATURE (FMA4_Usable) ? __sin_fma4 : 
        HAS_ARCH_FEATURE (AVX_Usable) 
        ? __sin_avx : __sin_sse2)); 
weak_alias (__sin, sin) 

Теперь каждый из __sin_XXX является внутренней функцией Glibc которая неэкспортируется из libm.so и поэтому dladdr не может найти его.

Таким образом, ответ в основном нет, dladdr не очень хорошо работает с ifuncs ...

удается работать, если вы удалите -fPIC

Это происходит потому, что при компиляции без -fPIC компилятор знает, что текущий исходный файл перейдет к основному исполняемому файлу, поэтому гарантируется, что адрес функции выполнения будет разрешен для записи PLT исполняемого файла. Поэтому вместо того, чтобы загружать его из GOT, он просто передает адрес PLT в name и dladdr, а затем удачно находит sin в файле исполнительного файла symtab.

EDIT:

Подтверждено Glibc людей here.

+0

Большое спасибо. Я нашел некоторые [сообщения] (https://gcc.gnu.org/ml/gcc/2016-08/msg00138.html) о ifunc и видимости, но тема для меня довольно новая. Как обход, есть ли способ ссылаться на исходную косвенную функцию, то есть с '__attribute__ ifunc'? – listcrawler

+0

Я лично не знаю более простого способа, чем ручной анализ таблицы GOT (например, описанный здесь (http://vxheaven.org/lib/vrn00.html#c6)), но это довольно серьезная задача. Вы можете попробовать просить в [libc-help] (https://sourceware.org/ml/libc-help/). – yugr

+0

И [здесь] (https://sourceware.org/ml/libc-help/2017-01/msg00010.html) является ответом на мой вопрос о libc-help.Короче говоря, информация об исходном имени символа ifunc теряется при его решении. Что касается разбора GOT - извините мою сборку, но из того, что я могу прочитать из сгенерированного кода, я не уверен, что ifuncs не были решены уже при запуске программы, а не при первом вызове. Если это так, не было бы возможности разобрать GOT для исходного адреса ifunc, правильно? – listcrawler