일반적인 aaa.c파일 내에서 외부 참조가 어떻게 실행이 되는지 알아보자.
aaa.c
#include <stdio.h>
extern bbb();
int aaa()
{
printf("aaa called\n");
return 0;
}
int main()
{
aaa();
bbb();
}
bbb.c
#include <stdio.h>
int bbb()
{
printf("bbb called\n");
return 0;
}
다음과 같이 aaa파일을 컴파일 하면 해보자. ##root@linux-VirtualBox:#gcc aaa.c 아마도 아래와 같이 에러가 뜰 것이다.
화면 표시:
/tmp/cckyz0rW.o: In function `main':
aaa.c:(.text+0x29): undefined reference to `bbb'
collect2: error: ld returned 1 exit status
사실 bbb라는 함수는 사실 bbb.c에 있다.
이것을 컴파일 하려면 컴파일 할때
bbb.c를 추가해 주면 된다.
##root@linux-VirtualBox:#gcc aaa.c bbb.c ##root@linux-VirtualBox:#./a.out
화면 표시:
aaa called
bbb called
이렇게 extrn을 사용 하는 것을 외부 참조라고 한다.
이제 커널모듈에서 외부 참조를 알아 보자.
첨부 코드
- nosymbol.c
- symbol1.c
- symbol2.c
- Makefile
Makefile:
KERNELDIR = /lib/modules/$(shell uname -r)/build
obj-m := nosymbol.o symbol1.o symbol2.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
rm -rf *.ko
rm -rf *.mod.*
rm -rf .*.cmd
rm -rf *.o
rm -rf .tmp_versions
nosymbol.c:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
static int module_begin(void)
{
printk("Hello nosymbol!\n");
return 0;
}
static void module_end(void)
{
printk("Good bye");
}
module_init(module_begin);
module_exit(module_end);
** symbol1.c :**
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
char *test;
void symbol_test(void)
{
printk("%s \n", test);
}
EXPORT_SYMBOL (symbol_test);
static int module_begin(void)
{
printk("Hello symbol1!\n");
test = "This is a test. \n";
return 0;
}
static void module_end(void)
{
printk("Good bye symbol1");
}
module_init(module_begin);
module_exit(module_end);
** symbol2.c: **
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
MODULE_LICENSE("GPL");
extern void symbol_test(void);
static int module_begin(void)
{
printk("Hello symbol2!\n");
symbol_test();
return 0;
}
static void module_end(void)
{
printk("Good bye symbol2\n");
}
module_init(module_begin);
module_exit(module_end);
##코드 파일과 Makefile 파일을 작성 하시고 밑 내용대로 명령어를 실행 하시면 됩니다.
make을 하여 nosymbol.ko, symbol1.ko, symbol2.ko 준비한다.
일단 nosymbol.ko파일을 올려 보자. ##root@linux-VirtualBox:#insmod nosymbol.ko ##root@linux-VirtualBox:#dmesg
화면 표시:
...
...
...
[38.479039] audit: type=1400 audit(1434530634.417:75): apparmor="STATUS" operatio
n="profile_replace" name="/usr/sbin/cupsd" pid=2178 comm="apparmor_parser"
[38.479354] audit: type=1400 audit(1434530634.417:76): apparmor="STATUS" operatio
n="profile_replace" name="/usr/sbin/cupsd" pid=2178 comm="apparmor_parser"
[1369.122239] Hello nosymbol! <== 동작 확인.
사실 위의 예제는 static으로 선언이 되어 있을때 실행이 되는 여부를 알아 보기 위한 것이다.
이제 본격 적으로 static과 외부 선언을 확인해 보자.
##root@linux-VirtualBox:#cat /proc/kallsyms | grep symbol[12] insmod를 하지 않았기 때문에 심볼테이블에 아무것도 올라 가지 않았다.
따라서 화면 안에 아무것도 표시가 안될 것이다.
이제 insmod를 해보자. ##root@linux-VirtualBox:#insmod symbol2.ko
화면 표시:
insmod: ERROR: could not insert module symbol2.ko: Unknown symbol in module
삽입 할수 없다고 나올 것이다.
우리가 코드를 작성을 할때 symbol1안에 **symbol_test(void)**를 EXPORT 했다.
따라서 symbol1.ko파일이 먼저 올라가 있지 않으면 symbol2.ko파일이 삽입이 안된다. ##root@linux-VirtualBox:#insmod symbol1.ko ##root@linux-VirtualBox:#dmesg
화면 표시:
[ 2162.062027] Hello symbol1!
##root@linux-VirtualBox:#cat /proc/kallsyms | grep symbol[12]
화면 표시:
ffffffffa0049020 t module_begin [symbol1]
ffffffffa0049050 t module_end [symbol1]
ffffffffa004a080 r __kstrtab_symbol_test [symbol1]
ffffffffa004a040 r __kcrctab_symbol_test [symbol1]
ffffffffa004b000 d __this_module [symbol1]
ffffffffa0049050 t cleanup_module [symbol1]
ffffffffa0049020 t init_module [symbol1]
ffffffffa0049000 T symbol_test [symbol1] <== 확인
ffffffffa004b260 b test [symbol1]
ffffffffa004a030 r __ksymtab_symbol_test [symbol1]
모듈이 정상적으로 동작이 되었는것도 확인을 하였고 심볼테이블에 올려 진것도 확인하였다. 이제 2번째 심볼을 올려 보자. ####root@linux-VirtualBox:#insmod symbol2.ko ####root@linux-VirtualBox:#dmesg
화면 표시:
[ 2562.354554] Hello symbol2!
[ 2562.354558] This is a test.
##root@linux-VirtualBox:#cat /proc/kallsyms | grep symbol[12]
화면 표시:
ffffffffa003d000 t module_begin [symbol2] << 추가됨
ffffffffa003d020 t module_end [symbol2] <<
ffffffffa003f000 d __this_module [symbol2] <<
ffffffffa003d020 t cleanup_module [symbol2] <<
ffffffffa003d000 t init_module [symbol2] << 추가됨
ffffffffa0049020 t module_begin [symbol1]
ffffffffa0049050 t module_end [symbol1]
ffffffffa004a080 r __kstrtab_symbol_test [symbol1]
ffffffffa004a040 r __kcrctab_symbol_test [symbol1]
ffffffffa004b000 d __this_module [symbol1]
ffffffffa0049050 t cleanup_module [symbol1]
ffffffffa0049020 t init_module [symbol1]
ffffffffa0049000 T symbol_test [symbol1]
ffffffffa004b260 b test [symbol1]
ffffffffa004a030 r __ksymtab_symbol_test [symbol1]
모든 모듈이 정상적으로 동작이 되었는것도 확인을 하였고 symbol2.ko안에 내용들이 심볼테이블에 올려 진것도 확인하였다.
##root@linux-VirtualBox:#lsmod
화면 표시:
Module Size Used by
symbol2 16384 0
symbol1 16384 1 symbol2 << 심볼2가 심볼1을 참조 하고 있다.
nosymbol 16384 0
모듈 symbol1을 다른 모듈1개가 사용 하고 있다. 따라서 symbol1를 참조 하고 있는 모든 모듈을 제거 하지 않으면 symbol1은 제거 되지 않는다. 제거 순서 symbol2 -> symbol1 -> nosymbol
##root@linux-VirtualBox:#rmmod symbol2 ##root@linux-VirtualBox:#dmesg ##root@linux-VirtualBox:#cat /proc/kallsyms | grep symbol[12] ##root@linux-VirtualBox:#lsmod ##root@linux-VirtualBox:#rmmod symbol1 ##root@linux-VirtualBox:#dmesg ##root@linux-VirtualBox:#cat /proc/kallsyms | grep symbol[12] ##root@linux-VirtualBox:#lsmod ##root@linux-VirtualBox:#rmmod nosymbol ##root@linux-VirtualBox:#dmesg ##root@linux-VirtualBox:#lsmod