国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Linux 內(nèi)核函數(shù)kallsyms_lookup_name

這篇具有很好參考價值的文章主要介紹了Linux 內(nèi)核函數(shù)kallsyms_lookup_name。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

前言

內(nèi)核模塊開發(fā)的基本規(guī)則之一是,模塊只能訪問已顯式導(dǎo)出的符號(函數(shù)和數(shù)據(jù)結(jié)構(gòu)),內(nèi)核使用EXPORT_SYMBOL宏和EXPORT_SYMBOL_GPL宏來導(dǎo)出符號。
關(guān)于EXPORT_SYMBOL宏和EXPORT_SYMBOL_GPL宏請參考:Linux EXPORT_SYMBOL宏詳解

即便如此,許多符號也受到限制,因此只有具有GPL兼容許可證的模塊才能訪問它們。然而,事實證明,有一種現(xiàn)成的解決方法,可以讓模塊輕松訪問它想要的任何符號,那就是使用內(nèi)核函數(shù)kallsyms_lookup_name來獲取沒有使用EXPORT_SYMBOL宏和EXPORT_SYMBOL_GPL宏來導(dǎo)出符號。

kallsyms_lookup_name它將返回與內(nèi)核符號表中任何符號相關(guān)的地址。

EXPORT_SYMBOL_GPL(kallsyms_lookup_name);

但使用kallsyms_lookup_name方法來獲取沒有導(dǎo)出內(nèi)核符號的地址在內(nèi)核版本5.7被刪除,即在內(nèi)核版本5.7即以上該函數(shù)沒有被導(dǎo)出。

一、API使用

kallsyms_lookup_name 是一個內(nèi)核函數(shù),用于通過符號名稱查找相應(yīng)的符號地址。它是內(nèi)核符號查找機(jī)制的一部分,允許內(nèi)核代碼和模塊在運(yùn)行時動態(tài)地查找和訪問內(nèi)核符號。

只要符號存在于/proc/kallsyms 文件中,都可以通過kallsyms_lookup_name獲取其符號的地址。

內(nèi)核版本 2.6.33 - 5.7.0 該符號都是導(dǎo)出的:

# cat /proc/kallsyms | grep '\<kallsyms_lookup_name\>'
ffffffffb8558e90 T kallsyms_lookup_name
// linux-4.19.90/kernel/kallsyms.c

/* Lookup the address for this symbol. Returns 0 if not found. */
unsigned long kallsyms_lookup_name(const char *name)
{
	char namebuf[KSYM_NAME_LEN];
	unsigned long i;
	unsigned int off;

	for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
		off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));

		if (strcmp(namebuf, name) == 0)
			return kallsyms_sym_address(i);
	}
	return module_kallsyms_lookup_name(name);
}
EXPORT_SYMBOL_GPL(kallsyms_lookup_name);

使用EXPORT_SYMBOL_GPL宏導(dǎo)出kallsyms_lookup_name函數(shù)。

然而在 2.6.33 以下和 5.7.0 以上該函數(shù)沒有使用EXPORT_SYMBOL_GPL導(dǎo)出,比如5.19:

// linux-5.19/include/linux/kallsyms.h

/* Lookup the address for a symbol. Returns 0 if not found. */
unsigned long kallsyms_lookup_name(const char *name);
// linux-5.19/kernel/kallsyms.c

/* Lookup the address for this symbol. Returns 0 if not found. */
unsigned long kallsyms_lookup_name(const char *name)
{
	char namebuf[KSYM_NAME_LEN];
	unsigned long i;
	unsigned int off;

	/* Skip the search for empty string. */
	if (!*name)
		return 0;

	for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
		off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));

		if (strcmp(namebuf, name) == 0)
			return kallsyms_sym_address(i);

		if (cleanup_symbol_name(namebuf) && strcmp(namebuf, name) == 0)
			return kallsyms_sym_address(i);
	}
	return module_kallsyms_lookup_name(name);
}

對于在高版本內(nèi)核kallsyms_lookup_name不在導(dǎo)出的原因請參考:https://lwn.net/Articles/813350/

雖然沒有導(dǎo)出,但還是可以在/proc/kallsym 獲取其地址,如下:

# uname -r
5.19.0-46-generic
# cat /proc/kallsyms | grep "\<kallsyms_lookup_name\>"
ffffffffb9bbba60 T kallsyms_lookup_name

