GNU/Linux >> Belajar Linux >  >> Linux

Bagaimana pustaka bersama (.so) memanggil fungsi yang diimplementasikan dalam program pemuatannya?

Anda memiliki dua opsi, yang dapat Anda pilih:

Opsi 1:ekspor semua simbol dari executable Anda. Ini adalah opsi sederhana, saat membuat executable, tambahkan flag -Wl,--export-dynamic . Ini akan membuat semua fungsi tersedia untuk panggilan perpustakaan.

Opsi 2:buat file simbol ekspor dengan daftar fungsi, dan gunakan -Wl,--dynamic-list=exported.txt . Ini membutuhkan beberapa pemeliharaan, tetapi lebih akurat.

Untuk mendemonstrasikan:pustaka sederhana yang dapat dieksekusi dan dimuat secara dinamis.

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

void exported_callback() /*< Function we want to export */
{
    printf("Hello from callback!\n");
}

void unexported_callback() /*< Function we don't want to export */
{
    printf("Hello from unexported callback!\n");
}

typedef void (*lib_func)();

int call_library()
{
   void     *handle  = NULL;
   lib_func  func    = NULL;
   handle = dlopen("./libprog.so", RTLD_NOW | RTLD_GLOBAL);
   if (handle == NULL)
   {
       fprintf(stderr, "Unable to open lib: %s\n", dlerror());
       return -1;
   }
   func = dlsym(handle, "library_function");

   if (func == NULL) {
       fprintf(stderr, "Unable to get symbol\n");
      return -1;
   }

   func();
   return 0;
}

int main(int argc, const char *argv[])
{
    printf("Hello from main!\n");
    call_library();
    return 0;
}

Kode pustaka (lib.c):

#include <stdio.h>
int exported_callback();

int library_function()
{
    printf("Hello from library!\n");
    exported_callback();
    /* unexported_callback(); */ /*< This one will not be exported in the second case */
    return 0;
}

Jadi, pertama bangun perpustakaan (langkah ini tidak berbeda):

 gcc -shared -fPIC lib.c -o libprog.so

Sekarang buat yang dapat dieksekusi dengan semua simbol yang diekspor:

 gcc -Wl,--export-dynamic main.c -o prog.exe -ldl

Jalankan contoh:

 $ ./prog.exe
 Hello from main!
 Hello from library!
 Hello from callback!

Simbol yang diekspor:

 $ objdump -e prog.exe -T | grep callback
 00000000004009f4 g    DF .text  0000000000000015  Base        exported_callback
 0000000000400a09 g    DF .text  0000000000000015  Base        unexported_callback

Sekarang dengan daftar yang diekspor (exported.txt ):

{
    extern "C"
    {
       exported_callback;
    };
};

Bangun &periksa simbol yang terlihat:

$ gcc -Wl,--dynamic-list=./exported.txt main.c -o prog.exe -ldl
$ objdump -e prog.exe -T | grep callback
0000000000400774 g    DF .text  0000000000000015  Base        exported_callback

Anda perlu membuat fungsi register di .so agar executable dapat memberikan penunjuk fungsi ke .so Anda untuk digunakan nanti.

Seperti ini:

void in_main_func () {
// this is the function that need to be called from a .so
}

void (*register_function)(void(*)());
void *handle = dlopen("libmylib.so");

register_function = dlsym(handle, "register_function");

register_function(in_main_func);

register_function perlu menyimpan pointer fungsi dalam variabel di .so di mana fungsi lain di .so dapat menemukannya.

Mylib.c Anda perlu terlihat seperti ini:

void (*callback)() = NULL;

void register_function( void (*in_main_func)())
{
    callback = in_main_func();
}

void function_needing_callback() 
{
     callback();
}

  1. Letakkan prototipe fungsi utama Anda dalam file .h dan sertakan dalam kode pustaka utama dan dinamis Anda.

  2. Dengan GCC, cukup kompilasi program utama Anda dengan -rdynamic bendera.

  3. Setelah dimuat, pustaka Anda akan dapat memanggil fungsi dari program utama.

Sedikit penjelasan lebih lanjut adalah setelah dikompilasi, pustaka dinamis Anda akan memiliki simbol yang tidak terdefinisi di dalamnya untuk fungsi yang ada di kode utama. Setelah aplikasi utama Anda memuat pustaka, simbol akan diselesaikan oleh tabel simbol program utama. Saya telah menggunakan pola di atas berkali-kali dan itu berfungsi dengan sangat baik.


Linux
  1. Mengapa /dev/null Merupakan File? Mengapa Fungsinya Tidak Diimplementasikan Sebagai Program Sederhana?

  2. Bagaimana Memanggil Fungsi Bash Dalam Skrip Bash Di Dalam Awk?

  3. Bagaimana cara menerapkan batas waktu dalam panggilan fungsi baca?

  1. Bisakah exit() gagal menghentikan proses?

  2. Bagaimana saya bisa menautkan ke versi lama dari perpustakaan bersama

  3. Galat Memuat Pustaka Bersama (glew)

  1. Linux – Bagaimana Cara Memastikan Bahwa Pustaka Bersama Akan Memiliki Halaman Memori yang Dibagikan Oleh Beberapa Proses?

  2. Memuat Pustaka Bersama Dan Penggunaan Ram?

  3. Cara Membuat dan Memanggil Fungsi di Bash