C 언어로 개발된 프로그램에서 main 함수는 누가 호출해 줄까요?
보통 컴파일 할 때 자동으로 startup code가 링크되어 프로그램을 실행하면 main함수가 실행 됩니다. 여기서 링크되는 startup code는 라이브러리에 들어 있으며 시스템 마다 다릅니다. 현재 사용하고 있는 yagarto toolchain의 경우 newlib이라는 라이브러리를 사용합니다. 이 startup code에서 main함수를 호출해 줍니다.
newlib 라이브러리는 임베이드 시스템용으로 개발된 오픈 소스로 소스를 다운 받아 분석해 볼 수 있습니다. startup code는 어셈블리 언어로 작성되어 있으며 crt0.S라는 이름을 가지고 프로세서 마다 다릅니다. 여기서 crt란 C Runtime이라는 의미 입니다.
newlib-1.18버전의 경우 예를 들면
ARM processor 의 경우 newlib-1.18.0/newlib/libc/sys/arm/crt0.S 파일이 startup code 입니다. 이 파일을 따라 가다 보면 237번 줄에 main함수로 분기하는 어셈 명령을 확인 할 수 있습니다.
bl FUNCTION (main)
여기서 하나 더 생각해 볼 것이 있습니다. 같은 ARM 이라도 보드에 따라 ARM 프로세서의 구성이 다르고 메모리 연결 방식이나 타입이 다르기 때문에 같은 crt0.S를 사용할 수 없습니다. 그래서 보드 마다 별도의 crt0.S 파일을 만들어 주고 yagarto toolchain에 들어있는 newlib 라이브러리의 crt0.o는 제외 시키고 컴파일 해야 합니다. 링크 옵션 중 -nostartfiles 옵션이 startup code를 제외하고 링크하라는 의미 입니다.
FreeRTOS의 경우 gcc관련 데모를 보면 폴더안에 boot.s라는 파일을 볼 수 있는데 이 파일이 startup code입니다. 코드를 보시면 main으로 점프하는 명령을 확인 할 수 있습니다.
그러면 startup code에서 어떤일 들을 할까요?
- 보드에 따른 레지스터들 초기화
- 인터럽트 처리
- 인터럽트 벡터 주소와 실제 코드 주소가 다른 경우 인터럽트 벡터 코드를 복사
- .bss 영역을 영으로 초기화
- data영역이 read only인 경우 rw 할 수 있는 메모리 영역으로 복사
- 캐시나 MMU같은 메모리 설정
- main함수 호출
메모리 관련 정보는 ld라는 확장자를 가지는 링크 스크립트 파일에서 설정하고 링크 옵션(-T) 에서 지정해 줄 수 있습니다. Makefile를 분석해 보면 알 수 있습니다.