因此在 2.6.33 以下和 5.7.0 以上可以用 kprobe 來獲取該函數(shù)的地址:

#include <linux/version.h>
#include <linux/kallsyms.h>

#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0) || LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)

#include <linux/kprobes.h>

static unsigned long (*kallsyms_lookup_name_sym)(const char *name);

static int _kallsyms_lookup_kprobe(struct kprobe *p, struct pt_regs *regs)
{
        return 0;
}

unsigned long get_kallsyms_func(void)
{
        struct kprobe probe;
        int ret;
        unsigned long addr;

        memset(&probe, 0, sizeof(probe));
        probe.pre_handler = _kallsyms_lookup_kprobe;
        probe.symbol_name = "kallsyms_lookup_name";
        ret = register_kprobe(&probe);
        if (ret)
                return 0;
        addr = (unsigned long)probe.addr;
        unregister_kprobe(&probe);
        return addr;
}

unsigned long generic_kallsyms_lookup_name(const char *name)
{
        /* singleton */
        if (!kallsyms_lookup_name_sym) {
                kallsyms_lookup_name_sym = (void *)get_kallsyms_func();
                if(!kallsyms_lookup_name_sym)
                        return 0;
        }
        return kallsyms_lookup_name_sym(name);
}

#else

unsigned long generic_kallsyms_lookup_name(const char *name)
{
    return kallsyms_lookup_name(name);
}

#endif

這樣generic_kallsyms_lookup_name在所有內(nèi)核版本都可以完成kallsyms_lookup_name的功能。

二、源碼解析

2.1 kallsyms_lookup_name

extern const unsigned long kallsyms_num_syms
__attribute__((weak, section(".rodata")));

/* Lookup the address for this symbol. Returns 0 if not found. */
unsigned long kallsyms_lookup_name(const char *name)
{
	char namebuf[KSYM_NAME_LEN];
	unsigned long i;
	unsigned int off;

	for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
		off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf));

		if (strcmp(namebuf, name) == 0)
			return kallsyms_sym_address(i);
	}
	return module_kallsyms_lookup_name(name);
}
EXPORT_SYMBOL_GPL(kallsyms_lookup_name);

首先定義了一個名為 namebuf 的字符數(shù)組,用于存儲擴(kuò)展后的符號名稱。KSYM_NAME_LEN 是一個常量,表示符號名稱的最大長度。

接下來,函數(shù)通過一個循環(huán)來遍歷符號表中的每個符號。kallsyms_num_syms 是一個表示符號表中符號數(shù)量的變量。

在循環(huán)中,使用 kallsyms_expand_symbol 函數(shù)對符號進(jìn)行解壓縮,將解壓后的符號名稱存儲在 namebuf 中。

然后,函數(shù)將解壓后的符號名稱與傳入的 name 進(jìn)行比較。如果找到匹配的符號名稱,函數(shù)返回相應(yīng)符號的地址,即通過 kallsyms_sym_address 函數(shù)獲取的地址。

如果循環(huán)結(jié)束后仍然沒有找到匹配的符號,函數(shù)調(diào)用 module_kallsyms_lookup_name 函數(shù),用于在內(nèi)核模塊中查找符號。

最后,通過 EXPORT_SYMBOL_GPL 宏,將 kallsyms_lookup_name 函數(shù)導(dǎo)出為內(nèi)核符號,以便其他模塊或代碼可以引用和使用該函數(shù)。

2.2 kallsyms_expand_symbol

(1)

extern const u8 kallsyms_names[] __weak;

extern const u8 kallsyms_token_table[] __weak;
extern const u16 kallsyms_token_index[] __weak;

/*
 * Expand a compressed symbol data into the resulting uncompressed string,
 * if uncompressed string is too long (>= maxlen), it will be truncated,
 * given the offset to where the symbol is in the compressed stream.
 */
static unsigned int kallsyms_expand_symbol(unsigned int off,
					   char *result, size_t maxlen)
{
	int len, skipped_first = 0;
	const u8 *tptr, *data;

	/* Get the compressed symbol length from the first symbol byte. */
	data = &kallsyms_names[off];
	len = *data;
	data++;

	/*
	 * Update the offset to return the offset for the next symbol on
	 * the compressed stream.
	 */
	off += len + 1;

	/*
	 * For every byte on the compressed symbol data, copy the table
	 * entry for that byte.
	 */
	while (len) {
		tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
		data++;
		len--;

		while (*tptr) {
			if (skipped_first) {
				if (maxlen <= 1)
					goto tail;
				*result = *tptr;
				result++;
				maxlen--;
			} else
				skipped_first = 1;
			tptr++;
		}
	}

tail:
	if (maxlen)
		*result = '\0';

	/* Return to offset to the next symbol. */
	return off;
}

