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

第三十一章 linux-模塊的加載過程一

這篇具有很好參考價值的文章主要介紹了第三十一章 linux-模塊的加載過程一。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

模塊的加載過程一



ps:kernel symbol內(nèi)核符號表,就是在內(nèi)核的內(nèi)部函數(shù)或變量中,可供外部引用的函數(shù)和變量的符號表。. 其實說白了就是一個索引文件,它存在的目的就是讓外部軟件可以知道kernel文件內(nèi)部實際分配的位置。

先來個圖:

第三十一章 linux-模塊的加載過程一

在用戶空間,用insmod這樣的命令來向內(nèi)核空間安裝一個內(nèi)核模塊,本節(jié)將詳細(xì)討論模塊加載時的內(nèi)核行為。當(dāng)調(diào)用“insmod demodev.ko”來安裝demodev.ko這樣的內(nèi)核模塊時,insmod會首先利用文件系統(tǒng)的接口將其數(shù)據(jù)讀取到用戶空間的一段內(nèi)存中,然后通過系統(tǒng)調(diào)用sys_init_module讓內(nèi)核去處理模塊加載的整個過程。

sys_init_module

原型:

asmlinkage long sys_init_module(void __user *umod, unsigned long len,
				const char __user *uargs);

其中,第一參數(shù)umod是指向用戶空間demodev.ko文件映像數(shù)據(jù)的內(nèi)存地址,第二參數(shù)len是該文件的數(shù)據(jù)大小,第三參數(shù)是傳給模塊的參數(shù)在用戶空間下的內(nèi)存地址。

sys_init_module實現(xiàn)
SYSCALL_DEFINE3宏定義

#define SYSCALL_DEFINEx(x, sname, ...)				\
	SYSCALL_METADATA(sname, x, __VA_ARGS__)			\
	__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)

#define __PROTECT(...) asmlinkage_protect(__VA_ARGS__)
#define __SYSCALL_DEFINEx(x, name, ...)					\
	asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))	\
		__attribute__((alias(__stringify(SyS##name))));		\
	static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__));	\
	asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__));	\
	asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__))	\
	{								\
		long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__));	\
		__MAP(x,__SC_TEST,__VA_ARGS__);				\
		__PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));	\
		return ret;						\
	}								\
	static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))
SYSCALL_DEFINE3(finit_module, int, fd, const char __user *, uargs, int, flags)
{
	int err;
	struct load_info info = { };

	err = may_init_module();//確定具有加載或去除內(nèi)核模塊的能力 并是否使能modules
	if (err)
		return err;

	pr_debug("finit_module: fd=%d, uargs=%p, flags=%i\n", fd, uargs, flags);

	if (flags & ~(MODULE_INIT_IGNORE_MODVERSIONS
		      |MODULE_INIT_IGNORE_VERMAGIC))
		return -EINVAL;

	err = copy_module_from_fd(fd, &info);//copy_module_from_fd () 將打開的模塊文件讀到申請的內(nèi)核內(nèi)存中,并交由 load_module () 處理。
	if (err)
		return err;

	return load_module(&info, uargs, flags);
}

在sys_init_module函數(shù)中,加載模塊的任務(wù)主要是通過調(diào)load_module函數(shù)來完成的,該函數(shù)的定義為:

/* Allocate and load the module: note that size of section 0 is always
   zero, and we rely on this for optional sections. */
//二進制數(shù)據(jù)使用load_module傳輸?shù)絻?nèi)核地址空間中,鎖有需要的重定位都會完成,所有iny都會解決
//在load_module中創(chuàng)建module實例已近添加到全局的modues鏈表后,內(nèi)核內(nèi)需要調(diào)用模塊的初始化函數(shù)并釋放
//初始化數(shù)據(jù)占用的內(nèi)存空間

