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

從module_init看內(nèi)核模塊

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

開篇

module_init是linux內(nèi)核提供的一個宏, 可以用來在編寫內(nèi)核模塊時注冊一個初始化函數(shù), 當(dāng)模塊被加載的時候, 內(nèi)核負(fù)責(zé)執(zhí)行這個初始化函數(shù). 在編寫設(shè)備驅(qū)動程序時, 使用這個宏看起來理所應(yīng)當(dāng), 沒什么特別的, 但畢竟我還是一個有點追求的程序員嘛:P, 這篇文章是我學(xué)習(xí)module_init相關(guān)源碼的一個記錄, 主要就回答了下面的3個問題, 篇幅略長, 做好準(zhǔn)備.

問題1

內(nèi)核模塊是什么?

問題2

內(nèi)核模塊是怎么被加載的?

問題3

內(nèi)核怎么獲取到module_init注冊的初始化函數(shù)?

注: 以下回答是個人學(xué)習(xí)總結(jié), 僅供參考.

回答1

編譯好內(nèi)核模塊的代碼, 會得到一個".ko"文件, 這個就是內(nèi)核模塊了. 實際上, ".ko"就是一個普通的ELF文件, 只不過可以使用insmod讓內(nèi)核去動態(tài)加載它. 查閱ELF格式標(biāo)準(zhǔn)可知, 主要有三種類型的ELF文件, 包括:

  • relocatable file
  • excutable file
  • shared object file

以上三種類型的ELF, 基本上可以簡單對應(yīng)編譯得到的".o", "a.out", ".so". 這里討論的".ko"模塊文件, 屬于relocatable file類型, 可以在系統(tǒng)里找一個內(nèi)核模塊文件驗證一下.

junan@ZEN2:/lib/modules/5.19.0-50-generic/kernel/drivers/char$ ls
agp  applicom.ko  hangcheck-timer.ko  hw_random  ipmi  lp.ko  mwave  nvram.ko  pcmcia  ppdev.ko  tlclk.ko  tpm  uv_mmtimer.ko  xillybus
junan@ZEN2:/lib/modules/5.19.0-50-generic/kernel/drivers/char$ file lp.ko 
lp.ko: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), BuildID[sha1]=98c89bd841e31b1140e61559c0bf312eb5128f5c, not stripped

使用gcc編譯一個c文件, 可以得到對應(yīng)的.o文件, 前面說過.o文件屬于relocatable類型的ELF, 如果有多個.o文件, 可以使用鏈接器把它們"合并"成一個.o, 就像這樣:

junan@ZEN2:~$ ls
a.c  a.o  b.c  b.o  Desktop  Documents  Downloads  Music  Pictures  Public  snap  Templates  Videos
junan@ZEN2:~$ file a.o b.o
a.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
b.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
junan@ZEN2:~$ ld -r a.o b.o -o c.o
junan@ZEN2:~$ file c.o
c.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped

經(jīng)過ld鏈接之后, 得到了"c.o", 這個"c.o"相當(dāng)于合并了"a.o"和"b.o", 這可以從它們各自包含的符號中看出來:

junan@ZEN2:~$ nm a.o b.o c.o

a.o:
                 U add
0000000000000000 T call_add

b.o:
0000000000000000 T add

c.o:
000000000000001a T add
0000000000000000 T call_add

同樣的道理, 一個設(shè)備驅(qū)動, 可能包含多個源文件, 但是編譯之后最終可以合并成一個".ko"文件. 總結(jié)下來, ".ko"也是一種普通的ELF文件, 可以被內(nèi)核動態(tài)加載和卸載.

回答2

一個內(nèi)核模塊, 除了自己實現(xiàn)一些功能外, 通常還要引用其他人提供的api, 包括:

  • 內(nèi)核本身提供的api
  • 其他模塊提供的api