用于將壓縮的符號數(shù)據(jù)展開為未壓縮的字符串形式。

kallsyms_names數(shù)組保存每一個內(nèi)核符號名字被壓縮后的字節(jié)編碼。存儲的格式是 len + data,data是壓縮后的字符編碼。

函數(shù)的參數(shù)和功能如下:

off:指定符號在壓縮流中的偏移量。
result:存儲展開后的符號字符串的緩沖區(qū)。
maxlen:緩沖區(qū)的最大長度,用于避免字符串溢出。

函數(shù)首先從壓縮流中獲取符號的壓縮長度,并將其存儲在變量 len 中。然后,更新偏移量 off,使其指向下一個符號在壓縮流中的位置。

接下來,函數(shù)開始解壓縮符號數(shù)據(jù)。它逐字節(jié)遍歷壓縮的符號數(shù)據(jù),根據(jù)每個字節(jié)在符號表中的索引,從符號表中獲取相應(yīng)的字符,并將其復(fù)制到結(jié)果緩沖區(qū)中。

在解壓縮過程中,函數(shù)會跳過第一個字符,并將 skipped_first 設(shè)置為 1,這是為了處理一種特殊情況,即如果結(jié)果緩沖區(qū)的長度不足以容納完整的符號,則只復(fù)制符號的一部分。

當(dāng)解壓縮完成后,函數(shù)檢查剩余的緩沖區(qū)空間。如果緩沖區(qū)還有剩余空間,將在末尾添加空字符 ‘\0’,以確保結(jié)果字符串以 null 結(jié)尾。

最后,函數(shù)返回下一個符號在壓縮流中的偏移量,以便在下次解壓縮時使用。

(2)

extern const u8 kallsyms_token_table[] __weak;
extern const u16 kallsyms_token_index[] __weak;

kallsyms_token_table 和 kallsyms_token_index 數(shù)組在 Linux 內(nèi)核的符號查找機(jī)制中用于符號展開過程。

這些數(shù)組的作用是提供壓縮的符號數(shù)據(jù)與對應(yīng)的未壓縮字符之間的映射關(guān)系,以高效地將壓縮的符號展開為原始的字符串形式。

以下是對這兩個數(shù)組的簡要說明:

kallsyms_token_table:該數(shù)組包含了用作壓縮符號表示中的標(biāo)記(token)的字符表。每個標(biāo)記表示一系列在符號名稱中常見的字符序列。數(shù)組中的條目被組織成一種能夠高效查找標(biāo)記索引的方式。

kallsyms_token_index:該數(shù)組用作對 kallsyms_token_table 的索引。它將壓縮符號數(shù)據(jù)中的每個字節(jié)值映射到對應(yīng)的標(biāo)記表條目。在符號展開過程中,通過這個索引可以快速獲取壓縮數(shù)據(jù)中的字節(jié)對應(yīng)的字符序列。

在符號展開過程中,kallsyms_expand_symbol 函數(shù)逐字節(jié)遍歷壓縮的符號數(shù)據(jù)。對于每個字節(jié),它使用 kallsyms_token_index 數(shù)組獲取對應(yīng)的 kallsyms_token_table 中的索引。然后,從標(biāo)記表中獲取相應(yīng)的字符序列,并將其復(fù)制到結(jié)果緩沖區(qū)中。

通過使用標(biāo)記和索引,符號展開過程避免了在壓縮的符號數(shù)據(jù)中多次存儲重復(fù)的字符。相反,它使用較短的標(biāo)記表示常見字符序列,從而實現(xiàn)了對符號名稱的更高效壓縮和解壓縮。

kallsyms_token_table 和 kallsyms_token_index 數(shù)組在 Linux 內(nèi)核中的符號壓縮和展開機(jī)制中起著關(guān)鍵作用,通過優(yōu)化符號名稱的存儲和查找,提高了效率。

(3)
符號數(shù)據(jù)通常是通過編譯器和鏈接器生成的。這些符號數(shù)據(jù)包括函數(shù)名、變量名以及其他在編譯和鏈接過程中產(chǎn)生的符號,然后保存在內(nèi)核符號表(kernel symbol table)。

