일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 |
- yocto
- AVR
- Debug
- UART
- Visual Studio
- platformio
- bare metal
- QEMU
- vscode
- 라즈베리파이
- C++
- atmel
- 리눅스
- BeagleBone
- esp32
- 디버깅
- Raspberry
- Debugging
- buildroot
- nucleo
- Arduino
- GPIO
- AArch64
- STM32
- Linux
- USART
- avr-gcc
- 아두이노
- raspberrypi
- Visual Studio Code
- Today
- Total
임베디드를 좋아하는 조금 특이한 개발자?
[AArch64] Bare metal에서 BSS 섹션 초기화(전역 변수 쓰레기 값 문제) 본문
- 개발 환경
개발 보드 : Raspberrypi 4
WSL2 (Ubuntu 22.04 LTS)
toolchain : aarch64-linux-gnu-gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
- 예제 코드
GitHub - MainForm/RaspberryPI4_Baremetal_Firmware
Contribute to MainForm/RaspberryPI4_Baremetal_Firmware development by creating an account on GitHub.
github.com
1. 서론
일반적인 C언어 개발 환경에서는 초기화 하지 않은 전역 변수에 대해서 자동적으로 0으로 초기화를 수행하는 과정(crt0)이 있습니다. 하지만 우리는 그러한 과정조차 없는 말 그대로 Bare metal 환경이기에 bss을 직접 초기화 해주는 과정을 추가해야합니다. 혹시 시, 가상환경(QEMU)에서는 미리 메모리가 0으로 초기화 되어 있어 굳이 해줄필요가 없지만 실제 하드웨어에서는 그렇지 않습니다. 전역 변수가 초기화 되지 않으므로 해당 내용을 주의하며 프로그래밍하면 문제가 없을 수 있다고 생각하지만 문제는 외부 라이브러리를 사용하는 순간 발생하게 됩니다. 해당 라이브러리에서 만약 초기화 하지 않은 전역변수를 사용한다면 빌드 과정에서는 문제가 발생하지 않지만 프로그램 실행시 이유없이 프로그램이 멈추는 문제가 발생할 수 있을 것입니다. 그러므로 해당 문제가 발생하지 않도록 main함수를 호출하기 전 BSS 섹션을 초기화하는 방법에 대해서 알아 보도록하겠습니다.
2. 문제 확인
- main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
#include "uart.h"
// 특정 시간동안 멈추기 위한 함수
void delay(volatile int val){
while(val-- > 0);
}
// 초기화 하지 않은 전역변수 int test;
int main(void){
uint32_t recvData;
// UART 초기화
UART_Initialize(115200);
while(1){
if(test == 0){
// test가 0으로 초기화 되었다면 0 출력
UART_SendWord('0');
}
else{
// test에 0이 아닌 쓰레기값이 들어 있다면
UART_SendWord('1');
}
UART_SendWord('\n');
delay(0x400000);
}
return 0;
}
|
cs |
위 출력 결과를 통해 test라는 전역변수에 쓰레기 값이 들어 있음을 확인하였습니다. 굳이 변수의 값을 직접 확인하지 않은 이유는 bare metal 환경에서는 변수의 값을 출력하기 위해 정수를 문자열로 변환하는 함수를 작성해야하는데 그런 함수를 작성하는 것이 쉬운일이 아닐 수 있기에 간단한 방법으로 초기화 되지 안았음을 확인하였습니다.
3. BSS 섹션 초기화
3.1. 링커 스크립트에서 BSS 섹션에 라벨 추가
1
2
3
4
5
|
.bss : {
__bss_start__ = .;
*(.bss*) *(COMMON)
__bss_end__ = .;
}
|
cs |
위 링커 스크립트에서 __bss_start__와 __bss_end__ 라벨을 추가함으로써 어셈블리 언어로 프로그래밍 시 BSS 섹션의 시작 및 끝에 대한 주소를 확인 할 수 있게 됩니다.
3.2. BSS 초기화 코드 추가
- start.S
1
2
3
4
5
6
7
8
9
10
|
// Clear the entire BSS section to 0.
ADR x1, __bss_start__
ADR X2, __bss_end__
MOV x0, #0
clear_bss:
CMP x1, X2
B.HS done_clear
STR x0, [x1], #8
B clear_bss
done_clear:
|
cs |
- BSS 초기화 순서
- x1에는 BSS 섹션의 시작 주소를 x2에는 BSS의 끝 주소를 저장합니다.
- x0에는 0을 저장하여 BSS 섹션을 0으로 초기화 할 준비를 합니다.
- 그 후 x1가 x2보다 크거나 같아 질 때까지 x1 주소의 값을 0으로 저장하면서 x1의 주소을 8씩 증가합니다.
주소를 8씩 증가하는 이유는 1byte x 8 = 64bit 이기 때문입니다.
4. BSS 초기화 확인
이제 정상적으로 0으로 초기화 되었음을 확인하였습니다.
'Embedded > ARM' 카테고리의 다른 글
[AArch64] Bare metal에서 EL2에서 EL1으로 모드 변경 방법 (2) | 2025.07.30 |
---|---|
[AArch64] FPU 및 SIMD 활성화 (실수 연산시 멈춤 현상 해결) (1) | 2025.07.28 |