static int load_module(struct load_info *info, const char __user *uargs,
		       int flags)
{
	struct module *mod;
	long err;
	char *after_dashes;

	err = module_sig_check(info);//module_sig_check () 需要開啟 
	//CONFIG_MODULE_SIG 才會起作用
	if (err)
		goto free_copy;

	err = elf_header_check(info);//主要是檢查一下 ELF 文件頭信息,別忘了模塊文
	//件.ko 是 ELF relocatable 文件,所以需要檢查一下是否是正確的 ELF 文件格
	//式。
	if (err)
		goto free_copy;

	/* Figure out module layout, and allocate all the memory. */
	mod = layout_and_allocate(info, flags);//獲取模塊的布局,重新申請一次內(nèi)存
	//,并對相關(guān)section對內(nèi)容進行修改
	if (IS_ERR(mod)) {
		err = PTR_ERR(mod);
		goto free_copy;
	}

	/* Reserve our place in the list. */
	err = add_unformed_module(mod);//將模塊加入到內(nèi)核的模塊鏈表中。
	if (err)
		goto free_module;

#ifdef CONFIG_MODULE_SIG
	mod->sig_ok = info->sig_ok;
	if (!mod->sig_ok) {
		pr_notice_once("%s: module verification failed: signature "
			       "and/or required key missing - tainting "
			       "kernel\n", mod->name);
		add_taint_module(mod, TAINT_UNSIGNED_MODULE, LOCKDEP_STILL_OK);
	}
#endif

	/* To avoid stressing percpu allocator, do this once we're unique. */
	err = percpu_modalloc(mod, info);//對模塊里面的percpu進行特殊的內(nèi)存申請,
	//這個percpu變量比較特殊,在每個CPU上都存在一份,所以用特殊的申請內(nèi)存函數(shù)
	//去處理
	if (err)
		goto unlink_mod;

	/* Now module is in final location, initialize linked lists, etc. */
	err = module_unload_init(mod);//為后續(xù)執(zhí)行rmmod卸載命令時初始化一些引用變
	//量以及鏈表等。
	if (err)
		goto unlink_mod;

	/* Now we've got everything in the final locations, we can
	 * find optional sections. */
	err = find_module_sections(mod, info);//找模塊里面的一些section,
	//比如參數(shù)的__param節(jié),內(nèi)核符號表__ksymtab節(jié),GPL范圍協(xié)議的符號
	//__ksymtab_gpl節(jié),ftrace增加的_ftrace_events節(jié)等待。
	if (err)
		goto free_unload;

	err = check_module_license_and_versions(mod);
	//主要是檢查模塊的license是否存在污染內(nèi)核的可能
	if (err)
		goto free_unload;

	/* Set up MODINFO_ATTR fields */
	setup_modinfo(mod, info);//對sys屬性進行一些預(yù)先setup處理。

	/* Fix up syms, so that st_value is a pointer to location. */
	err = simplify_symbols(mod, info);//修復(fù)加載模塊的符號,使符號指向內(nèi)核正確的運行地址。
	if (err < 0)
		goto free_modinfo;

	err = apply_relocations(mod, info);//是對.rel節(jié)和.rela節(jié)進行重定位的一個過程。
	if (err < 0)
		goto free_modinfo;

	err = post_relocation(mod, info);//對重定位后的percpu變量重新賦值,并將即
	//將加載完成的模塊的符號加入到內(nèi)核模塊的符號鏈表中,如果成功加載此模塊且
	//內(nèi)核配置了CONFIG_KALLSYMS,那么在/proc/kallsyms下可以看到此模塊的符號


	if (err < 0)
		goto free_modinfo;

	flush_module_icache(mod);//執(zhí)行刷新模塊的init_layout和core_layout的cache。

	/* Now copy in args */
	mod->args = strndup_user(uargs, ~0UL >> 1);//復(fù)制一下模塊的參數(shù)
	if (IS_ERR(mod->args)) {
		err = PTR_ERR(mod->args);
		goto free_arch_cleanup;
	}

	dynamic_debug_setup(info->debug, info->num_debug);//需要開啟內(nèi)核CONFIG_DYNAMIC_DEBUG才會啟用

	/* Ftrace init must be called in the MODULE_STATE_UNFORMED state */
	ftrace_module_init(mod);//需要開啟相關(guān)的ftrace配置

	/* Finally it's fully formed, ready to start executing. */
	err = complete_formation(mod, info);//對模塊的內(nèi)存屬性進行修改,比如.text的讀+執(zhí)行,.data的讀寫屬性。
	if (err)
		goto ddebug_cleanup;

	/* Module is ready to execute: parsing args may do that. */
	after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
				  -32768, 32767, unknown_module_param_cb);//解析模塊參數(shù)
	if (IS_ERR(after_dashes)) {
		err = PTR_ERR(after_dashes);
		goto bug_cleanup;
	} else if (after_dashes) {
		pr_warn("%s: parameters '%s' after `--' ignored\n",
		       mod->name, after_dashes);
	}

	/* Link in to syfs. */
	err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp);//對sys進行創(chuàng)建的過程
	if (err < 0)
		goto bug_cleanup;

	/* Get rid of temporary copy. */
	free_copy(info);//釋放最初內(nèi)核申請的用于保存模塊原文件信息的內(nèi)存

	/* Done! */
	trace_module_load(mod);//trace相關(guān)的

	return do_init_module(mod);//最后模塊執(zhí)行init函數(shù)的過程

 bug_cleanup:
	/* module_bug_cleanup needs module_mutex protection */
	mutex_lock(&module_mutex);
	module_bug_cleanup(mod);
	mutex_unlock(&module_mutex);

	blocking_notifier_call_chain(&module_notify_list,
				     MODULE_STATE_GOING, mod);

	/* we can't deallocate the module until we clear memory protection */
	unset_module_init_ro_nx(mod);
	unset_module_core_ro_nx(mod);

 ddebug_cleanup:
	dynamic_debug_remove(info->debug);
	synchronize_sched();
	kfree(mod->args);
 free_arch_cleanup:
	module_arch_cleanup(mod);
 free_modinfo:
	free_modinfo(mod);
 free_unload:
	module_unload_free(mod);
 unlink_mod:
	mutex_lock(&module_mutex);
	/* Unlink carefully: kallsyms could be walking list. */
	list_del_rcu(&mod->list);
	wake_up_all(&module_wq);
	/* Wait for RCU synchronizing before releasing mod->list. */
	synchronize_rcu();
	mutex_unlock(&module_mutex);
 free_module:
	/* Free lock-classes; relies on the preceding sync_rcu() */
	lockdep_free_key_range(mod->module_core, mod->core_size);

	module_deallocate(mod, info);
 free_copy:
	free_copy(info);
	return err;
}

