Как динамически вызвать функцию в самом исполняемом файле?

Я пытался динамически вызвать функцию в самом исполняемом файле. Целевая функция test_func была закодирована вместе с функцией main в том же исходном файле. Вот пример кода:

#include <stdio.h>
#include <dlfcn.h>

// or with some tricks
// void __attribute__((visibility("default")))
void test_func(void)
{
    printf("test_func in %s \n",__FILE__);
}

int main()
{
    void *handle = dlopen(0, RTLD_LAZY); // or RTLD_GLOBAL
    printf("dlopen return %p\n", handle);

    void (*func)() = dlsym(handle, "test_func");
    printf("dlsym  return %p\n", func);

    if (func) (*func)();
    return 0;
}

Затем я скомпилировал его с помощью gcc, и результат получился таким:

$ ./a.out
dlopen return 0xe29dfbec1c7bc0d
dlsym  return 0x0

Я могу прочитать символ в ELF. Мне пришло в голову, что должен быть какой-то способ получить функцию test_func и вызвать ее.

$ readelf -s a.out | grep test_func
    40: 00000000000017c8    36 FUNC    GLOBAL DEFAULT   13 test_func

Есть ли что-то, что мне не хватает?

Я пытался исправить орфографию, но есть несколько неясных фраз. Я думаю, вы имеете в виду «скомпилировано», а не «соблюдено»; но что означает это предложение? Как именно вы это скомпилировали?

tripleee 06.08.2024 08:44
dlopen и dlsym также работают в Windows, но имена файлов библиотеки явно отличаются. stackoverflow.com/questions/11741580/… кажется актуальным
tripleee 06.08.2024 08:46

Извини, моя ошибка. Орфографию исправил, спасибо.

uscq 06.08.2024 09:21

Еще раз спасибо, но в моем исходном вопросе я действительно хочу спросить: могу ли я динамически вызывать функцию в самом исполняемом файле с помощью GetModuleHandle()/GetProcAddress()?

uscq 06.08.2024 09:25
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
4
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы используете окна? Тогда вам следует рассмотреть возможность использования DLL для динамической загрузки функций.

Обычно, когда вы вызываете dlopen(0, RTLD_LAZY), он пытается открыть собственную таблицу символов исполняемого файла; при извлечении символов он может работать не так, как ожидалось. Это связано с тем, что динамический компоновщик может не предоставлять все символы исполняемого файла так же, как для общих библиотек.

Несмотря на то, что вы можете увидеть test_func в выводе readelf, он все равно может быть недоступен через dlsym, если он не отображается должным образом или если таблица динамических символов не заполнена должным образом.

Итак, поскольку цель dlopen в основном касается общих библиотек. Распространенным решением было бы переключение на общую библиотеку, но если вам действительно нужно использовать исполняемый файл: Вы должны обязательно выполнить компиляцию с флагом -rdynamic, чтобы символы были включены в таблицу динамических символов.

gcc -rdynamic -o a.out <filename.c>

Это важно, чтобы символы были видны через dlsym.

Итак, если позиция -rdynamic должна быть принята, то dlopen(NULL, RTLD_LAZY) действительно должно сработать. Если предположить, что это не так, то, вероятно, это ошибка или ошибка в вашем компоновщике или динамическом загрузчике и в том, как он обрабатывает символы.


Итак, в сортировке мы можем сказать:

  1. Используйте -rdynamic при компиляции, чтобы отображать символы.
  2. Для общих библиотек используйте dlopen и dlsym по назначению.

Вот полный код, в котором я использовал -rdynamic, а также проверил, виден ли символ или нет:

#include <stdio.h>
#include <dlfcn.h>

// Define the function to be called
void __attribute__((visibility("default"))) test_func(void)
{
    printf("test_func in %s \n", __FILE__);
}

int main()
{
    // Open the executable's symbol table
    void *handle = dlopen(NULL, RTLD_LAZY); 
    if (!handle) {
        fprintf(stderr, "dlopen failed: %s\n", dlerror());
        return 1;
    }
    printf("dlopen return %p\n", handle);

    // Retrieve the address of test_func
    void (*func)() = dlsym(handle, "test_func");
    if (!func) {
        fprintf(stderr, "dlsym failed: %s\n", dlerror());
        dlclose(handle);
        return 1;
    }
    printf("dlsym return %p\n", func);

    // Call the function if found
    (*func)();

    // Close the handle
    dlclose(handle);
    return 0;
}

Сообщите мне, если вы все еще сталкиваетесь с какими-либо ошибками

Другие вопросы по теме