壓縮的符號數(shù)據(jù)來源通常是內(nèi)核符號表(kernel symbol table)。內(nèi)核符號表包含了各種內(nèi)核函數(shù)、變量和其他符號的信息,例如函數(shù)名、變量名以及其對應(yīng)的地址等。

內(nèi)核符號表中的符號信息通過特定的壓縮算法進(jìn)行壓縮,以減小其大小并節(jié)省存儲空間。

在編譯內(nèi)核時,可以選擇啟用內(nèi)核符號表的生成。通過特定的編譯選項,例如 CONFIG_KALLSYMS,可以將內(nèi)核符號信息保留在編譯后的內(nèi)核鏡像中。這樣,在運(yùn)行時,可以通過相應(yīng)的機(jī)制(例如 /proc/kallsyms 文件)讀取內(nèi)核符號表,并將符號信息保存在內(nèi)存中。

# cat /boot/config-4.19.90-23.8.v2101.ky10.x86_64 | grep CONFIG_KALLSYMS
CONFIG_KALLSYMS=y

壓縮的符號數(shù)據(jù)是通過對內(nèi)核符號表中的符號信息進(jìn)行壓縮算法處理而得到的。這樣做的目的是減小符號數(shù)據(jù)的大小,節(jié)省內(nèi)存空間和存儲空間。在壓縮過程中,符號的名稱和其他相關(guān)信息被編碼為壓縮格式,以便在需要時進(jìn)行解壓縮并恢復(fù)出原始的符號信息。

關(guān)于符號數(shù)據(jù)的壓縮,Linux內(nèi)核中使用了一種簡單的壓縮算法,將符號數(shù)據(jù)進(jìn)行壓縮以節(jié)省內(nèi)存空間。這種壓縮算法使用了基于標(biāo)記的方法,其中kallsyms_token_table和kallsyms_token_index數(shù)組用于解壓縮過程。

在內(nèi)核構(gòu)建過程中,符號數(shù)據(jù)首先被收集,并將其壓縮為一個壓縮流。壓縮的符號數(shù)據(jù)流中的每個字節(jié)都對應(yīng)于kallsyms_token_table中的一個標(biāo)記,或者表示一個特定的字符。通過解壓縮過程,這些壓縮的符號數(shù)據(jù)將被展開為原始的符號字符串。

kallsyms_expand_symbol 函數(shù)中的代碼片段處理的就是這樣的壓縮的符號數(shù)據(jù),通過解壓縮算法和相關(guān)的表格,將其還原為未壓縮的字符串形式,以便進(jìn)行進(jìn)一步的處理和使用。

備注:
具體的壓縮過程在內(nèi)核的構(gòu)建腳本中實現(xiàn),而不是在內(nèi)核源碼中:

// linux-4.19.90/scripts/kallsyms.c

/* replace a given token in all the valid symbols. Use the sampled symbols
 * to update the counts */
static void compress_symbols(unsigned char *str, int idx)
{
	unsigned int i, len, size;
	unsigned char *p1, *p2;

	for (i = 0; i < table_cnt; i++) {

		len = table[i].len;
		p1 = table[i].sym;

		/* find the token on the symbol */
		p2 = find_token(p1, len, str);
		if (!p2) continue;

		/* decrease the counts for this symbol's tokens */
		forget_symbol(table[i].sym, len);

		size = len;

		do {
			*p2 = idx;
			p2++;
			size -= (p2 - p1);
			memmove(p2, p2 + 1, size);
			p1 = p2;
			len--;

			if (size < 2) break;

			/* find the token on the symbol */
			p2 = find_token(p1, size, str);

		} while (p2);

		table[i].len = len;

		/* increase the counts for this symbol's new tokens */
		learn_symbol(table[i].sym, len);
	}
}

隨著內(nèi)核的發(fā)展,可能會采用更為復(fù)雜的壓縮算法,以提高壓縮率和解壓縮效率。例如,使用字典壓縮算法,如LZ77或LZ78變種,通過建立符號字典并對重復(fù)的符號序列進(jìn)行替換來實現(xiàn)壓縮。這些算法通常會結(jié)合其他技術(shù),如霍夫曼編碼或算術(shù)編碼,進(jìn)一步提高壓縮效果。

2.3 kallsyms_sym_address