所有參數(shù)同sys_init_module函數(shù)中的完全一樣,實際上在sys_init_module函數(shù)的一開始便會調(diào)用該函數(shù),調(diào)用時傳入的實參完全來自于sys_init_module函數(shù),沒有經(jīng)過任何的處理或者修改。

為了更清楚地解釋模塊加載時的內(nèi)核行為,我們把sys_init_module分為兩個部分:第一部分是調(diào)用load_module,完成模塊加載最核心的任務(wù):第二部分是在模塊被成功加載到系統(tǒng)之后的后續(xù)處理。我們將在討論完load_module部分之后再繼續(xù)討論sys_init_module的第二部分。不過,在繼續(xù)load_module話題之前,先要看一個內(nèi)核中非常重要的數(shù)據(jù)結(jié)構(gòu)—------struct module。

struct module

load module函數(shù)的返回值是一個struct module類型的指針,struct module是內(nèi)核用來管理系統(tǒng)中加載的模塊時使用的一個非常重要的數(shù)據(jù)結(jié)構(gòu),一個struct module對象代表著現(xiàn)實中一個內(nèi)核模塊在Linux系統(tǒng)中的抽象,該結(jié)構(gòu)的定義如下〈刪除了一些trace和unused symbol相關(guān)的部分):

struct module {
	enum module_state state;//模塊的狀態(tài)