內(nèi)核僅僅把".ko"文件讀到自己的地址空間中, 是遠(yuǎn)遠(yuǎn)不夠的, 他要像鏈接器一樣, 幫我們的內(nèi)核模塊正確地處理這些符號引用關(guān)系, 并且調(diào)用我們使用module_init注冊的模塊初始化函數(shù). 下面分析一下這部分的內(nèi)核源碼. 我們的".ko"文件是使用insmod命令才加載進(jìn)內(nèi)核的, insmod命令實際上是一個符號鏈接. 和insmod一樣, rmmod也指向/bin/kmod, 當(dāng)kmod被執(zhí)行的時候, 可以通過args[0]區(qū)分出是執(zhí)行insmod還是rmmod, 或者其他的功能.

junan@ZEN2:~$ which insmod | xargs ls -l
lrwxrwxrwx 1 root root 9  7月 22 23:20 /usr/sbin/insmod -> /bin/kmod

在內(nèi)核代碼中, 專門為模塊的加載和卸載提供了兩個系統(tǒng)調(diào)用, 準(zhǔn)確說是三個, 其中兩個用于加載模塊, 一個用于卸載模塊. linux代碼中使用SYSCALL_DEFINEx這個宏定義一個系統(tǒng)調(diào)用的入口, 其中x代表系統(tǒng)調(diào)用的參數(shù)個數(shù), 看一下內(nèi)核代碼就可以找到和模塊的加載以及卸載相關(guān)的syscall函數(shù), 使用正則表達(dá)式或者其他工具能很快在內(nèi)核代碼中找到這三個系統(tǒng)調(diào)用的定義.

首先是init_module和finit_module:

SYSCALL_DEFINE3(init_module, void __user *, umod,
		unsigned long, len, const char __user *, uargs)
{
    // ...
	return load_module(&info, uargs, 0);
}

SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
{
    // ...
	return load_module(&info, uargs, flags);
}

以上兩個syscall負(fù)責(zé)模塊的加載, 最終都調(diào)用了load_module去真正加載模塊.

然后是delete_module:

SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
		unsigned int, flags)
{
    // ...
}

這三個syscall定義在"kernel/module.c"文件中, 我使用的內(nèi)核版本是5.4.250, 下面可以寫一個什么都不做的內(nèi)核模塊, 通過gdb調(diào)試的方法, 看一下這幾個syscall是怎么被調(diào)用的. 環(huán)境的準(zhǔn)備包括:

  • qemu: 啟動編譯好的內(nèi)核鏡像, 以及gdb server, 等待gdb的連接
  • rootfs: 內(nèi)核正常啟動, 需要一個根文件系統(tǒng), 使用busybox制作
  • kernel Image: 編譯好的內(nèi)核鏡像
  • ko文件: 編譯好的沒有實際功能的內(nèi)核模塊

關(guān)于怎么建立內(nèi)核的調(diào)試環(huán)境, 會在其他文章中說明, 這里僅通過調(diào)試內(nèi)核的方法, 記錄一下以上三個syscall的調(diào)用過程. 當(dāng)你還不知道insmod和rmmod需要使用到這三個系統(tǒng)調(diào)用, 怎么樣才能知道這兩個命令依賴什么系統(tǒng)調(diào)用呢? 答案是可以使用strace去定位一個進(jìn)程運行過程中用到了哪些syscall, 比如, 我的系統(tǒng)里有一個名字叫做lp的ko模塊:

junan@ZEN:~$ lsmod | grep lp
lp                     28672  0
drm_display_helper    184320  1 i915
cec                    81920  2 drm_display_helper,i915
drm_kms_helper        200704  2 drm_display_helper,i915

先把這個模塊卸載, 看看使用了什么syscall:

junan@ZEN:~$ sudo strace rmmod lp
...
...
close(3)                                = 0
openat(AT_FDCWD, "/sys/module/lp/refcnt", O_RDONLY|O_CLOEXEC) = 3
read(3, "0\n", 31)                      = 2
read(3, "", 29)                         = 0
close(3)                                = 0
delete_module("lp", O_NONBLOCK)         = 0
exit_group(0)                           = ?
+++ exited with 0 +++

能看到倒數(shù)第3行, 調(diào)用了delete_module.

再重新加載這個lp模塊:

junan@ZEN:/usr/lib/modules/5.19.0-50-generic/kernel/drivers/char$ sudo strace insmod lp.ko
...
...
getcwd("/usr/lib/modules/5.19.0-50-generic/kernel/drivers/char", 4096) = 55
newfstatat(AT_FDCWD, "/usr/lib/modules/5.19.0-50-generic/kernel/drivers/char/lp.ko", {st_mode=S_IFREG|0644, st_size=72553, ...}, 0) = 0
openat(AT_FDCWD, "/usr/lib/modules/5.19.0-50-generic/kernel/drivers/char/lp.ko", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1", 6)               = 6
lseek(3, 0, SEEK_SET)                   = 0
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=72553, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 72553, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f4675dac000
finit_module(3, "", 0)                  = 0
munmap(0x7f4675dac000, 72553)           = 0
close(3)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++

倒數(shù)第5行, finit_module被調(diào)用, 用來加載lp模塊. 使用這種方式, 先分析一下執(zhí)行過程, 能夠幫助你大致確定它是怎么實現(xiàn)的. 接下來開始調(diào)試內(nèi)核, 看一下syscall的調(diào)用過程:

以下是對視頻中調(diào)試過程的詳細(xì)記錄:

  1. 使用qemu加載了一個編譯好的內(nèi)核鏡像.

    • 使用arm平臺
    • 掛載本機(jī)目錄到qemu虛擬機(jī), 目錄下包含一個等待測試的ko模塊
    • 開啟調(diào)試選項, qemu啟動之后等待外部gdb的連接
  2. 啟動vscode遠(yuǎn)程調(diào)試的配置, 開始調(diào)試內(nèi)核代碼

    • 先關(guān)閉所有斷點, 加載和卸載testko模塊, 得到正確的輸出
    • 之后開啟斷點, 分別break在init_module和finit_module兩個syscall上
  3. 重新插入testko模塊

    • init_module系統(tǒng)調(diào)用上的斷點命中
    • 調(diào)用load_module函數(shù)
      • 加載模塊到內(nèi)核
      • 完成鏈接, 處理符號的引用關(guān)系
      • 調(diào)用testko注冊的初始化函數(shù), 得到初始化函數(shù)的輸出

所以, 內(nèi)核模塊在加載時, 需要使用init_module/finit_module系統(tǒng)調(diào)用, 經(jīng)syscall進(jìn)入內(nèi)核之后, 內(nèi)核會把我們的模塊加載到自己的地址空間中, 然后完成原本鏈接器需要做的工作, 這時, 模塊中引用的其他符號, 已經(jīng)得到了真實的地址, 在模塊加載的最后階段, 內(nèi)核調(diào)用do_one_initcall去調(diào)用我們注冊的模塊初始化函數(shù). 以上就是內(nèi)核模塊加載的基本過程, 模塊卸載的過程類似.

回答3

先找到module_init宏的實現(xiàn)代碼, 在include/linux/module.h文件中, 能找到這個宏的定義:

#ifndef MODULE
/**
 * module_init() - driver initialization entry point
 * @x: function to be run at kernel boot time or module insertion
 *
 * module_init() will either be called during do_initcalls() (if
 * builtin) or at module insertion time (if a module).  There can only
 * be one per module.
 */
#define module_init(x)	__initcall(x);

/**
 * module_exit() - driver exit entry point
 * @x: function to be run when driver is removed
 *
 * module_exit() will wrap the driver clean-up code
 * with cleanup_module() when used with rmmod when
 * the driver is a module.  If the driver is statically
 * compiled into the kernel, module_exit() has no effect.
 * There can only be one per module.
 */
#define module_exit(x)	__exitcall(x);

#else /* MODULE */

/*
 * In most cases loadable modules do not need custom
 * initcall levels. There are still some valid cases where
 * a driver may be needed early if built in, and does not
 * matter when built as a loadable module. Like bus
 * snooping debug drivers.
 */
#define early_initcall(fn)		module_init(fn)
#define core_initcall(fn)		module_init(fn)
#define core_initcall_sync(fn)		module_init(fn)
#define postcore_initcall(fn)		module_init(fn)
#define postcore_initcall_sync(fn)	module_init(fn)
#define arch_initcall(fn)		module_init(fn)
#define subsys_initcall(fn)		module_init(fn)
#define subsys_initcall_sync(fn)	module_init(fn)
#define fs_initcall(fn)			module_init(fn)
#define fs_initcall_sync(fn)		module_init(fn)
#define rootfs_initcall(fn)		module_init(fn)
#define device_initcall(fn)		module_init(fn)
#define device_initcall_sync(fn)	module_init(fn)
#define late_initcall(fn)		module_init(fn)
#define late_initcall_sync(fn)		module_init(fn)

#define console_initcall(fn)		module_init(fn)

/* Each module must use one module_init(). */
#define module_init(initfn)					\
	static inline initcall_t __maybe_unused __inittest(void)		\
	{ return initfn; }					\
	int init_module(void) __copy(initfn) __attribute__((alias(#initfn)));

/* This is only required if you want to be unloadable. */
#define module_exit(exitfn)					\
	static inline exitcall_t __maybe_unused __exittest(void)		\
	{ return exitfn; }					\
	void cleanup_module(void) __copy(exitfn) __attribute__((alias(#exitfn)));

#endif

可以看到根據(jù)是否定義了MODULE, module_init有兩個不同的實現(xiàn), 對于驅(qū)動程序的內(nèi)核模塊來說, 走到的是#else分支的定義, 這一點能夠從編譯ko時詳細(xì)的編譯命令中確認(rèn):

junan@ZEN:~/Documents/github/blogcodes/01-testko$ ARCH=$ARCH CROSS_COMPILE=$CROSS_COMPILE KDIR=$KDIR make -nB V=1
...
arm-linux-gnueabihf-gcc -Wp,-MD,/home/junan/Documents/github/blogcodes/01-testko/.testko.o.d -nostdinc -isystem /usr/lib/gcc-cross/arm-linux-gnueabihf/11/include -I../arch/arm/include -I./arch/arm/include/generated -I../include -I./include -I../arch/arm/include/uapi -I./arch/arm/include/generated/uapi -I../include/uapi -I./include/generated/uapi -include ../include/linux/kconfig.h -include ../include/linux/compiler_types.h -D__KERNEL__ -mlittle-endian -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -fno-PIE -Werror=implicit-function-declaration -Werror=implicit-int -Werror=return-type -Wno-format-security -std=gnu89 -fno-dwarf2-cfi-asm -fno-ipa-sra -mabi=aapcs-linux -mfpu=vfp -funwind-tables -marm -Wa,-mno-warn-deprecated -D__LINUX_ARM_ARCH__=7 -march=armv7-a -msoft-float -Uarm -fno-delete-null-pointer-checks -Wno-frame-address -Wno-format-truncation -Wno-format-overflow -Wno-address-of-packed-member -O2 -fno-allow-store-data-races -Wframe-larger-than=1024 -fstack-protector-strong -Wimplicit-fallthrough -Wno-unused-but-set-variable -Wno-unused-const-variable -fomit-frame-pointer -fno-var-tracking-assignments -g -gdwarf-4 -Wdeclaration-after-statement -Wvla -Wno-pointer-sign -Wno-stringop-truncation -Wno-zero-length-bounds -Wno-array-bounds -Wno-stringop-overflow -Wno-restrict -Wno-maybe-uninitialized -fno-strict-overflow -fno-merge-all-constants -fmerge-constants -fno-stack-check -fconserve-stack -Werror=date-time -Werror=incompatible-pointer-types -Werror=designated-init -fmacro-prefix-map=../= -Wno-packed-not-aligned  -DMODULE  -DKBUILD_BASENAME='\''"testko"'\'' -DKBUILD_MODNAME='\''"testko"'\'' -c -o /home/junan/Documents/github/blogcodes/01-testko/testko.o /home/junan/Documents/github/blogcodes/01-testko/testko.c
...

從上面截取的編譯命令中, 應(yīng)該能找到"-DMODULE", 雖然有點多, 但仔細(xì)看還是能找到的哈, 實在沒看到可以Ctrl+F搜索一下. gcc的-D參數(shù)相當(dāng)于幫你在代碼里#define了一個宏, 所以, 在包含module.h頭文件時, module_init確實會走到#else那個分支, 在這個分支里, module_init定義了一個static inline的函數(shù), 并且, 聲明了一個名字叫做init_module的函數(shù), 千萬不要把這個函數(shù)名和之前視頻里調(diào)試的syscall名字搞混了:

int init_module(void) __copy(initfn) __attribute__((alias(#initfn)));

注意, 這個函數(shù)帶了一個alias屬性(詳細(xì)介紹, 參考官方文檔), 這樣init_module函數(shù)就變成了我們傳遞進(jìn)來的initfn函數(shù)的別名, 也就是說如果調(diào)用init_module, 實際上會調(diào)用initfn. 接下來的問題是, 加載模塊的時候, 內(nèi)核如何能夠得到模塊初始化函數(shù)的地址呢? 你如果自己編譯一個內(nèi)核模塊代碼, 會發(fā)現(xiàn)編譯完成之后, 除了".ko"還會生成很多其他東西, 比如: xxx.mod.c, 內(nèi)核的構(gòu)建系統(tǒng)給你生成了一個c文件, 看一下里面的內(nèi)容:

junan@ZEN:~/Documents/github/blogcodes/01-testko$ cat testko.mod.c
#include <linux/build-salt.h>
#include <linux/module.h>
#include <linux/vermagic.h>
#include <linux/compiler.h>

BUILD_SALT;

MODULE_INFO(vermagic, VERMAGIC_STRING);
MODULE_INFO(name, KBUILD_MODNAME);

__visible struct module __this_module
__section(.gnu.linkonce.this_module) = {
        .name = KBUILD_MODNAME,
        .init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
        .exit = cleanup_module,
#endif
        .arch = MODULE_ARCH_INIT,
};

#ifdef CONFIG_RETPOLINE
MODULE_INFO(retpoline, "Y");
#endif

MODULE_INFO(depends, "");

這個文件中定義了一個struct module類型的變量__this_module, 并且.init成員已經(jīng)被填上了模塊初始化函數(shù)的并名"init_module", .exit成員也是這樣. 這樣當(dāng)內(nèi)核把模塊載入自己的地址空間, 完成鏈接器的工作之后, 這個.init字段就指向真實的模塊初始化函數(shù)地址了, 之前的調(diào)試視頻里可以看到有這樣的判斷:

...
if(mod->init != NULL)
    ret = do_one_initcall(mod->init);
...

這里的"mod"是一個struct module*, 它實際上就是xxx.mod.c中的__this_module, 看一下代碼:

static struct module *layout_and_allocate(struct load_info *info, int flags)
{
	struct module *mod;
	unsigned int ndx;
	int err;

	...

    /* Determine total sizes, and put offsets in sh_entsize.  For now
	   this is done generically; there doesn't appear to be any
	   special cases for the architectures. */
	layout_sections(info->mod, info);
	layout_symtab(info->mod, info);

	/* Allocate and move to the final place */
	err = move_module(info->mod, info);
	if (err)
		return ERR_PTR(err);

	/* Module has been copied to its final place now: return it. */
	mod = (void *)info->sechdrs[info->index.mod].sh_addr;
	kmemleak_load_module(mod, info);
	return mod;
}

總結(jié)下來, 關(guān)于內(nèi)核怎么獲取到我們注冊的初始化函數(shù)這個問題:

  • 實現(xiàn)模塊初始化函數(shù)
  • 使用module_init宏傳遞上述初始化函數(shù)
    • 這個宏會聲明一個名字叫做"init_module"的函數(shù), 這個函數(shù)是真實的模塊初始化函數(shù)的別名
  • 編譯模塊時, 內(nèi)核的構(gòu)建系統(tǒng)生成xxx.mod.c文件, 在這個文件里
    • 定義一個struct module類型的變量, __this_module
    • 用"init_module"填充.init成員
    • 順便說一下, THIS_MODULE宏實際上就會展開成__this_module
  • 內(nèi)核載入模塊
    • 做一些鏈接器的工作(這個地方實際上有點復(fù)雜, 之后有需要可以仔細(xì)研究, 暫時就理解為內(nèi)核幫你把引用的一些符號的地址都算好了, 并在引用的地方填上正確的值)
    • 獲取到__this_module的地址, 判斷.init成員是否為空, 不為空就調(diào)用模塊初始化函數(shù)

注: 當(dāng)module_init宏的定義走到第一個分支時, 之后再寫一篇討論一下.


結(jié)尾

這篇文章主要討論了3個問題:

  1. 內(nèi)核模塊是什么?
  2. 模塊是怎么被內(nèi)核加載的?
  3. 內(nèi)核是怎么找到模塊初始化函數(shù)的?

讀完之后, 你應(yīng)該對這3個問題有了自己的體會. 除此之外, 你還應(yīng)該解到一些的技術(shù), 它們能夠幫你找到一些問題的答案:

  1. strace跟蹤系統(tǒng)調(diào)用
  2. 使用qemu+gdb調(diào)試內(nèi)核源碼
  3. gcc的一些擴(kuò)展語法, 比如給函數(shù)或者變量加屬性

第1點, 比較簡單, 就是一個命令的使用問題, 但是背后的原理應(yīng)該不簡單;

第2點, 是一個環(huán)境搭建的問題, 有時間可以發(fā)個視頻詳細(xì)介紹一下;

第3點, 讀源碼的過程中碰到了, 不懂的話查一下官方手冊, 寫一點代碼驗證一下, 就知道怎么用了. 實際上, 除了attribute, 還有很多方式能夠告訴編譯器, 你要做什么.


建了個QQ群: 838923389. 有想法的老鐵可以加一下, 一起交流linux內(nèi)核的使用和學(xué)習(xí)經(jīng)驗. 后續(xù)也會在b站發(fā)一些技術(shù)視頻, 老鐵們覺得有需要可以先關(guān)注一下, 視頻和文章肯定會給各位帶來一些啟發(fā)和幫助.文章來源地址http://www.zghlxwxcb.cn/news/detail-622503.html

到了這里,關(guān)于從module_init看內(nèi)核模塊的文章就介紹完了。如果您還想了解更多內(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ù)器費用

相關(guān)文章

  • Linux內(nèi)核學(xué)習(xí)(十三)—— 設(shè)備與模塊(基于Linux 2.6內(nèi)核)

    目錄 一、設(shè)備類型 二、模塊 構(gòu)建模塊 安裝模塊 載入模塊 在 Linux 以及 Unix 系統(tǒng)中,設(shè)備被分為以下三種類型: 塊設(shè)備(blkdev) :以塊為尋址單位,塊的大小隨設(shè)備的不同而變化;塊設(shè)備通常支持重定位(seeking)操作,也就是對數(shù)據(jù)的隨機(jī)訪問。如硬盤、藍(lán)光光碟和 Flas

    2024年02月11日
    瀏覽(90)
  • linux驅(qū)動開發(fā)--day1(驅(qū)動、內(nèi)核模塊及相關(guān)命令、內(nèi)核模塊傳參)
  • Linux驅(qū)動開發(fā)——內(nèi)核模塊

    Linux驅(qū)動開發(fā)——內(nèi)核模塊

    目錄 內(nèi)核模塊的由來 第一個內(nèi)核模塊程序? 內(nèi)核模塊工具? 將多個源文件編譯生成一個內(nèi)核模塊? 內(nèi)核模塊參數(shù) 內(nèi)核模塊依賴 關(guān)于內(nèi)核模塊的進(jìn)一步討論? 習(xí)題 最近一直在玩那些其它的技術(shù),眼看快暑假了,我決定夯實一下我的驅(qū)動方面的技能,迎接我的實習(xí),找了一本

    2024年02月04日
    瀏覽(100)
  • 【嵌入式Linux內(nèi)核驅(qū)動】內(nèi)核模塊三要素與驗證測試

    內(nèi)核模塊 Linux內(nèi)核模塊是一種可以動態(tài)加載和卸載的軟件組件,用于擴(kuò)展Linux操作系統(tǒng)的功能。Linux內(nèi)核本身只包含了必要的核心功能,而內(nèi)核模塊則允許開發(fā)者在運行時向內(nèi)核添加新的功能、驅(qū)動程序或文件系統(tǒng)支持,而無需重新編譯整個內(nèi)核或重新啟動系統(tǒng)。 內(nèi)核模塊是

    2024年02月06日
    瀏覽(134)
  • 如何將模塊加載到linux內(nèi)核

    如何將模塊加載到linux內(nèi)核

    假設(shè)存在一個文件叫mymq.c,下該文件相同目錄下的makefile如下語句: obj-y += mymq.o 然后編譯:編譯完成了以后,mymq.c文件中,有個函數(shù)叫mymq_open,搜索這個函數(shù)在不在System.map文件中,如果在,就說明這個模塊被內(nèi)置到內(nèi)核中了。 執(zhí)行g(shù)rep -rn mymq_open System.map,在文件System.map中搜索

    2023年04月24日
    瀏覽(91)
  • Linux 內(nèi)核模塊加載過程之重定位

    1.1.1 struct load_info info 加載模塊只需要讀入模塊的二進(jìn)制代碼即可,然后執(zhí)行init_module系統(tǒng)調(diào)用。 我們先介紹下struct load_info info結(jié)構(gòu)體。 struct load_info 是一個用于加載模塊時存儲相關(guān)信息的數(shù)據(jù)結(jié)構(gòu)。 該結(jié)構(gòu)體包含以下成員: name:模塊的名稱,以字符串形式存儲。 mod:指向

    2024年02月10日
    瀏覽(645)
  • 修改linux的/sys目錄下內(nèi)核參數(shù)、模塊...

    ① /sys/devices 該目錄下是全局設(shè)備結(jié)構(gòu)體系,包含所有被發(fā)現(xiàn)的注冊在各種總線上的各種物理設(shè)備。一般來說,所有的物理設(shè)備都按其在總線上的拓?fù)浣Y(jié)構(gòu)來顯示,但有兩個例外,即platform devices和system devices。platform devices一般是掛在芯片內(nèi)部的高速或者低速總線上的各種控制

    2024年02月05日
    瀏覽(92)
  • Linux 編譯內(nèi)核模塊出現(xiàn)--Unknown symbol mcount

    Linux suse: 在編譯SUSE Linux Enterprise Server 12 SP時,使用低版本的docker鏡像編譯內(nèi)核模塊時,加載內(nèi)核模塊時出現(xiàn): 加載內(nèi)核模塊時: (1) 指示系統(tǒng)可能受到 Spectre V2 漏洞的影響,并且正在加載的模塊沒有使用 retpoline 編譯器進(jìn)行編譯。 Spectre V2(CVE-2017-5715)是 Spectre 漏洞家族

    2024年02月11日
    瀏覽(87)
  • Linux學(xué)習(xí)之Ubuntu 20.04安裝內(nèi)核模塊

    Linux學(xué)習(xí)之Ubuntu 20.04安裝內(nèi)核模塊

    參考博客:Ubuntu20.04編譯內(nèi)核教程 sudo lsb_release -a 可以看到我當(dāng)前的系統(tǒng)是 Ubuntu 20.04.4 , sudo uname -r 可以看到我的系統(tǒng)內(nèi)核版本是 5.4.0-100-generic 。 sudo apt-get install -y libncurses5-dev flex bison libssl-dev 安裝所需要的依賴。 sudo apt-get install linux-source 按兩下 Tab ,看一下可以下載的源

    2024年02月15日
    瀏覽(127)
  • Linux內(nèi)核模塊vmalloc和kmalloc系統(tǒng)調(diào)用的代碼實戰(zhàn)

    Linux內(nèi)核模塊vmalloc和kmalloc系統(tǒng)調(diào)用的代碼實戰(zhàn)

    當(dāng)設(shè)備長時間運行后,內(nèi)存碎片化,很難找到連續(xù)的物理頁。在這種情況下,如果需要分配長度超過一頁的內(nèi)存塊,可以使用不連續(xù)頁分配器,分配虛擬地址連續(xù)但是物理地址不連續(xù)的內(nèi)存塊。在 32 位系統(tǒng)中不連分配器還有一個好處:優(yōu)先從高端內(nèi)存區(qū)域分配頁,保留稀缺的

    2023年04月16日
    瀏覽(19)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包