extern const int kallsyms_offsets[] __weak;

extern const unsigned long kallsyms_relative_base
__attribute__((weak, section(".rodata")));


static unsigned long kallsyms_sym_address(int idx)
{
	if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE))
		return kallsyms_addresses[idx];

	/* values are unsigned offsets if --absolute-percpu is not in effect */
	if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU))
		return kallsyms_relative_base + (u32)kallsyms_offsets[idx];

	/* ...otherwise, positive offsets are absolute values */
	if (kallsyms_offsets[idx] >= 0)
		return kallsyms_offsets[idx];

	/* ...and negative offsets are relative to kallsyms_relative_base - 1 */
	return kallsyms_relative_base - 1 - kallsyms_offsets[idx];
}

用于在內(nèi)核中獲取符號地址的函數(shù)kallsyms_sym_address的實現(xiàn)。根據(jù)給定的索引idx,該函數(shù)返回對應(yīng)符號的地址。

該函數(shù)的實現(xiàn)基于一些條件編譯選項,包括CONFIG_KALLSYMS_BASE_RELATIVE和CONFIG_KALLSYMS_ABSOLUTE_PERCPU。這些選項根據(jù)內(nèi)核的配置狀態(tài)來確定符號地址的計算方式。

目前我接觸的x86_64和arm64 都配置了CONFIG_KALLSYMS_BASE_RELATIVE編譯選項。在啟用CONFIG_KALLSYMS_BASE_RELATIVE選項時,符號地址以相對于基地址的偏移量形式存儲,而不是絕對地址。kallsyms_relative_base表示這個基地址:

kallsyms_relative_base變量作為基地址,用于計算相對符號地址。
kallsyms_offsets 是一個數(shù)組,記錄著每一個符號相對于kallsyms_relative_base變量的偏移量。

但是x86_64配置了CONFIG_KALLSYMS_ABSOLUTE_PERCPU選項,arm64沒有配置CONFIG_KALLSYMS_ABSOLUTE_PERCPU選項。

CONFIG_KALLSYMS_ABSOLUTE_PERCPU 選項與 kallsyms 特性中的 per-CPU 符號處理相關(guān)。Per-CPU 符號是針對系統(tǒng)中每個 CPU 單獨存在的特殊符號。這些符號通常用于存儲特定于每個 CPU 的數(shù)據(jù)或狀態(tài)。

當(dāng)啟用 CONFIG_KALLSYMS_ABSOLUTE_PERCPU 時,意味著在 kallsyms 機(jī)制中將 per-CPU 符號視為絕對值。正的 per-CPU 符號的偏移量被視為絕對地址,而負(fù)的偏移量被視為相對于特定基地址(kallsyms_relative_base - 1)的相對地址。

另一方面,當(dāng)未啟用 CONFIG_KALLSYMS_ABSOLUTE_PERCPU 時,per-CPU 符號被視為相對于基地址(kallsyms_relative_base)的無符號偏移量?;刂废鄬Φ姆椒梢愿o湊地存儲 per-CPU 符號在符號表中的表示。

2.3.1 x86_64

# cat /etc/os-release
NAME="Kylin Linux Advanced Server"

# uname -r
4.19.90-23.8.v2101.ky10.x86_64

# lscpu
架構(gòu):                           x86_64
# cat /boot/config-4.19.90-23.8.v2101.ky10.x86_64 | grep CONFIG_KALLSYMS_BASE_RELATIVE
CONFIG_KALLSYMS_BASE_RELATIVE=y
# cat /boot/config-4.19.90-23.8.v2101.ky10.x86_64 | grep CONFIG_KALLSYMS_ABSOLUTE_PERCPU
CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y
static unsigned long kallsyms_sym_address(int idx)
{
	/* ...otherwise, positive offsets are absolute values */
	if (kallsyms_offsets[idx] >= 0)
		return kallsyms_offsets[idx];

	/* ...and negative offsets are relative to kallsyms_relative_base - 1 */
	return kallsyms_relative_base - 1 - kallsyms_offsets[idx];
}

CONFIG_KALLSYMS_ABSOLUTE_PERCPU啟用,表示偏移量包含正負(fù)值,函數(shù)根據(jù)正負(fù)值決定地址的計算方式。

如果偏移量kallsyms_offsets[idx]大于等于0,表示偏移量是絕對值,函數(shù)返回kallsyms_offsets[idx]作為地址。
正數(shù):表示符號的地址是絕對地址,可以直接作為符號的地址使用。