	/* Member of list of modules */
	struct list_head list;//用作模塊鏈表的鏈表元素

	/* Unique handle for this module */
	char name[MODULE_NAME_LEN];//該模塊唯一的句柄,模塊名稱

	/* Sysfs stuff. */
	//導(dǎo)出符號
	struct module_kobject mkobj;
	struct module_attribute *modinfo_attrs;
	const char *version;
	const char *srcversion;
	struct kobject *holders_dir;

	/* Exported symbols */
	const struct kernel_symbol *syms;
	const unsigned long *crcs;//內(nèi)核模塊導(dǎo)出符號的校驗碼所在起始地址。
	unsigned int num_syms;

	/* Kernel parameters. */
	struct kernel_param *kp;//內(nèi)核模塊參數(shù)所在的起始地址。
	unsigned int num_kp;

	/* GPL-only exported symbols. */
	//只適用于GPL的導(dǎo)出符號
	unsigned int num_gpl_syms;
	const struct kernel_symbol *gpl_syms;
	const unsigned long *gpl_crcs;

#ifdef CONFIG_UNUSED_SYMBOLS
	/* unused exported symbols. */
	const struct kernel_symbol *unused_syms;
	const unsigned long *unused_crcs;
	unsigned int num_unused_syms;

	/* GPL-only, unused exported symbols. */
	unsigned int num_unused_gpl_syms;
	const struct kernel_symbol *unused_gpl_syms;
	const unsigned long *unused_gpl_crcs;
#endif

#ifdef CONFIG_MODULE_SIG
	/* Signature was verified. */
	bool sig_ok;
#endif

	/* symbols that will be GPL-only in the near future. */
	const struct kernel_symbol *gpl_future_syms;
	const unsigned long *gpl_future_crcs;
	unsigned int num_gpl_future_syms;

	/* Exception table */
	//異常表
	unsigned int num_exentries;
	struct exception_table_entry *extable;

	/* Startup function. */
	//初始化函數(shù)
	int (*init)(void);//init是一個指針,指向一個在模塊初始化時調(diào)用的函數(shù)
	//指向內(nèi)核模塊初始化函數(shù)的指針,在內(nèi)核模塊源碼中由module init宏指定。
	/* If this is non-NULL, vfree after init() returns */
	void *module_init;

	/* Here is the actual code + data, vfree'd on unload. */
	void *module_core;

	/* Here are the sizes of the init and core sections */
	unsigned int init_size, core_size;

	/* The size of the executable code in each section.  */
	unsigned int init_text_size, core_text_size;

	/* Size of RO sections of the module (text+rodata) */
	unsigned int init_ro_size, core_ro_size;

	/* Arch-specific module values */
	struct mod_arch_specific arch;

	unsigned int taints;	/* same bits as kernel:tainted */

#ifdef CONFIG_GENERIC_BUG
	/* Support for BUG */
	unsigned num_bugs;
	struct list_head bug_list;
	struct bug_entry *bug_table;
#endif

#ifdef CONFIG_KALLSYMS
	/*
	 * We keep the symbol and string tables for kallsyms.
	 * The core_* fields below are temporary, loader-only (they
	 * could really be discarded after module init).
	 */
	Elf_Sym *symtab, *core_symtab;
	unsigned int num_symtab, core_num_syms;
	char *strtab, *core_strtab;

	/* Section attributes */
	struct module_sect_attrs *sect_attrs;

	/* Notes attributes */
	struct module_notes_attrs *notes_attrs;
#endif

