한 모듈 은 다른 모듈 에서 내 보 낸 함 수 를 참조 합 니 다.

11884 단어 linux 커 널 모듈
/ * 본 편 은 진짜 뚱뚱 한 동지 가 만 들 었 습 니 다. 오리지널 고생, 전재 출처 를 밝 혀 주세요.http://blog.csdn.net/figtingforlove/article/details/20067463*/
모듈 에서 다른 모듈 의 내 보 내기 함 수 를 참조 하 는 커 널 모듈 을 만 듭 니 다.플러스 내 보 내기 함 수 를 제공 하 는 module 작성플러스 모듈
(1) 소스 프로그램
#include
#include
#include

MODULE_LICENSE("GPL");

static int init(void)
{
	printk("<0>""
plus_init success!
"); return 0; } static int exit(void) { printk("<0>""
plus_exit success!
"); return0; } int plus(int a, int b) { return(a+b); } EXPORT_SYMBOL(plus); module_init(init); module_exit(exit);

(2) Makefile 파일
ifneq ($(KERNELRELEASE),)
    obj-m :=module_plus.o
else
    KERNELDIR := /lib/modules/$(shell uname -r)/build
    PWD := $(shell pwd)
default:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

endif

Makefile 이 작성 한 구체 적 인 형식 은 나중에 분석 ~ ~ ~ ~ (3) 컴 파일, 로드, 출력 make sudoinsmod module plus. ko dmesg 를 보면 터미널 에 'plus initsuccess!'lsmod 는 모듈 로드 에 성 공 했 음 을 보 여 줍 니 다. 모듈 Size Used by module plus 12630 cat / proc / kallsyms 는 커 널 기호 표를 보면 모듈 내 보 낸 함수 00000000000000 T plus [module plus] 를 볼 수 있 습 니 다.모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈 모듈
module plus. mod. c 파일, 즉 앞에서 말 한 모듈 컴 파일 도구 체인 으로 생 성 된 것 입 니 다. 그 재 미 있 는 성명 을 보 겠 습 니 다.
struct module __this_module
__attribute__((section(".gnu.linkonce.this_module"))) = {
	.name = KBUILD_MODNAME,
	.init = init_module,
#ifdef CONFIG_MODULE_UNLOAD
	.exit = cleanup_module,
#endif
	.arch = MODULE_ARCH_INIT,
};

이 밖 에 모듈 의 버 전 정보 와 의존 관 계 를 제공 합 니 다. Module. symvers 파일 은 모듈 내 보 내기 함수 정 보 를 제공 합 니 다. 함수 주소, 함수 명, 소재 모듈 디 렉 터 리 0x668f06c 7 plus / home / l / ll / otn 프로젝트 / 프로젝트 테스트 코드 / 커 널 모듈 인 스 턴 스 / 모듈 기호 내 보 내기 인 스 턴 스 / symbol / module plus EXPORT SYMBOL 은 module test 모듈 을 작성 하여 plus 함 수 를 참조 합 니 다.일반 프로 그래 밍 코드 에 따 르 면 다음 과 같다.
(1) 소스 프로그램
#include
#include
#include

MODULE_LICENSE("GPL");

extern int plus(int,int);
static int hello_init()
{
	printk(KERN_ALERT"Hello world
"); inti ; int c = 0; c = plus(1,2); printk(KERN_ALERT"c = %d
",c); return0; } static int hello_exit() { printk(KERN_ALERT"Goodbye world
"); return0; } module_init(hello_init); module_exit(hello_exit);

(2) make 를 컴 파일 하면 "plus" 함수 가 정의 되 지 않 았 다 는 경 고 를 볼 수 있 습 니 다. WARNING: "plus" [/ home / l / ll / otn 프로젝트 / 프로젝트 테스트 코드 / 커 널 모듈 인 스 턴 스 / 모듈 기호 내 보 내기 인 스 턴 스 / hello / hello. ko] undefined! (3) sudoinsmod hello. ko inmod: error inserting 'hello. ko': - 1 Invalid parameters 는 사용 할 수 없 는 인자 가 있다 고 합 니 다. why? 출력 정보 dmesg 보기[2052.726996] hello: no symbol version for plus [2052.727001] hello: Unknown symbol plus (err - 22) 는 원래 "plus" 를 찾 지 못 했 습 니 다.기호, 이상 한 ing, 분명히 내 보 냈 는데, why?.......................................................................이상 한 0000000000000, 즉 커 널 기호 표 에서 이 함수 의 주 소 는 0, 즉 알 수 없 는 것 입 니 다. 어쩐지 모듈 을 불 러 올 때 해당 하 는 함수 코드 를 찾 지 못 했 습 니 다. So? How? Answer 1: module plus 모듈 이 Mododule. symvers 기호 보 기 를 생 성 하지 않 았 다 고 생각 하 십 니까? 그러면 이 파일 로 현재 hello 모듈 디 렉 터 리 에서 생 성 된 Mododule. symvers 파일 컴 파일, succe 를 대체 합 니 다.ss 로 딩, success dmesg, [2278.175896] c = 3 좋 습 니 다. 그 는 성 공 했 습 니 다. butwhy? 위대 한 뇌 를 발휘 하 세 요 ~ ~ ~ ~ ~ 앞의 모듈 로 딩 부분 을 돌 이 켜 보면 '해결 을 위 한 인용' 을 발견 할 수 있 습 니 다.기호 시 처리 함수 Answer 2: 커 널 기호 표 내 보 내기 함수 주 소 는 0 이 고 함수 가 내 보 냈 으 니 불 러 온 Module plus 모듈 에 있 는 plus 함수 의 주 소 를 찾 습 니 다.
커 널 프로 그래 밍 에서 내 보 내기 기 호 를 찾 는 함수 에 대해 구체 적 인 함수 설명 은 내 보 내기 기호 장 을 보십시오.
/*inclede/module.h*/

/*Find a symbol and return it, along with, (optional) crc and(optional) module which owns it */

const struct kernel_symbol *find_symbol(const char *name,struct module **owner,const unsigned long **crc,bool gplok,bool warn)
{
	struct find_symbol_arg fsa;
	fsa.name= name;
	fsa.gplok= gplok;
	fsa.warn= warn;

	if(each_symbol(find_symbol_in_section, &fsa)) {
		if(owner)
			*owner= fsa.owner;
		if(crc)
			*crc= fsa.crc;
		return fsa.sym;
	}

	DEBUGP("Failedto find symbol %s
", name); return NULL; } EXPORT_SYMBOL(find_symbol); // void*__symbol_get(const char *symbol) { struct module *owner; const struct kernel_symbol *sym; preempt_disable(); sym= find_symbol(symbol, &owner, NULL, true, true); if(sym && strong_try_module_get(owner)) sym= NULL; preempt_enable(); return sym ? (void *)sym->value : NULL; }
EXPORT_SYMBOL(__symbol_get);

위 프로그램 코드 를 다음 과 같이 수정 합 니 다. 저 희 는 symbol get 으로 함수 지침 을 가 져 옵 니 다.
typedef int (*plus)(int a, int b);
//extern int plus(int,int);
static int hello_init()
{
	printk(KERN_ALERT"Hello world
"); plus p = NULL; inti ; p= (plus)__symbol_get("plus") ; int c = 0; //c= plus(1,2); c = p(1,2); printk(KERN_ALERT"c = %d
",c); return 0; }

make, insmod, dmesg 는 아무런 문제 도 없 이 문 제 를 해결 할 수 있 습 니 다. 이 방법 은 가능 할 것 같 습 니 다. [14534.773267] plus init success! [14681.389583] Hello world [14681.389592]c = 3 요약 하 자 면 모듈 을 불 러 올 때 인 용 된 기 호 를 처리 할 때 의존 관계 에 따라 이 기 호 를 검색 하여 인 용 된 함수 의 주 소 를 얻 을 수 있 습 니 다. 처리 하지 않 을 때 hello 모듈 을 불 러 올 때 plus 함 수 를 찾 을 수 없고 모듈 간 의존 관 계 를 만 들 수 없습니다. hello. mod. c 파일 에서
static const char module depends [] used attribute (section ("modinfo") = "depends ="; answer 1: 모듈 을 불 러 올 때 Module. symvers 파일 에 따라 내 보 낼 인용 을 사용 할 줄 알 고 모듈 module plus static const char module depends [] used attribute (section ("modinfo") = "depends = mosule plus"; answer 2: 모듈 을 불 러 올 때 커 널 내 보 내기 모듈 에 따라 "인용 해결" 을 처리 합 니 다.기호의 원칙, 여기저기 기호 표를 찾 아서 위 치 를 바 꾸 고 기호 주 소 를 찾 습 니 다 ~ ~ find symbol 은 대략 이 렇 습 니 다. 오차 가 있 을 수 있 지만 이해 에 영향 을 주지 않 습 니 다. 그러나 이 때 모듈 module plusrmodule plus 를 마 운 트 해제 하면 ERROR: Module module plus is inuse 를 알려 줍 니 다. 이 모듈 을 참조 하 는 모듈 을 마 운 트 해제 하 였 습 니 다. 왜 마 운 트 를 해제 하지 못 합 니까?모듈 은 모듈 플러스 모듈 의 상 태 를 읽 고 왜 그런 지 보 세 요.
(3) 테스트 모듈 을 작성 하여 다른 모듈 의 상 태 를 읽 습 니 다.
#include
#include
#include
#include
#include
static int __init mymod_init(void)
{
	struct module *mod;
	struct module_use *use;
	int cpu;
	//              
	printk(KERN_ALERT"[insmod mymod] name:%s, state:%d
",THIS_MODULE->name,THIS_MODULE->state); // , target list_for_each_entry(mod,THIS_MODULE->list.prev,list) { if(strcmp(mod->name,"module_plus")==0){ //1. 、 、 printk(KERN_ALERT"name:%s,state:%d, refcnt:%lu ",mod->name,mod->state,module_refcount(mod)); //1. module_plus ( mod->source_list) if(!list_empty(&mod->source_list)){ list_for_each_entry(use,&mod->source_list,source_list) printk(KERN_ALERT"%s\t",use->source->name); }else printk(KERN_ALERT"used by NULL
"); /* //2. 0 for_each_possible_cpu(cpu){ per_cpu_ptr(mod->refptr, cpu)->decs = 0; per_cpu_ptr(mod->refptr,cpu)->incs = 0; } //2. module_plus 、 、 printk(KERN_ALERT"name:%s,state:%d, refcnt:%lu
",mod->name,mod->state,module_refcount(mod)); */ } } return 0; } static int __exit mymod_exit(void) { printk(KERN_ALERT"[rmmodmymod] name:%s state:%d
",THIS_MODULE->name,THIS_MODULE->state); return0; } module_init(mymod_init); module_exit(mymod_exit); MODULE_AUTHOR("lilei"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Whymodule can not be removed");

코드 를 먼저 나 눠 보도 록 하 겠 습 니 다.
/*linux/module.h*/
/*    */
208 enum module_state {
209 	MODULE_STATE_LIVE, // 0
210 	MODULE_STATE_COMING, // 1
211 	MODULE_STATE_GOING, // 2
212 	MODULE_STATE_UNFORMED, // 3
213};

/*      */

224 struct module_ref {
225 	unsigned long incs;
226 	unsigned long decs;
227} __attribute((aligned(2 * sizeof(unsigned long))));
228

/*kernel/module.c*/
/*           */

774 unsigned long module_refcount(struct module *mod)
775{
776 	unsigned long incs = 0, decs = 0;
777 	int cpu;
778
779 	for_each_possible_cpu(cpu)
780 		decs += per_cpu_ptr(mod->refptr, cpu)->decs;
794 	smp_rmb();
795 	for_each_possible_cpu(cpu)
796 		incs += per_cpu_ptr(mod->refptr, cpu)->incs;
797 	return incs - decs;
798}

현재 코드 1 컴 파일, 로드 모듈, dmesg [8276.079311] [insmod my mod] name: a, state: 1 [8276.079317] name: module plus, state: 0, refcnt: 1 [8276.079318]used by NULL 여기 stat: 1 은 mod - > state = MODULE STATE COMING 을 나 타 냅 니 다. 이 모듈 이 mod - > init 함 수 를 실행 하고 있 음 을 나 타 냅 니 다. mod - > state = MODULE STATE LIVING 까지 실행 되 지 않 았 음 을 나 타 냅 니 다. module plusde 의 인용 수 는 1 입 니 다. 이 모듈 의 이 값 을 0 으로 바 꾸 면 되 는 것 아 닙 니까? 주석 을 지우 고 코드 2 를 추가 하 는 오래된 과정 입 니 다.[8276.079311] [insmod my mod] name: a, state: 1 [8276.079317] name: module plus, state: 0, refcnt: 1 [8276.079318] used by NULL [8276.079321] name: module plus, state: 0, refcnt: 0 [8307.155957] [8307.155957] plus exit success! [8358.543440] [rmmod my mod] name: a state: 2 모듈 은 성공 적 으로 마 운 트 해제 되 었 는데 왜?
이 때 module plus 는 다른 모듈 에 의존 하 지 는 않 았 지만 refcnt = 1. why? hello 모듈 에 추 가 된 코드 에 bug 가 있다 는 것 을 쉽게 생각 할 수 있 습 니 다. 어 딘 가 에 모듈 수 를 1 로 더 한 것 같 습 니 다. module plus 를 작성 할 때 symbol get 으로 기 호 를 찾 습 니 다.
1886 void *__symbol_get(const char *symbol)
1887{
1888 	struct module *owner;
1889 	const struct kernel_symbol *sym;
1890
1891 	preempt_disable();
1892 	sym = find_symbol(symbol, &owner, NULL, true, true);
1893 	if (sym && strong_try_module_get(owner))
1894 		sym = NULL;
1895 	preempt_enable();
1896
1897 	return sym ? (void *)sym->value : NULL;
1898}

/*     find_symbol    ,   strong_try_module_get*/

190 static inline int strong_try_module_get(struct module *mod)
191{
192 	BUG_ON(mod && mod->state ==MODULE_STATE_UNFORMED);
193  	if (mod && mod->state == MODULE_STATE_COMING)
194  		return -EBUSY;
195 	if (try_module_get(mod))
196 		return 0;
197 	else
198 	return -ENOENT;
199}

/*  try_module_get*/

951 bool try_module_get(struct module *module)
952{
953 	bool ret = true;
954
955 	if (module) {
956 		preempt_disable();
957
958 		if (likely(module_is_live(module))) {
959 			__this_cpu_inc(module->refptr->incs);
960 			trace_module_get(module, _RET_IP_);
961 		} else
962 			ret = false;
963
964 		preempt_enable();
965 	}
966 	return ret;
967}

놀 라 운 발견 역시 this cpu inc (module - > refptr - > incs); 모듈 의 인용 계수 에 1 을 더 했 습 니 다. 예상 한 대로 (니 마 의 것 이 나 오지 않 고 오래 찾 았 더 니 생각 났 습 니 다 ~)이것 이 바로 refcnt = 1 입 니 다. 몬스터 는 모듈 을 마 운 트 해제 할 수 밖 에 없 기 때문에 커 널 코드 도 마음대로 인용 할 수 없습니다. 특히 그의 세부 사항 을 모 를 때. 이 제 는 이 유 를 알 게 되 었 습 니 다. 함수 find symbol 을 바 꿔 보 겠 습 니 다. 모듈 의 이 변 량 값 을 직접 변경 하 는 것 은 규범 적 이지 않 기 때 문 입 니 다.
static int hello_init()
{
	printk(KERN_ALERT"Hello world
"); plus p = NULL; const struct kernel_symbol *sym;; int c = 0; sym = find_symbol("plus",THIS_MODULE, NULL, true, true); if(sym) { p= (plus*)sym->value; c= p(1,2); }else sym= NULL; p= NULL; printk(KERN_ALERT"c = %d
",c); return 0; }

컴 파일, 로드, dmesg [14534.773267] plus init success! [14681.389583] Hello world [14681.389592] c = 3 ok! noproblem ~ ~ ~ 정상적으로 마 운 트 해제 되 었 습 니 다. 규범 에 맞 는 지 는 저도 잘 모 르 겠 지만 이것 도 방법 이 라 고 할 수 있 습 니 다. 2.6 커 널 의 해결 ~ 참고 하 세 요.http://blog.csdn.net/zhangskd/article/details/7945140

좋은 웹페이지 즐겨찾기