如果偏移量kallsyms_offsets[idx]小于0,表示偏移量是相對于kallsyms_relative_base - 1的負(fù)值,函數(shù)返回kallsyms_relative_base - 1 - kallsyms_offsets[idx]作為地址。
負(fù)數(shù):表示符號的地址是相對于 kallsyms_relative_base - 1 地址的偏移量。通過將偏移量從 kallsyms_relative_base - 1 中減去,可以計算出符號的實際地址。

CONFIG_KALLSYMS_ABSOLUTE_PERCPU用于控制符號地址在處理器特定數(shù)據(jù)區(qū)(per-CPU)時的解釋方式。

在內(nèi)核中,有一些符號(如變量或函數(shù))可以在每個處理器的特定數(shù)據(jù)區(qū)中有不同的副本。這是為了提高性能和并發(fā)性。這些符號在每個處理器的數(shù)據(jù)區(qū)中的地址可能是相對于某個基地址而不是絕對地址。

當(dāng)啟用了CONFIG_KALLSYMS_ABSOLUTE_PERCPU選項時,表示偏移值中的正數(shù)偏移是絕對地址,而負(fù)數(shù)偏移是相對于基地址的偏移量。這意味著符號在每個處理器的數(shù)據(jù)區(qū)中具有不同的絕對地址。

當(dāng)啟用CONFIG_KALLSYMS_ABSOLUTE_PERCPU配置選項時,表示每個處理器特定數(shù)據(jù)區(qū)(per-CPU)的符號具有獨立的絕對地址。這意味著每個處理器的符號地址不是相對于共享基地址的,而是每個處理器都有自己獨特的絕對地址。

2.3.2 arm64

# cat /etc/os-release
NAME="Kylin Linux Advanced Server"

# uname -r
4.19.90-24.4.v2101.ky10.aarch64

# lscpu
架構(gòu):                           aarch64
# cat /boot/config-4.19.90-24.4.v2101.ky10.aarch64 | grep CONFIG_KALLSYMS_BASE_RELATIVE
CONFIG_KALLSYMS_BASE_RELATIVE=y
# cat /boot/config-4.19.90-24.4.v2101.ky10.aarch64 | grep CONFIG_KALLSYMS_ABSOLUTE_PERCPU

沒有CONFIG_KALLSYMS_ABSOLUTE_PERCPU選項。

當(dāng)未啟用CONFIG_KALLSYMS_ABSOLUTE_PERCPU選項時,每個處理器特定數(shù)據(jù)區(qū)的符號通常表示為相對于共享基地址的偏移量。通過偏移量與基地址相加,內(nèi)核可以計算出實際的每個處理器特定數(shù)據(jù)區(qū)中的符號地址。這種方法通過避免為每個處理器存儲單獨的絕對地址,節(jié)省了內(nèi)存。

static unsigned long kallsyms_sym_address(int idx)
{
	/* values are unsigned offsets if --absolute-percpu is not in effect */
	if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU))
		return kallsyms_relative_base + (u32)kallsyms_offsets[idx];

如果CONFIG_KALLSYMS_ABSOLUTE_PERCPU未啟用,表示偏移量是無符號的,函數(shù)返回kallsyms_relative_base + (u32)kallsyms_offsets[idx],其中kallsyms_relative_base是一個基地址,kallsyms_offsets是一個無符號偏移量數(shù)組。

函數(shù)通過將基地址(kallsyms_relative_base)與無符號偏移值(kallsyms_offsets[idx])相加來計算相對地址。

2.3.3 CONFIG_KALLSYMS_ABSOLUTE_PERCPU

在內(nèi)核中啟用CONFIG_KALLSYMS_ABSOLUTE_PERCPU選項對性能的影響:

符號查找效率提高: 啟用CONFIG_KALLSYMS_ABSOLUTE_PERCPU選項后,每個處理器特定數(shù)據(jù)區(qū)的符號都有自己的絕對地址,而不是相對于基地址的偏移量。這意味著符號查找可以更快速和直接地進(jìn)行,因為不再需要計算相對地址。這可能會提高符號查找的效率,特別是在需要頻繁訪問處理器特定數(shù)據(jù)區(qū)的情況下。