	/* The command line arguments (may be mangled).  People like
	   keeping pointers to this stuff */
	char *args;

#ifdef CONFIG_SMP
	/* Per-cpu data. */
	void __percpu *percpu;
	unsigned int percpu_size;
#endif

#ifdef CONFIG_TRACEPOINTS
	unsigned int num_tracepoints;
	struct tracepoint * const *tracepoints_ptrs;
#endif
#ifdef HAVE_JUMP_LABEL
	struct jump_entry *jump_entries;
	unsigned int num_jump_entries;
#endif
#ifdef CONFIG_TRACING
	unsigned int num_trace_bprintk_fmt;
	const char **trace_bprintk_fmt_start;
#endif
#ifdef CONFIG_EVENT_TRACING
	struct ftrace_event_call **trace_events;
	unsigned int num_trace_events;
	struct trace_enum_map **trace_enums;
	unsigned int num_trace_enums;
#endif
#ifdef CONFIG_FTRACE_MCOUNT_RECORD
	unsigned int num_ftrace_callsites;
	unsigned long *ftrace_callsites;
#endif

#ifdef CONFIG_LIVEPATCH
	bool klp_alive;
#endif

#ifdef CONFIG_MODULE_UNLOAD
//用來在內(nèi)核模塊間建立依賴關(guān)系。
	/* What modules depend on me? */
	struct list_head source_list;
	/* What modules do I depend on? */
	struct list_head target_list;

	/* Destruction function. */
	void (*exit)(void);

	atomic_t refcnt;
#endif

#ifdef CONFIG_CONSTRUCTORS
	/* Constructor functions. */
	ctor_fn_t *ctors;
	unsigned int num_ctors;
#endif
};

load_module

作為內(nèi)核模塊加載器中最核心的函數(shù),load_module負(fù)責(zé)最艱苦的模塊加載全過程。我們將仔細(xì)討論該函數(shù),因為除了可以了解內(nèi)核模塊加載的幕后機制之外,還能了解到一些非常有趣的特性,諸如內(nèi)核模塊如何調(diào)用內(nèi)核代碼導(dǎo)出的函數(shù),被加載的模塊如何向系統(tǒng)中其他的模塊導(dǎo)出自己的符號,以及模塊如何接收外部的參數(shù)等。在介紹這部分內(nèi)容時,如果完全按照內(nèi)核代碼的順序依序進行的話,邏輯上可能會顯得比較凌亂。所以此處文字組織的基本思路是:將load_module函數(shù)按照各主要功能分成若干部分,各部分在下文中的出現(xiàn)順序盡可能維持在代碼中的出現(xiàn)順序:如果某些功能之間存在著某種依賴關(guān)系,比如有A和B兩個功能,A功能的敘述需要用到B功能中提供的機制,則先介紹B功能:獨立于功能模塊之外的一些基礎(chǔ)設(shè)施,比如某些功能性函數(shù),則盡量往前放。

模塊ELF靜態(tài)的內(nèi)存視圖

用戶空間程序insmod首先通過文件系統(tǒng)接口讀取內(nèi)核模塊demodev.ko的文件數(shù)據(jù),將其放在一塊用戶空間的存儲區(qū)域中(圖中void *umod所示)。然后通過系統(tǒng)調(diào)用sys_init_module進入到內(nèi)核態(tài),同時將umod指針作為參數(shù)傳遞過去(同時傳入的還有umod所指向的空間大小len和存放有模塊參數(shù)的地址空間指針uargs)。

sys_init_module調(diào)用load_module,后者將在內(nèi)核空間利用vmalloc分配一塊大小同樣為len的地址空間,如圖1·2中Elf_Ehdr *hdr所示。然后通過copy_from_user函數(shù)的調(diào)用將用戶空間的文件數(shù)據(jù)復(fù)制到內(nèi)核空間中,從而在內(nèi)核空間構(gòu)造出demodev.ko的一個ELF靜態(tài)的內(nèi)存視圖。接下來的操作都將以此視圖為基礎(chǔ),為使敘述簡單起見,我們稱該視圖為HDR視圖(圖1·2下方點畫線橢圓部分)。HDR視圖所占用的內(nèi)存空間在load_module結(jié)束時通過vfree予以釋放。
第三十一章 linux-模塊的加載過程一

