일반적으로 bootup code는 startup.S로 작성한다.
startup.S에는 다음 내용이 들어간다.
- vector table
- stack pointer 초기화
- 전역변수 초기화
- 기타 이미지 로딩
- pc를 main으로 이동, 꼭 main이 아니어도 되며, startup.S에서 branch 해주기만 하면 된다. 이 때 부터 C 코드를 사용 가능함.
- C code를 사용하려면 기본적으로 변수 초기화, sp 초기화 등을 해야 한다. 하지 않으면 당연히 data abort!
변수의 class
- register variable
- 예약어는 register이며, 쓴다고 항상 적용되지 않고, 성능에 영향을 준다고 판단하면 그냥 stack에 저장한다.
- 단, register를 사용하면, 주소값을 읽을 수 없다. 원래 register에 저장하라고 하는 것이니깐.
- local variable
- auto 예약어인데 일반적으로 생략된다.
- static variable
- global variable
memory layout
- 아래서부터,
- TEXT(program code)
- RODATA(constant)
- DATA(initialized data)
- BSS(uninitialized data)
- HEAP(BSS 이후로 커감)
- STACK(메모리 끝에서 부터 내려옴)
- 원하는 section에 넣으려면, linker를 이용한다.
- t32에서 section 확인하려면, sYmbol.List.SECtion
Inline assembly
- C보다 빠른 처리를 위함이고, __volatile__ 예약어를 사용해야 컴파일러가 맘대로 최적화 하지 않는다
- 일반적인 형태:
- __asm__ __volatile__("" : "
C 파일을 compile 하면(main.c)
- 전처리기가 main.i를 생성
- compiler가 main.S를 생성
- assembler가 main.o를 생성
- 사람이 읽을 수 있는 언어를 hex code로 변경해 준다.
- objdump -S main.o <-- object의 정보를 확인할 수 있다.
- linker가 a.elf를 생성
- linker가 하는 역할은 object 파일을 메모리에 mapping을 하는 것
- input file들이 같은 메모리에 위치하여 서로 symbol을 사용할 수 있게 해준다.
- 각 object들의 .text(code), .data 들을 section별로 정리해서 elf로 저장한다.
- objcopy로 a.bin을 생성
- objcopy는 elf의 header, debug info 등을 날려버리고 binary만을 추출한다.
- 디버깅을 하려면 그래서 elf가 필요하다.
- gcc option인 --save-temps를 넣으면 위의 이미지들을 삭제하지 않는다.
Booting mode는 어떤 메모리를 이용하는지에 따라 여러가지가 있다.
보통 Hardware pin으로 설정할 수 있도록 하며, 각 mode별로 memory mapping이 달라진다.
- NOR flash mode: NOR는 비싸고 부피가 큰 메모리로, 주소에 접근해서 실행 가능하다. 그래서 부트로더를 NOR flash에 넣고 부팅할 수 있다.
- NAND flash mode:
-NAND는 싸고 집적도가 높다. 하지만 주소가 없고 블락별로 data를 읽을 수 있도록 되어 있다. 즉 I/O port만 있어서 전자적 신호로 Page단위로 load하여 주소 접근이 가능한 다른 메모리에 복사하여 사용해야 한다.
- 일반적으로 MCU 내부에 IRAM에 복사해서 사용한다.
- 간단히 요약하자면, IROM이 NAND에서 IRAM으로 부트 코드를 복사한 다음에 PC를 IRAM으로 이동해 준다. IRAM은 DRAM을 초기화 하고 OS image를 얹은 다음 PC를 DRAM으로 이동해 주어 'stepping stone' 방식으로 부팅하게 된다.
- 일반적으로 boot code를 이동하는 IRAM 주소는 vendor datasheet에 있음.
- 그 외에 network booting mode / usb booting mode 등이 있다.