內(nèi)存占用增加: 啟用CONFIG_KALLSYMS_ABSOLUTE_PERCPU選項會導(dǎo)致每個處理器特定數(shù)據(jù)區(qū)的符號都需要獨立的絕對地址。相對于使用相對地址來表示,這可能會增加內(nèi)存的占用量,因為需要為每個處理器存儲獨立的地址。如果系統(tǒng)中有大量的處理器或大量的處理器特定數(shù)據(jù)區(qū)符號,這種額外的內(nèi)存開銷可能是顯著的。

啟動時間延長: 內(nèi)核在啟動時需要解析符號表并建立符號地址的映射關(guān)系。啟用CONFIG_KALLSYMS_ABSOLUTE_PERCPU選項后,需要額外的工作來處理每個處理器特定數(shù)據(jù)區(qū)的符號地址。這可能會導(dǎo)致啟動時間延長,特別是在有大量處理器或處理器特定數(shù)據(jù)區(qū)符號的系統(tǒng)中。

代碼復(fù)雜性增加: 啟用CONFIG_KALLSYMS_ABSOLUTE_PERCPU選項會引入對處理器特定數(shù)據(jù)區(qū)符號的維護(hù)和處理的復(fù)雜性。需要確保每個處理器的符號地址在正確的位置,并且符號查找和解釋邏輯需要處理符號地址的絕對性和相對性。這可能增加內(nèi)核代碼的復(fù)雜性和維護(hù)成本。

參考資料

Linux 4.19.90

https://lwn.net/Articles/813350/
https://blog.csdn.net/weixin_38878510/article/details/113264807文章來源地址http://www.zghlxwxcb.cn/news/detail-674000.html