字符串表(string Table)

字符串表是ELF文件中的一個section,用來保存ELF文件中各個section的名稱或符號名,這些名稱以字符串的形式存在。圖1·3給出了一個具體的字符串表實例:
第三十一章 linux-模塊的加載過程一
由圖1·3可見,字符串表中各個字符串的構(gòu)成和c語言中的字符串完全一樣,都以’\0’作為一個字符串的結(jié)束標(biāo)記。由index指向的字符串是從字符串表第index個字符開始,直到遇到一個’\0’標(biāo)記,如果index處恰好是,那么index指向的就是個空串(null stnng)。

在驅(qū)動模塊所在的ELF文件中,一般有兩個這樣的字符串表section,一個用來保存各section名稱的字符串,另一個用來保存符號表中每個符號名稱的字符串。雖然同樣都是字符串表section,但是得到這兩個section的基地址的方法并不一樣。

section名稱字符串表的基地址為char *secstrings=(char *)hdr+entry[hdr->e_shstrndx].sh_offset。而獲得符號名稱字符串表的基地址則有點繞:首先要遍歷Section
header table中所有的entry,去找一個entry[i].sh_type=SHT_SYMTAB的entry,SHT_SYMTAB表明這個entry所對應(yīng)的section是一符號表。這種情況下,entry[i].sh_link是符號名稱字符串表section在Section header table中的索引值,換句話說,符號名稱字符串表所在section的基地址為char *strtab=(char *)hdr+entry[entry[i].shlink].sh_offset。

如此,若想獲得某一section的名稱(假設(shè)該section在section header table中的索引值是i),那么用secstrings+entry[i].sh_name即可。

至此,load_module函數(shù)通過以上計算獲得了section名稱字符串表的基地址secstrings和符號名稱字符串表的基地址stb,留作將來使用。

HDR視圖的第一次改寫

在獲得了section名稱字符串表的基地址secstrings和符號名稱字符串表的基地址strtab之后,函數(shù)開始第一次遍歷section header table中的所有entry,將每個entry中的sh_addr改寫為entry[i].sh_addr=(size_t)hdr+entry[i].offset,這樣entry[i].sh_addr將指向該entry所對應(yīng)的section在HDR視圖中的實際存儲地址。

在遍歷過程中,如果發(fā)現(xiàn)CONFIG_MODULE_UNLOAD宏沒有定義,表明系統(tǒng)不支持動態(tài)卸載一個模塊,這樣,對于名稱為".exit”的section,將來就沒有必要把它加載到內(nèi)存中,內(nèi)核代碼于是清除對應(yīng)entry中sh_flags里面的SHF_ALLOC標(biāo)志位。

相對于剛復(fù)制到內(nèi)核空間的HDR視圖,HDR視圖的第一次改寫只是在自身基礎(chǔ)上修改了Section header table中的某些字段,其他方面沒有任何變化。接下來在“HDR視圖的第2次改寫”一節(jié)中將會看到改寫后的HDR視圖會再次被改寫,在那里,HDR視圖中的絕大部分會被搬移到一個新的內(nèi)存空間中,那也是它們最終的內(nèi)存位置。

find_sec函數(shù)

內(nèi)核用find_sec來尋找section再Section header table中的索引值,load_module->find_module_sections->find_sec

static unsigned int find_sec(const struct load_info *info, const char *name)
{
	unsigned int i;

	for (i = 1; i < info->hdr->e_shnum; i++) {
		Elf_Shdr *shdr = &info->sechdrs[i];
		/* Alloc bit cleared means "ignore it." */
		if ((shdr->sh_flags & SHF_ALLOC)
		    && strcmp(info->secstrings + shdr->sh_name, name) == 0)
			return i;
	}
	return 0;
}

