Arm Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

493
557
422263


[부록 A] GCC 지시어: __init 과 __section 부록

__init 키워드가 함수 선언부에 있으면 해당 함수는 init.text 섹션에 위치합니다. 이제 이해를 돕기 위해 __init 키워드로 선언된 함수를 볼까요?  

01 https://github.com/raspberrypi/linux/tree/rpi-4.19.y/kernel/watchdog.c 
02 void __init lockup_detector_init(void)
03 {
04 set_sample_period();
02번째 줄 과 같이 lockup_detector_init() 함수 옆에 보이는 __init 구문입니다. 함수 선언부에 __init 키워드가 보이면 다음과 같이 해석하면 됩니다.

    부팅 과정에 1번 호출되는 함수이구나. 

__init 키워드로 선언된 함수는 언제 호출될까요? 아래 코드와 같이 do_one_initcall() 함수에서 부팅 과정에 1번 호출됩니다.

https://elixir.bootlin.com/linux/v4.19.30/source/init/main.c 
static void __init do_initcall_level(int level)
{
initcall_entry_t *fn;
...
trace_initcall_level(initcall_level_names[level]);
for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++)
do_one_initcall(initcall_from_entry(fn));
}

init과 __section 매크로 코드 분석

 이번에는 __init 키워드의 정체를 같이 확인해보겠습니다. __init 키워드는 매크로 타입으로 다음 코드와 같이 정의돼 있습니다.

https://github.com/raspberrypi/linux/tree/rpi-4.19.y/include/linux/init.h 
#define __init          __section(.init.text) __cold notrace __latent_entropy

이어서 include/linux/compiler.h 파일을 열어보면 '__section(S)'는 '__attribute__ ((__section__(#S)))' 구문으로 치환됩니다.
# define __section(S) __attribute__ ((__section__(#S)))

여기서 __section(S) 매크로의 'S'를 유심히 볼 필요가 있습니다.

좀 복잡해보입니다. 조금 풀어서 설명을 드려볼께요.
__init 키워드는 매크로 타입으로 __section(.init.text) 코드로 치환됩니다.

__section(.init.text) 이 코드에서 입력이 .init.text이므로 #S 대신 .init.text가 치환되면 다음 코드가 되는 것입니다.
__attribute__ ((__section__(.init.text)))

여기서 __attribute__란 지시자는 컴파일러에게 함수 컴파일 속성을 기능입니다.

그러면 __attribute__ ((__section__(.init.text))) 은 어떤 의미일까요? 이는 ‘.init.text’ 이란 섹션에 해당 함수 코드를 위치시키라는 의미입니다. 여기서 섹션이란 비슷한 역할을 수행하는 코드 묶음을 의미합니다. 이 방식으로 비슷한 속성의 코드나 변수들을 특정 섹션에 위치시키는 경우가 많습니다. 

.init.text 섹션 정보 확인하기

__init 키워드 코드를 분석하니 자연히 다음과 같은 의문이 생깁니다.

    .init.text 섹션의 정체는 무엇일까?

 리눅스에서 기본으로 제공하는 objdump이란 바이너리 유틸리티 프로그램을 다음 명령어로 사용하면 섹션 정보를 확인할 수 있습니다.
objdump -x vmlinux  | more

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .head.text    0000026c  80008000  80008000  00008000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .text         00607798  80100000  80100000  00010000  2**6
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  2 .fixup        0000001c  80707798  80707798  00617798  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  3 .rodata       001c2c84  80800000  80800000  00618000  2**12
                  CONTENTS, ALLOC, LOAD, DATA
...
 17 .stubs        000002c0  ffff1000  80b00020  008a1000  2**5
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 18 .init.text    0004275c  80b002e0  80b002e0  008a82e0  2**5
                  CONTENTS, ALLOC, LOAD, READONLY, CODE

18번째 섹션인 .init.text은  0x80b002e0부터 위치 해있고 그 사이즈는 0x4275c라는 것을 알 수 있습니다. 당연히 .init.text 섹션은 0x80b002e0--0x80b42a3c 메모리 공간에 위치했다고 볼 수 있습니다.


"혹시 궁금한 점이 있으면 댓글로 질문 남겨주세요. 아는 한 성실히 답변 올려드리겠습니다!" 

Thanks,
Austin Kim(austindh.kim@gmail.com)


[부록 A] GCC 지시어
   * inline    
   * noinline    
   * __noreturn   
   * unused   
[부록 B] 리눅스 커널 실력을 키우는 방법
[부록 C] 리눅스 커널 프로젝트에 기여하기  
C.1 리눅스 커널 오픈소스 프로젝트 소개 
   * 용어  
C.2 설정 방법 
C.3 패치 코드를 작성한 후 이메일로 보내기  
C.5 리눅스 커널 오픈소스 프로젝트로 얻는 지식 


# Reference: For more information on 'Linux Kernel';

디버깅을 통해 배우는 리눅스 커널의 구조와 원리. 1

디버깅을 통해 배우는 리눅스 커널의 구조와 원리. 2


 

핑백

덧글

댓글 입력 영역