GNU/Linux >> Belajar Linux >  >> Linux

Apa arti EXPORT_SYMBOL dalam kode kernel Linux?

Itu membuat simbol dapat diakses oleh modul yang dimuat secara dinamis (asalkan modul tersebut menambahkan extern deklarasi).

Belum lama ini, ada yang bertanya bagaimana cara menggunakannya.


Ini penjelasan yang bagus.

https://www.quora.com/What-is-the-difference-between-extern-and-EXPORT_SYMBOL-in-Linux-kernel-codes

Extern adalah kata kunci kelas penyimpanan C. Dalam kernel, seperti dalam Ccode lainnya, ia memberi tahu kompiler bahwa definisi variabel atau fungsi yang memenuhi syarat diimplementasikan dalam "file" lain, atau lebih tepatnya, lebih akurat Unit terjemahan (pemrograman) - Wikipedia. Unit terjemahan yang mendefinisikannya tidak boleh menggunakan qualifier statis. Oleh karena itu, tabel simbol memiliki entri yang sesuai dengannya. Pada waktu tautan, simbol diselesaikan seperti biasa. Tidak ada yang spesifik tentang kernel tentang "eksternal".

EXPORT_SYMBOL() adalah makro yang ditentukan oleh header kernel Linux. Ini tidak memiliki banyak kesamaan dengan eksternal. Ini memberi tahu mekanisme kbuild bahwa simbol yang dimaksud harus menjadi bagian dari daftar global simbol kernel. Itu, pada gilirannya memungkinkan modul kernel untuk mengaksesnya. Kode yang dibangun ke dalam kernel itu sendiri (berlawanan dengan modul), tentu saja, dapat mengakses simbol non-statis apa pun melalui deklarasi extern, sesuai dengan C biasa. Mekanisme EXPORT_SYMBOL() memungkinkan kita untuk mengekspor simbol untuk digunakan oleh modul yang dapat dimuat sebagai dengan baik. Hal yang menarik adalah simbol yang diekspor oleh satu modul menjadi dapat diakses oleh modul lain yang mungkin bergantung padanya!

Singkatnya, extern tidak spesifik untuk kernel. Ini digunakan untuk memenuhi syarat deklarasi ke simbol non-statis dari unit terjemahan lain.EXPORT_SYMBOL() dikhususkan untuk kernel Linux. Ini digunakan dalam unit terjemahan definisi untuk membuat simbol tersedia untuk modul yang dapat dimuat.

Jadi EXPORT_SYMBOL hanyalah mekanisme seperti extern, tetapi untuk referensi antara modul yang dapat dimuat, bukan file.

Untuk maju, kita bisa menebak itu dicapai oleh extern karena extern adalah bentuk C yang merupakan fondasinya.

Ini petunjuknya.

https://elixir.bootlin.com/linux/v4.6.7/source/include/linux/export.h#L56

#define EXPORT_SYMBOL(sym)                  \
    __EXPORT_SYMBOL(sym, "")

/* For every exported symbol, place a struct in the __ksymtab section */
#define __EXPORT_SYMBOL(sym, sec)               \
    extern typeof(sym) sym;                 \
    __CRC_SYMBOL(sym, sec)                  \
    static const char __kstrtab_##sym[] __attribute__((section("__ksymtab_strings"), aligned(1)))  = VMLINUX_SYMBOL_STR(sym);               \
    extern const struct kernel_symbol __ksymtab_##sym;  \
    __visible const struct kernel_symbol __ksymtab_##sym    __used __attribute__((section("___ksymtab" sec "+" #sym), unused)) = { (unsigned long)&sym, __kstrtab_##sym }

Pertama, deklarasikan sym eksternal.

Kemudian sebuah string __kstrtab_##sym ==VMLINUX_SYMBOL_STR(sym).

Terakhir extern struct kernel_symbol __ksymtab_##sym ={ (unsigned long)&sym , __kstrtab_##sym }. &simbol catat alamat sebenarnya dari sym seperti fungsi atau variabel, _kstrtab ##simbol rekam string nama.


Bukan jawaban semata tetapi demonstrasi, seperti yang dijanjikan dari komentar saya, bahwa simbol yang diekspor tidak harus non-statis. 2 modul di bawah ini menunjukkan hal ini:

/* mod1.c */
#include <linux/module.h>

static int mod1_exp_func(int i)
{
    pr_info("%s:%d the value passed in is %d\n",
            __func__, __LINE__, i);

    return i;
}
EXPORT_SYMBOL(mod1_exp_func); /* export static symbol */

static int __init mod1_init(void)
{
    pr_info("Initializing simple mod\n");
    return 0;
}

static void __exit mod1_exit(void)
{
    pr_info("This module is exiting\n");
}

module_init(mod1_init);
module_exit(mod1_exit);
MODULE_LICENSE("GPL v2");

Dan modul kedua

/* mod2.c */
#include <linux/module.h>

extern int mod1_exp_func(int);

static int __init mod2_init(void)
{
    pr_info("Initializing mod2\n");
    pr_info("Calling exported function in mod1\n");
    mod1_exp_func(3);
    return 0;
}

static void __exit mod2_exit(void)
{
    pr_info("mod2 exiting\n");
}

module_init(mod2_init);
module_exit(mod2_exit);
MODULE_LICENSE("GPL v2");

Ini diuji pada CentOS 6 &CentOS 7:kernel 2.6.32 dan 3.10 (masing-masing). Memuat mod1.ko lalu mod2.ko akan menghasilkan nilai yang diteruskan ke mod1_exp_func() yang dicetak ke buffer log kernel.


Linux
  1. Apa itu Kode Keluar Bash di Linux

  2. Bagaimana cara memuat modul kernel Linux dari kode C?

  3. Apa yang lebih baik int 0x80 atau syscall dalam kode 32-bit di Linux?

  1. Bagaimana cara membuat kode modul kernel Linux?

  2. Arti rc5 di linux kernel 2.6.37-rc5

  3. apa resolusi jiffie di Linux Kernel

  1. Linux – Bagian Kernel yang Dimiliki Atau Tertutup?

  2. Apa yang Membuat Server Linux Kernel Mendasar?

  3. Apa arti curl -k -i -X ​​di Linux?