函數(shù)返回該的索引值,如果沒有找到對應(yīng)的section,則返回0。該函數(shù)的前兩個參數(shù)分別是ELF文件的ELF header和section header。因為函數(shù)要查找的是某一section的name,所以第三個參數(shù)就是前面提到的secstrings,第四個參數(shù)則是安查找的section的name。函數(shù)的具體實現(xiàn)過程非常簡單:遍歷section header table中所有的entry(忽略沒有SHF_ALLOC標(biāo)志的section,因為這樣的section最終不占有實際內(nèi)存地址),對每一個entry,先找到其所對應(yīng)的section name,然后和第四個參數(shù)進行比較,如果相等,就找到對應(yīng)的section,返回該section在Section header table中的索引值。

在對HDR視圖進行第一次改寫之后,內(nèi)核通過調(diào)用find_sec,分別查找以下名稱的section:".gnu.linkonce.this_module”,“__versions”和“.modinfo,。查找的索引值分別保存在變量modindex、versindex和infoindex中,以備將來使用。文章來源地址http://www.zghlxwxcb.cn/news/detail-435641.html

到了這里,關(guān)于第三十一章 linux-模塊的加載過程一的文章就介紹完了。如果您還想了解更多內(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īng)查實,立即刪除!

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

相關(guān)文章

  • 【正點原子STM32連載】第三十一章 待機模式實驗 摘自【正點原子】APM32E103最小系統(tǒng)板使用指南

    1)實驗平臺:正點原子APM32E103最小系統(tǒng)板 2)平臺購買地址:https://detail.tmall.com/item.htm?id=609294757420 3)全套實驗源碼+手冊+視頻下載地址: http://www.openedv.com/docs/boards/xiaoxitongban 本章介紹APM32E103低功耗模式中的待機模式,進入待機模式后,MCU內(nèi)部的電壓調(diào)壓器將斷開1.3V電源域

    2024年01月22日
    瀏覽(157)
  • 【正點原子FPGA連載】第三十一章DDR4讀寫測試實驗 摘自【正點原子】DFZU2EG/4EV MPSoC 之FPGA開發(fā)指南V1.0

    【正點原子FPGA連載】第三十一章DDR4讀寫測試實驗 摘自【正點原子】DFZU2EG/4EV MPSoC 之FPGA開發(fā)指南V1.0

    1)實驗平臺:正點原子MPSoC開發(fā)板 2)平臺購買地址:https://detail.tmall.com/item.htm?id=692450874670 3)全套實驗源碼+手冊+視頻下載地址: http://www.openedv.com/thread-340252-1-1.html DDR4 SDRAM(Double-Data-Rate Fourth Generation Synchronous Dynamic Random Access Memory,簡稱為DDR4 SDRAM),是一種高速動態(tài)隨機

    2024年01月16日
    瀏覽(27)
  • 【正點原子FPGA連載】第三十一章基于lwip的echo server實驗 摘自【正點原子】DFZU2EG_4EV MPSoC之嵌入式Vitis開發(fā)指南

    【正點原子FPGA連載】第三十一章基于lwip的echo server實驗 摘自【正點原子】DFZU2EG_4EV MPSoC之嵌入式Vitis開發(fā)指南

    隨著物聯(lián)網(wǎng)的興起,萬物互聯(lián)需要一個強大而又靈活的協(xié)議體系,TCP/IP協(xié)議得天獨厚,而在嵌入式網(wǎng)絡(luò)設(shè)備中,由于硬件資源的限制,需要特殊的實現(xiàn)方式。LWIP作為TCP/IP協(xié)議的一種輕量級實現(xiàn)方式,滿足了這一要求。本章我們利用VITIS軟件自帶的lwIP Echo Server例程模板,初步了

    2024年02月14日
    瀏覽(23)
  • 第十一章 Python第三方庫縱覽

    11.1 網(wǎng)絡(luò)爬蟲方向 網(wǎng)絡(luò)爬蟲是自動進行HTTP訪問并捕獲HTML頁面的程序。Python語言提供了多個具備網(wǎng)絡(luò)爬蟲功能的第三方庫。這里介紹兩個常用的Python網(wǎng)絡(luò)爬蟲庫: requests和scrapy 。 11.1.1 requests requests庫是一個簡潔且簡單的處理HTTP請求的第三方庫,其最大優(yōu)點是程序編寫過程更

    2024年02月08日
    瀏覽(26)
  • Linux 內(nèi)核模塊加載過程之重定位

    1.1.1 struct load_info info 加載模塊只需要讀入模塊的二進制代碼即可,然后執(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)
  • 【從零開始學(xué)習(xí)JAVA | 第三十一篇】異常體系介紹

    【從零開始學(xué)習(xí)JAVA | 第三十一篇】異常體系介紹

    ? ? ? ? 本文我們將為大家介紹一下異常的整個體系,而我們學(xué)習(xí)異常,不是為了敲代碼的時候不出異常,而是為了能夠熟練的處理異常,如何解決代碼中的異常。 ?我們就以這張圖作為線索來詳細(xì)介紹一下Java中的異常: 在Java中, Exception(異常)是一種表示非致命錯誤或異

    2024年02月15日
    瀏覽(89)
  • 研一第二十一周論文閱讀情況

    研一第二十一周論文閱讀情況

    一、《Benchmarking PathCLIP for Pathology Image Analysis》 1、Abstract: ????????準(zhǔn)確的圖像分類和檢索對于臨床診斷和治療決策具有重要意義。最近的對比語言圖像預(yù)訓(xùn)練(CLIP)模型在理解自然圖像方面表現(xiàn)出了顯著的能力。從CLIP中汲取靈感,PathCLIP專為病理學(xué)圖像分析而設(shè)計,在

    2024年02月19日
    瀏覽(15)
  • 孩子都能學(xué)會的FPGA:第三十一課——用FPGA實現(xiàn)SPI主機發(fā)送數(shù)據(jù)

    孩子都能學(xué)會的FPGA:第三十一課——用FPGA實現(xiàn)SPI主機發(fā)送數(shù)據(jù)

    (原創(chuàng)聲明:該文是 作者的原創(chuàng) ,面向?qū)ο笫?FPGA入門者 ,后續(xù)會有進階的高級教程。宗旨是 讓每個想做FPGA的人輕松入門 , 作者不光讓大家知其然,還要讓大家知其所以然 !每個工程作者都搭建了全自動化的仿真環(huán)境,只需要雙擊 top_tb.bat 文件就可以完成整個的仿真(前

    2024年02月04日
    瀏覽(24)
  • JavaScript從入門到精通系列第三十一篇:詳解JavaScript中的字符串和正則表達式相關(guān)的方法

    JavaScript從入門到精通系列第三十一篇:詳解JavaScript中的字符串和正則表達式相關(guān)的方法

    ? 文章目錄 知識回顧 1:概念回顧 2:正則表達式字面量 一:字符串中正則表達式方法 1:split 2:search 3:match 4:replace ????????正則表達式用于定義一些字符串的規(guī)則,計算機可以根據(jù)正則表達式檢查一個字符串是否符合規(guī)則,或者將字符串中符合規(guī)則的內(nèi)容提取出來。

    2024年01月17日
    瀏覽(34)
  • Linux 第十一章

    Linux 第十一章

    ??博主主頁: @??. 一懷明月?? ????? 專欄系列: 線性代數(shù),C初學(xué)者入門訓(xùn)練,題解C,C的使用文章,「初學(xué)」C++,linux ?? 座右銘:“不要等到什么都沒有了,才下定決心去做” ??????大家覺不錯的話,就懇求大家點點關(guān)注,點點小愛心,指點指點?????? 目錄

    2024年04月28日
    瀏覽(170)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包