到了這里,關(guān)于Linux 內(nèi)核函數(shù)kallsyms_lookup_name的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Excel:通過Lookup函數(shù)提取指定文本關(guān)鍵詞

    Excel:通過Lookup函數(shù)提取指定文本關(guān)鍵詞

    函數(shù)公式 :=LOOKUP(9^9,FIND($G 2 : 2: 2 : G 6 , C 2 ) , 6,C2), 6 , C 2 ) , G 2 : 2: 2 : G$6) 公式解釋 : lookup第一參數(shù)為9^9:代表的是一個極大值的數(shù)據(jù),查詢位置里面最接近這一個值的數(shù)據(jù); lookup第二參數(shù)用find函數(shù)代替,目的就是查詢我們的在對應(yīng)文本找那個的位置; lookup第三參數(shù)

    2024年02月11日
    瀏覽(23)
  • 深入分析linux內(nèi)核的內(nèi)存分配函數(shù)devm_kzalloc

    深入分析linux內(nèi)核的內(nèi)存分配函數(shù)devm_kzalloc

    在分析驅(qū)動代碼的時候,經(jīng)常會遇到使用devm_kzalloc()為一個設(shè)備分配一片內(nèi)存的情況。devm_kzalloc()是內(nèi)核用來分配內(nèi)存的函數(shù),同樣可以分配內(nèi)存的內(nèi)核函數(shù)還有devm_kmalloc, kzalloc, kmalloc。它們之間的區(qū)別在于devm_XXX分配的內(nèi)存可以跟設(shè)備進(jìn)行綁定,當(dāng)設(shè)備跟驅(qū)動分離時,跟設(shè)備

    2024年02月02日
    瀏覽(25)
  • Excel 公式的定義、語法和應(yīng)用(LOOKUP 函數(shù)、HLOOKUP 函數(shù)、VLOOKUP 函數(shù);MODE.MULT 函數(shù); ROUND 函數(shù))

    Excel 公式的定義、語法和應(yīng)用(LOOKUP 函數(shù)、HLOOKUP 函數(shù)、VLOOKUP 函數(shù);MODE.MULT 函數(shù); ROUND 函數(shù))

    查找Excel公式使用方法的官方工具【強(qiáng)烈推薦?。?!】:Excel 函數(shù)(按字母順序)【微軟官網(wǎng)】 excel 函數(shù) 說明 語法 LOOKUP 函數(shù) 在向量或數(shù)組中查找值 LOOKUP(lookup_value, lookup_vector, [result_vector]) HLOOKUP 函數(shù) 在數(shù)組的頂行中查找并返回指定單元格的值 HLOOKUP(lookup_value, table_array, r

    2024年04月26日
    瀏覽(29)
  • bootz啟動 Linux內(nèi)核過程中涉及的 do_bootm_states 函數(shù)

    uboot 啟動Linux內(nèi)核使用bootz命令。當(dāng)然還有其它的啟動命令,例如,bootm命令等等。 本文只分析 bootz命令啟動 Linux內(nèi)核的過程中涉及的幾個重要函數(shù)。具體分析? do_bootm_states 函數(shù)執(zhí)行過程。 本文繼上一篇文章,地址如下: bootz啟動 Linux內(nèi)核過程中涉及的 bootz_start 函數(shù)-CSDN博客

    2024年02月04日
    瀏覽(290)
  • linux內(nèi)核內(nèi)存分配函數(shù)kmalloc()、kzalloc()、vmalloc()與__get_free_page()

    目錄 1、值得注意的點 2、函數(shù)原型 2.1 kmalloc()與kfree() 2.2 kzalloc與kfree() 2.3 vmalloc與vfree() 2.4?__get_free_page()與free_pages() 2.5?__get_free_pages()與free_pages() 2.6 get_zeroed_page() 1、內(nèi)核把物理 頁 作為內(nèi)存管理的基本單位,盡管處理器的最小尋址單位通常為字(或者為字節(jié)),但是MMU(內(nèi)存

    2024年02月12日
    瀏覽(33)
  • Linux 動態(tài)庫跨庫調(diào)用 symbol lookup error原因詳解

    今天調(diào)試了一個程序,發(fā)現(xiàn)symbol lookup error,本想網(wǎng)上找一下方法解決算了怎料找了半天都沒寫根因的文章,好不容易找到一篇類似的,竟然要收費(fèi)! 自此打算分析一下,symbol lookup error無非就是鏈接和庫的查找問題。 先說我的應(yīng)用場景(簡化): 主程序(main)調(diào)用A(libef

    2024年02月10日
    瀏覽(24)
  • C //練習(xí) 6-5 編寫函數(shù)undef,它將從由lookup和install維護(hù)的表中刪除一個變量及其定義。

    練習(xí) 6-5 編寫函數(shù)undef,它將從由lookup和install維護(hù)的表中刪除一個變量及其定義。 注意:代碼在win32控制臺運(yùn)行,在不同的IDE環(huán)境下,有部分可能需要變更。 IDE工具:Visual Studio 2010 ? 代碼塊:

    2024年01月21日
    瀏覽(29)
  • 【Linux】symbol lookup error: undefined symbol + nm指令定位錯誤

    一、undefined symbol錯誤 今天在運(yùn)行模塊執(zhí)行文件時,出現(xiàn)了如下報錯 \\\"symbol lookup error\\\"、\\\"undefined symbol\\\",提示 cos_getfile_mcd 可執(zhí)行文件在加載 .so 文件時,出現(xiàn)了無法找到符號的錯誤,并給出了具體錯誤:_ZN20CCosGetfileTimerInfoC2Ev 符號未定義。 那么如何定位該錯誤呢?一般可以先

    2024年02月08日
    瀏覽(14)
  • 嵌入式培訓(xùn)機(jī)構(gòu)四個月實訓(xùn)課程筆記(完整版)-Linux ARM驅(qū)動編程第七天-內(nèi)核函數(shù)接口(物聯(lián)技術(shù)666)

    鏈接:https://pan.baidu.com/s/1V0E9IHSoLbpiWJsncmFgdA?pwd=1688 提取碼:1688 //************************************************** #include linux/module.h??? /*module_init()*/ #include linux/kernel.h??????? /* printk() */ #include linux/init.h??????????? /* __init __exit */ #include linux/fs.h????????????? /* file_opera

    2024年02月22日
    瀏覽(33)
  • 驅(qū)動開發(fā):內(nèi)核文件讀寫系列函數(shù)

    驅(qū)動開發(fā):內(nèi)核文件讀寫系列函數(shù)

    在應(yīng)用層下的文件操作只需要調(diào)用微軟應(yīng)用層下的 API 函數(shù)及 C庫 標(biāo)準(zhǔn)函數(shù)即可,而如果在內(nèi)核中讀寫文件則應(yīng)用層的API顯然是無法被使用的,內(nèi)核層需要使用內(nèi)核專有API,某些應(yīng)用層下的API只需要增加Zw開頭即可在內(nèi)核中使用,例如本章要講解的文件與目錄操作相關(guān)函數(shù),多

    2024年02月08日
    瀏覽(23)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包