1주일도 넘게 멈춘 진도
최근 RTOS 공부를 시작하면서 어셈블리어로 작성된 코드를 다루게 되었습니다. 제대로 배운 적은 없지만, 많이 어려운 내용이 아니라서 그래도 따라갈 만하다고 생각했었는데요, 도저히 풀리지 않는 오류가 발생해서 많이 헤맸습니다. 어셈블리 코드 상단에 C언어처럼 #include
를 이용해 헤더 파일을 불러와 사용하려는데 빌드 오류가 나는 겁니다. 아래처럼요.
➜ rtos git:(working) ✗ make all
mkdir -p build
arm-none-eabi-gcc -march=armv7-a -mcpu=cortex-a8 -Iinclude -c -g -o build/Entry.o boot/Entry.s
boot/Entry.S: Assembler messages:
boot/Entry.S:32: Error: undefined symbol ARM_MODE_BIT_SVC used as an immediate value
boot/Entry.S:38: Error: undefined symbol ARM_MODE_BIT_IRQ used as an immediate value
boot/Entry.S:44: Error: undefined symbol ARM_MODE_BIT_FIQ used as an immediate value
boot/Entry.S:50: Error: undefined symbol ARM_MODE_BIT_ABT used as an immediate value
boot/Entry.S:56: Error: undefined symbol ARM_MODE_BIT_UND used as an immediate value
boot/Entry.S:62: Error: undefined symbol ARM_MODE_BIT_SYS used as an immediate value
make: *** [Makefile:42: build/Entry.o] Error 1
#include
한 헤더 파일에 #define
되어 있는 값을 불러들이지 못하는 문제입니다. 처음에는 include 디렉터리를 제대로 포함하지 못해서 그런 것이라 생각했고 관련된 정보들을 찾아봤었습니다. 그러나 아무리 봐도 실수한 부분을 찾을 수가 없었습니다.
우연하게 알게된 사실
그러다 아주 우연히 이 글에서 다음과 같은 사실을 알게 되었습니다.
gcc 컴파일러는 어셈블리어로 작성된 파일도 컴파일할 수 있는데, 이때 파일 확장자의 대소문자를 구별한다.
.s(소문자) 파일은 전처리가 필요 없는 파일로 인식한다.
.S(대문자) 파일은 전처리가 필요한 파일로 인식한다.
당장 제가 가진 파일의 확장자를 확인해보았습니다. 확장자가 소문자로 .s
라고 적혀있더군요. 이것을 대문자 .S
로 바꾸니 1주일도 넘는 시간 동안 막혀있던 빌드 과정이 시원하게 뚫렸습니다.
일단 오류를 해결했으니 조금 더 검색을 진행해보았습니다.
.s
와 .S
도대체 무슨 차이일까?
이 글에서 두 확장자의 차이를 확인할 수 있었습니다. .s
확장자는 컴파일러가 출력한 어셈블리어 코드에 사용됩니다. '컴파일러가 어셈블리어 코드를 만들어낼 수 있나?'라고 생각이 들었는데, gcc 컴파일러에 -S
옵션을 주면 어셈블리어로 변환할 수 있다는 사실을 알게 되었습니다. 그리고 이때 만들어진 파일은 순수하게 어셈블리어로만 작성되어 있으며 확장자가 소문자 .s
로 만들어집니다.
$ gcc -S foo.c # -S 옵션으로 foo.c를 foo.s라는 어셈블리어로 작성된 파일로 변환합니다.
한편, .S
확장자는 개발자가 직접 작성한 어셈블리어 코드를 의미합니다. gcc 컴파일러는 .S
파일을 컴파일할 때 #include
나 #if
, #define
과 같은 C 언어 전처리 코드를 해석할 수 있습니다. 그래서 개발자는 자신이 작성한 어셈블리 코드에 C언어 형식의 매크로를 사용할 수 있지요. 예를 들어 #define
으로만 이루어진 .h
파일을 #include
하여 어셈블리 코드에서 #define
된 값을 사용할 수 있습니다. 그 예는 아래와 같습니다.
// "ARMv7AR.h" file
#define ARM_MODE_BIT_USR 0x10
#define ARM_MODE_BIT_FIQ 0x11
#define ARM_MODE_BIT_IRQ 0x12
#define ARM_MODE_BIT_SVC 0x13
#define ARM_MODE_BIT_ABT 0x17
#define ARM_MODE_BIT_UND 0x1B
#define ARM_MODE_BIT_SYS 0x1F
#define ARM_MODE_BIT_MON 0x16
#include "ARMv7AR.h"
#include "MemoryMap.h"
...(생략)...
reset_handler:
MRS r0, cpsr
BIC r1, r0, #0x1F
ORR r1, r1, #ARM_MODE_BIT_SVC
MSR cpsr, r1
LDR sp, =SVC_STACK_TOP
많은 시간을 흘려보냈지만 노력이 헛되지 않았다!
이번 기회에 작지만 아주 중요한 사실을 알게 되었습니다. 여태껏 파일 확장자가 대문자든 소문자든 신경을 쓴 적이 없었습니다. 어느 쪽이든 잘 작동했으니까 말입니다. 사실 제가 참고하고 있는 책에 어셈블리어 코드 파일 확장자를 대문자로 쓰여 있다는 사실은 알고 있었습니다. 그러나 저는 '굳이 귀찮게
Shift
키를 눌러가며 대문자로 써야 할까. 어차피 같을 텐데...'라고 대수롭지 않게 넘겼습니다. 그 귀찮음이 많은 시간이 지나가도록 만들었지요. 그래도 다행이라고 생각합니다. 만약 아무 생각 없이 책을 따라 했다면 .s
와 .S
의 차이를 몰랐을 테니까요.
'연구 노트 > Embedded' 카테고리의 다른 글
Windows 10에서 RTOS 개발환경 구축하기 2 - 개발 도구 설치하기 (1) | 2021.01.17 |
---|---|
Windows 10에서 RTOS 개발환경 구축하기 1 - WSL 2를 활성화하자 (0) | 2021.01.12 |
[TM4C] ADC 초기화 과정 (0) | 2020.12.10 |
[TM4C] GPIO 초기 설정 방법 해설 (0) | 2020.11.22 |
CCS 프로젝트 include 경로 설정 (4) | 2020.11.18 |