Статическая альтернатива ELF для dlsym

Можно ли найти местоположение функции с помощью ELF? Похоже на то, что

void *f = dlopen(NULL,..);
void *func = dlsym(f, "myfunc");

делает, но не требует -rdynamic во время компиляции?

Используя nm, я вижу, что имена элементов все еще присутствуют в скомпилированном двоичном файле?:

0000000000400716 T lookup
0000000000400759 T main

Могу ли я использовать эту информацию для поиска элементов после загрузки программы в память?


person hnh    schedule 23.05.2018    source источник


Ответы (1)


Могу ли я использовать эту информацию для поиска элементов после загрузки программы в память?

Вы, конечно, можете: перебирать все символы в a.out, пока не найдете подходящий. Пример кода для перебора символов находится здесь. Или используйте libelf.

Если вам нужно выполнить поиск нескольких символов, повторите один раз (медленно) по всем символам, создайте карту от имени символа до его адреса и выполните поиск, используя эту карту.

Обновление:

Пример, на который вы указываете, кажется неполным? Он использует данные и эльфа, откуда они берутся?

Да, вам нужно применить немного смазки для локтей к этому примеру.

data - это место в памяти, где a.out находится read, или (лучше) mmaped.

Вы можете либо mmap a.out самостоятельно, либо найти существующее сопоставление, например. getauxval(AT_PHDR) округляется до размера страницы.

ehdr равно (ElfW(Ehdr) *)data (то есть data преобразуется в Elf32_Ehdr или Elf64_Ehdr в зависимости от ситуации.

Если это неясно, то вам, вероятно, следует просто использовать libelf, который позаботится о деталях за вас.

Кроме того, позволяет ли ELF мне найти только имя символа или он действительно может дать мне указатель на местоположение символа в памяти?

Он может дать вам оба: str + sym[i].st_name — это имя, sym[i].st_value — указатель (значение, отображаемое nm).

(предположительно, например, 0000000000400716 - это какой-то относительный базовый адрес, а не фактическое расположение в памяти, верно?)

Нет, на самом деле (для этого бинарника) это абсолютный адрес.

Позиционно-независимые двоичные файлы используют относительные адреса (поэтому вам понадобится что-то вроде getauxval, упомянутого выше, чтобы найти базовое местоположение такого исполняемого файла), но этот конкретный двоичный файл выглядит как ET_EXEC (используйте readelf -h a.out, чтобы убедиться в этом). Адрес 0x400000 является типичным адресом для загрузки исполняемых файлов, отличных от PIE, в Linux x86_64 (вероятно, это ваша система).

person Employed Russian    schedule 23.05.2018
comment
Два вопроса: пример, на который вы указываете, кажется неполным? Он использует data и elf, откуда они берутся? Кроме того, позволяет ли ELF мне найти только имя символа или он действительно может дать мне указатель на местоположение в памяти символа? (предположительно, например, 0000000000400716 - это какой-то относительный базовый адрес, а не фактическое расположение в памяти, верно?) - person hnh; 23.05.2018