GNU/Linux >> Znalost Linux >  >> Linux

Co znamená EXPORT_SYMBOL v kódu jádra Linuxu?

Zpřístupňuje symbol dynamicky načítaným modulům (za předpokladu, že uvedené moduly přidají extern prohlášení).

Není to tak dávno, co se někdo zeptal, jak to používat.


Zde je dobré vysvětlení.

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

Extern je klíčové slovo třídy úložiště C. V jádře, stejně jako v každém jiném Ccode, říká kompilátoru, že definice proměnné nebo funkce, kterou kvalifikuje, je implementována v jiném „souboru“, přesněji řečeno Překladové jednotce (programování) – Wikipedii. Překladová jednotka, která ji definuje, by neměla používat statický kvalifikátor. Proto má tabulka symbolů odpovídající záznam. V době propojení je symbol vyřešen jako obvykle. Pro „exter“ není nic specifického pro jádro.

EXPORT_SYMBOL() je makro, které definují hlavičky linuxového jádra. S externem to nemá mnoho společného. Říká mechanismu kbuild, že zmíněný symbol by měl být součástí globálního seznamu jaderných symbolů. To zase umožňuje modulům jádra k nim přistupovat. Kód, který je zabudován do samotného jádra (na rozdíl od modulu), může samozřejmě přistupovat k jakémukoli nestatickému symbolu prostřednictvím externí deklarace, v souladu s běžným C. Mechanismus EXPORT_SYMBOL() nám umožňuje exportovat symbol pro použití načítatelnými moduly jako studna. Zajímavé je, že symbol takto exportovaný jedním modulem se stává přístupným dalšímu modulu, který na něm může záviset!

Abych to shrnul, extern není specifický pro jádro. Používá se ke kvalifikaci deklarace na nestatický symbol z jiné překladové jednotky. EXPORT_SYMBOL() je specifické pro jádro Linuxu. Používá se v jednotce překladu definice, aby byl symbol dostupný pro načítatelné moduly.

EXPORT_SYMBOL je tedy pouze mechanismus jako extern, ale slouží jako reference mezi načítatelnými moduly, nikoli souborem.

Abychom se posunuli kupředu, můžeme odhadnout, že toho dosáhl externista, protože extern je forma C, která je základem.

Tady je vodítko.

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 }

Nejprve deklarujte externí sym.

Potom řetězec __kstrtab_##sym ==VMLINUX_SYMBOL_STR(sym).

Poslední externí struktura kernel_symbol __ksymtab_##sym ={ (dlouhé bez znaménka)&sym , __kstrtab_##sym }. &sym zaznamenejte skutečnou adresu sym, jako je funkce nebo proměnná, _kstrtab ##sym zaznamenejte řetězec názvu.


Není to odpověď sama o sobě, ale ukázka, jak jsem slíbil z mého komentáře, že exportované symboly nejsou musí být nestatické. Níže uvedené 2 moduly to demonstrují:

/* 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");

A druhý modul

/* 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");

Ty byly testovány na CentOS 6 a CentOS 7:jádra 2.6.32 a 3.10 (v tomto pořadí). Načtení mod1.ko a poté mod2.ko bude mít za následek vytištění hodnoty předané do mod1_exp_func() do vyrovnávacích pamětí protokolu jádra.


Linux
  1. Co dělá jádro Linux Server základním?

  2. Co to znamená, když se řekne linuxové jádro je preemptivní?

  3. Jak načíst moduly jádra Linuxu z kódu C?

  1. Linux – proprietární nebo uzavřené části jádra?

  2. Jaký je aktuální zdrojový kód jádra Linuxu?

  3. Jaký je význam fork() a grep v Linuxu?

  1. Co jsou výstupní kódy Bash v Linuxu

  2. Co znamená __init v kódu jádra Linuxu?

  3. Jaký je význam úvodních a koncových podtržítek v identifikátorech jádra Linuxu?