☞ http://ya-n-ds.tistory.com/3137 : Embedded with ARM (2) Scatter file, Map file, etc
Reference : 'Embedded Recipes'(히언, 코너북)
< Registers >
- General Purpose Register : Address Register, Data Registser(In/Out), Instruction Pipeline Register(Op Code)
- Special Purpose Register :
a. Program Counter : 현재 실행되고 있는 코드 주소
b. Stack Pointer : 현재 Stack 영역의 마지막에 데이타가 Push된 곳을 가르키는 주소
cf. Stack initialization for Abort mode : Change CPU mode to Abort mode -> Link Abort stack to R13
msr CPSR_C, #PSR_Abort
lrd r13, =abort_stack+Abort_Stack_Size // Descending 일 때는 'abort_stack+Abort_Stack_Size'부터
// Ascending 일 때는 'abort_stack'부터
c. Linked Register : code가 Jump 했을 때 돌아갈 곳의 주소
d. Status Register : MCU의 상태를 나타내는 Register
- IO Register : D Flip-flop ( 필요한 크기만큼 assign -> Read할 때 Masking해서 사용 필요 )
Type : Read-only, Write-only, Read-Write
cf. Macro Instruction(Assembly) - Micro Instruction (Lower level : Logic gate?)
< ARM 동작 Mode >
- User : Normal
System : OS Task
Execption Mode : FIQ, IRQ, Supervisor(Protected OS - SWI), Abort(Memory data access violation), Undef(Undefined instruction)
cf. Privileged Mode : System + Exception Mode
- Privilegd Modes : 서로간의 mode 변경 가능 ( Priviledged -> Normal )
- Default mode : Supervisor Mode ( SVC )
< ARM Register >
- General register : R0~R12 / Special Purpose Register : R13~R15, CPSR, SPSR
- R0~R7, R13~R15 : Thumb mode & ARM mode / R8~R12 : ARM mode only
- R0~R7, R15(PC) : Common for All - 9ea
- R8~12 : Common for USR, SYS, FIQ, SVC, ABT, IRQ, UND - 5ea
- R9~12_banked : FIQ - 5ea
- R13~14 : Common for User, SYS - 2ea
- R13~14_banked : FIQ, SVC, ABT, IRQ, UND - 2*5=10ea
- CPSR : Common for SYS, FIQ, SVC, ABT, IRQ, UND - 1ea
- SPSR_banked : FIQ, SVC, ABT, IRQ, UND - 1*5=5ea
- CPSR : Current Program Status Register
. [31:28] : N(Negative), Z(zero), C(Carry), V(oVerflow)
. [7]-IRQ, [6]-FIQ : '1'-Disable, '0'-Enalbe
. [5] : '1'-Thumb mode / '0'-ARM mode
. [4:0] : modes
cf. USER, SYS : Same except for the CPSR mode bits
- SPSR : Saved Program Status Register - Mode change할 때 CPSR을 backup -> 이전 mode로 돌아갈 때 사용
- R14 ( Linked Register ) : 어디에서 branch 했는지를 알려 줌
- R13 ( Stack Pointer ) : 현재 Stack이 쌓여 있는 위치
- R15 ( Program Counter ) : 현재 Instruction을 Fetch해 온 위치
- Context : Register set의 snap shot
< ARM Exception & Mode >
- Exception : Initiation of Mode entry ( including Interrupt )
- Reaction : 현재 동작 멈춘다 -> Exception에 해당하는 Mode에 진입 -> Exception 해당 주소로 PC(Program Count)를 Jump -> Exception 처리
- PC for Modes ( Exception case )
. SVC mode : Power-on or Reset or SWI -> PC를 0x0(Low vector인 경우)로 jump
. IRQ/FIQ mode : Interrupt -> PC를 0x1C/0x18로 jump
. Abort mode : Data abort/Prefetch abort -> PC를 0x10/0x0C로 jump cf. Memory access fail ( e.g. Abnormal address, Access protection )
. UNDEF mode : PC를 0x04로 jump cf. Decoded Intruction error ( e.g. Memory corruption )
- CPSR for Modes
. User=0x10, FIQ=0x11, IRQ=0x12, SVC=0x13, Abort=0x17, Undef=0x1B, SYS=0x1F
- Exception priority : Reset > Data Abort > FIQ > IRQ > Prefetch Abort > Undefined > SWI
cf. Undefined : Handler에서 Coprocessor 또는 주변기기 control routine에 사용
- Exception Reaction;
1. Ability to return to the previous state
. Mode saving : CPSR -> SPSR_xcpt
. Context를 stack에 저장 - Banked register를 제외한 나머지 Register를 저장 ( R0~R12 )
R13_xcpt = Stack location
. Mode change : CPSR 변경(bit[4:0]) -> Stack pointer도 Exception mode 것으로 변경됨,
ARM mode로 변경(T=0), IRQ Disable(I=1) cf. Exception : 32-bit ARM mode .
. 돌아갈 주소 저장 : R14_xcpt <= R15(PC) // Back-up of PC to Linked Register
보정 : PC보다 2개의 OP code 전 ( Calculated address depends on MCU bit e.g. 16-bit, 32-bit, etc )
. R15(PC) <= Exception Jump 주소 -> PC 값을 Vector address로 변경
. R0~R12 : Saved to the stack pointed by R13_xcpt
cf. CPSR, R15(PC), R0~R12 are shared -> Back-up is required
2. Return to the Previous State
. CPSR <= SPSR_xcpt
. Stack에 저장했던 Register 복원 ( R0~R12 : via R13_exct )
. PC(R15) <= R14_xcpt(Linked Register)
3. Miscellaneous Tips
- mode : ARM can be secured from Application SW
- No SPSR for System/User mode -> There is no exception for entry -> CPSR is backed-up using Stack if necessary
- Exception Vector Table : Exception handling FW is to be implemented from that address
- High Vector : SRAM for Bootloader -> DRAM Initialization -> FW copy from NAND to SDRAM -> Change to Low vector
< ARM-Thumb PCS : Register 사용법 >
- APCS : ARM Procedure Call Standard -> Compiler가 기계어를 만들어 낼 때 사용하는 규칙
cf. AAPCS : Procedure Call Standard for ARM Architecture
. R12 : The Intra-Procedure-Call scratch register
. R11(=V8 / FP) : ARM state variable register 8 / Frame Pointer
. R10(=V7 / SL) : Stack Limit Pointer
. R9 (=V6 / SB) : ARM state variable 6
. R[8:4](=V5~V1) : ARM state variable [5:1]
. R[3:0](=A4~A1) : Argument/Result/Scratch register[4:1]
- R0~R3(a1~a4)
1) Argument
int function (int a, int b, int c, int d)
-> (void) function (10,20,30,40);
R0=10, R1=20, R2=30, R3=40
2) Result ( Return value )
f = function(10,20,30,40); // if result is '100'
-> R0=100 -> f=100
R1~R3 : Pointer값을 넣어주면 호출한 쪽에서 return 값처럼 R1~R3를 가져다 쓸 수 있음
-> Return value size : Max= 4byte*4 = 16byte
3) Scratch : Argument 전달 수단으로 쓰인 후, APCS만 잘 지키면 함수 내부에서 임의로 사용 가능
cf. Argument : 4개까지는 R0~R3에 저장, 나머지는 Stack에 저장
함수 내부 변수 : 8개까지는 R4~R11에 저장. 나머지는 Stack에 저장
- R4~R11(v1~v8) : Variable. 함수 호출 후에 바뀌면 안된다.
-> 함수 수행 전에 이전 R4~R11을 Stack에 저장한 후 사용
-> 함수가 끝나면 Stack의 값을 R4~R11로 다시 복원
- R12(IP, Intra) : ARM-Thumb interworking / Long branch할 때 Veneer를 통한 주소 할당할 때 임시 보관소로 사용
- R13(SP, Stack Pointer)
- R14(LR, Linked Register) : 함수 호출 또는 Jump할 때 돌아올 주소를 저장
- R15(PC, Program Counter) : Fetch하고 있는 주소
cf. Compiler option : -apcs
< Compie - Concept >
- Primitive Compiler : Assembly -Assembler-> Native code ( cf. Natvie code : Processor dependent )
cf. Assembly : 기계어(Native code)와 1:1로 mapping -> a kind of 'mnemonic' ( symbol for easy memorization )
- High level language Compiler : C, C++, etc. -> Assembly -> Native code ( Executable binary image )
cf. Processor에 맞는 Assembly를 만들어내는 compiler 필요
- Cross compile 환경 : 실제 Target에서 돌아갈 binary image를 PC에서 compile 할 수 있는 환경 ( Taget 자체는 Compile 하기에는 너무 작은 시스템 )
< Compile - Basic >
- '*.c, *.h' -(C compiler)-> '*.s' -(Assembler)-> '*.o'(+ELF format) -(Linker)-> '*.elf' image -(fromelf)-> '*.bin'
cf. Linker inputs : '*.o', '*.lib'(on Window, with wrappers for DLL), '*.a'(archive files on Unix), '*.scl'(SCatter Loading for code allocation in memory)
cf. Linker outputs : Shared object files(*.o, *.a), Executive image(*.elf), Text file for Memory structure(*.map, *.sym)
- C-compiler (armcc, tcc) / Assembler (armasm)
- ELF : Executable and Linking Format -> Native code + Other information = "linked objects"
- C-compiler + Assembler ;
1. Pre-process : #defien, #include 처리, Syntax error check -> c 형식의 *.i 파일 만듦
2. *.s 파일 만듦 ( Mnemonic의 Assembly )
3. Assembler : elf 형식의 *.o 파일 만듦
- *.lib : source code를 제공하고 싶지 않을 때 object 형식으로 미리 컴파일하여 제공하고, lib는 다른 컴파일된 object 들과 link되어 같이 물려 들어가는 방식으로 처리
- *.scl : Scatter loading - binary를 만들 때 메모리 주소 구성을 원하는 대로 할 수 있게 해주는 script 파일
- *.map, *.sym : compile된 binary의 메모리 구성을 나타내 주는 text file ( compiler option )
cf. Cross Compiler : ADS(ARM Developer's Suit), ARM GCC(GNU project)
< Compile Execution - Preprocess >
- tcc -E file_name.c > file_name.i
- #include "" : *.c가 있는 directory에서부터 시작하여 Search path로 등록된 path를 찾아감
#include <> : Compiler에게 미리 정의된 path부터 header를 찾아감
e.g. #include <stdio.h> : ADS 설치된 directory의 include directory가 pre-defined path
- tcc -E -Iinclude_path file_name.c > file_name.i // Inlcude path option : -I
cf. -J option : Compiler default include path for <>
- Header의 중복 include를 막음
#ifndef __SPAGHETTI_H__
#define __SPAGETTI_H__
#include "spaghetti.h"
#endif
< Compile Execution - Assembly >
- tcc -S file_name.c
main PROC
...
BX lr ;; Branch exchange to lr(Linked Register) ; Return value is r0
ENDP
__asm {...} ; In-line Assembly
cf. Function arguments are separately managed from the registers used in in-line assembly
< Compile Execution - Library >
- Library ( Archive file ) : 미리 컴파일 해놓은 object 파일 모음 ( 자주쓰는 함수는 compile할 때 Link만 해주면 됨 ) e.g. 'printf'
- Make Library from Object files
armar -r Lib_FileName.lib C_FileName1.o C_FileName1.o C_FileName1.o
cf. tcc -c C_FileName1.c C_FileName1.c C_FileName1.c
- command window에서 'armar' // Option is displayed
armar -x Lib_FileName.a Target_Name // Extract members corresponding to the target names
armar -d Lib_FileName.a Target_Name // archive 안에 있는 object 제거
armar -tv Lib_FileName.a // Print table of the contents of archive
ADS12\Lib\armlib>
*_a_*.? : ARM standard library
*_t_*.? : Thumb standard library
ADS12\Lib\armlib> armar -t f_t.b // Print table of the contents of the archive
ADS12\Lib\armlib> armar -zs f_t.b // Show table of the symbols
cf. Symbol : Names of Global variable, Function, etc.
ADS12\Lib\armlib> armar -d f_t.b printf2.o // Delete 'printf2.o' from f_t.b archicve
-> printf2.c에 다른 함수를 구현
-> tcc -c printf2.c // Generate only Linkable object
-> armar -c f_t.b printf2.o // Suppress warning when a new archive is created
< 변수의 scope >
- auto : Local 변수 - 함수 안에 정의. 선언된 함수 또는 block 안 -> 함수 수행 후 return과 함께 사라짐
e.g. void function_name { auto int var1; ... return; }
- Global 변수 - 함수 바깥에 정의... 선언된 위치부터 파일 끝까지 영향을 줌
int durian = 0x10; // durian : spaghetti, ramen 함수에서 사용 가능
void spaghetti(void){...}
char sirsak = 0x20; // sirsak : ramen 함수에서 사용 가능
void ramen(void){...}
- extern : 다른 파일에서 선언된 Global 변수를 사용
e.g. extern int durian : 다른 함수에서 정의되어 있는 durian을 사용 ( Link할 때 연결됨 )
- static : 프로그램 시작할 때 생성, 프로그램 끝날 때 없어짐. 접근성을 제약 ( 선언된 파일 안에서만 사용 )
. local static : 함수가 끝난 후에도 그 값을 유지
. global static : 다른 함수에서 extern을 선언하여 가져다 쓸 수 없음
e.g. static int durina = 0x10;
- volatile : Optimization 하지 않음
cf. Memory mapped I/O
< Memory Map & Symbol >
- Symbol : Linker가 알아볼 수 있는 기본 단위. Link 후에 자신만의 주소를 갖게 됨
-> Symbol의 이름은 메로리 영역의 시작 주소를 가리키는 pointer 역할
-> e.g. function, global variable, static variable ( 자기만의 고유 주소 가짐 - 다른 파일의 함수들에서도 access 가능 )
- ELF object 파일 내의 Symbol table : Source code에 의해 참조되는 Symbol들의 이름과 위치 정보
-> Linker가 참조하여 address로 변환하여 binary로 만듦
- Symbol Types ( ADS )
. RO ( Read Only ) - Function(Code - .text), Const Global Variable, Const data (.constdata )
. RW ( Read Write ) - 초기값 있는 Global variable ( .data )
. ZI ( Zero-Initialization ) - 초기값이 0인 Global variable ( .bss )
= initial 되지 않은 global variable + initial 값이 0인 global variable + 전역변수 array로 구현된 stack, heap
cf. RO->ROM / RW->ROM,RAM / ZI->RAM : Location can be manipulated via 'Scatter loading file'
- Non-symbol ( ZI )
. Local variable : Stack
. Dynamic Memory Allocation : Heap e.g. 'malloc-free'
< Executable and Linking Format : ELF >
☞ http://recipes.egloos.com/5010841 : ELF format Object 파일에 관한 진실
☞ http://recipes.egloos.com/v/5011946 : ELF와 fromelf까지!
☞ https://www.cs.utexas.edu/users/fussell/courses/cs429h/lectures/Lecture_20-429h.pdf : Linking
- Linking view ( Link 하기 전의 object 파일 ) / Execution view ( Link 후 )
cf. ELF Header / .text(code), .rodata (RO) / .data(RW) / .bss(Block Shared by Symbol:ZI)
-> readelf -h spaghetti.o ( cf. -h : header option )
-> fromelf -c spaghetti.o // disassemble
- Linker Placement Rule for Executable Image
. Input Section (Section) : Collect the same section from the surce files
. Output Section (Code) : Arrange the input section in alphabetic sequence
. Region (RO, RW, ZI) : ??
cf. Linker 역할 : 함수 위치와 전역변수들의 위치를 library 파일과 object 파일에서 조사한 후 Table로 가지고 있다가, 그 주소를 함수와 변수를 사용하는 코드 부분에 적는다. RAM이 많이 필요.
- ELF Relocatable object file ( Linker가 사용할 수 있는 정보 포함 )
ELF header
// Start of section
.text // 컴파일된 OP code
.rodata // Const data + switch case의 jump table
.data // Global variables with initial values other than zero
.bss // Global variables unitialized or zero-initialized
.symtab // Symbol table ( Global variable, function )
.rel.text // relocatable text, Relocation info for .text section. Addresses of instructions that will need to be modified in the executable object file
// Linker가 이 object 파일과 다른 object 파일 연결할 때 사용 (e.g. code with extern variable ). Link 후의 executable object file에서는 없어짐.
.rel.data // ( similar as .rel.text. ) Relocation info for .data. Addresses of pointer data that will need to be modified in the merged executable object file
.debug // -g option : debug symbol table ( DWARF type debugging symbol )
.line // -g option : op code와 C code의 line을 연결 ( for Trace32 Debugger cf. 'y.sourcepath' )
.strtab // .symtab과 .debug setction에 사용되는 const data인 string table
// End of section
Section header table // Description of object file sections
cf. Relocatable object file : section = Executable object file : segment(~Sum of sections)
- ELF Executable object file
ELF header // with entry point address which is the start address of this file
Segment header table // Maps contiguous file section to runtime memory segments
.init // ELF 실행전 OS의 Initializatin code + Program header ( Informatiom for execution )
.text // 컴파일된 OP code
.rodata // Const data + switch case의 jump table
.data // RW
.bss // RW
.symtab // Symbol table ( Global variable, function )
.debug // -g option : debug symbol table
.line // -g option : op code와 C code의 line을 연결
.strtab // .symtab과 .debug setction에 사용되는 const data인 string table
// End of section
Section header table // Description of object file sections
=> Segment allocation
. Read-only Segment : ELF header ~ .rodata ( Code segment ) -> RO : .text + .rodata
. Read-Write Segment : .data, .bss ( Data segment ) -> RW : .data
=> Binary for Embedded system : 'RO + RW'
cf. .symtab ~ Section header table are not loaded into memory
cf. .data : ROM에 초기값을 가지고 있어야
cf. .bss : 시작주소와 Size만 가고 RAM 영역 확보 -> boot sequence에서 bss 영역을 0으로 초기화
- Relocation Rule for the duplicated Global symbols
0. Function & Initialized Global varialbe=Strong // Uninitialized Global variable=Weak
1. Duplicated Strong symbol -> Link error
2. Strong symbol + Weak symbols -> Compiled with Strong symbol
3. Weak symbols -> randomly selected and compiled
cf. 'static' : prevention of reference from other files
- Making binary : stored in ROM ( RO, RW )
tcc -c arm.c thumb.c // for Relocatable object file in ELF format : Output - arm.o thumb.o
armlink -elf -o embedded.elf recipes.lib arm.o thumb.o // for Executable object file in ELF format
fromelf -bin -o embedded.bin embedded.elf // for Executable binary file
- Example including 'armar', 'armasm'
armcc -c arm.c thumb.c // linkable object 파일 만들기
// = 'armcc -S' + 'armasm'
armar -r armthumb.lib arm.o thumb.o // library 만들기
armasm boot.s // Assembly를 linkable object 파일 만들기
armlink -elf -o recipe.elf armthumb.lib boot.o
fromelf -bin -o recipe.bin recipe.elf
- DWARF : Executable ELF의 debug section의 형식 -> ICD(In Circuit Debugger)에 사용
- axf : arm executable format ( a variance of elf ) - .debug is based on DWARF2.0
-------