읽기일기

Embedded Recipes (3)

http://recipes.egloos.com/5000239

3. Software 데꾸바쮸 (Decoupage) - Software의 정체와 만들기

a. Little Endian과 Big Endian

  • Little Endian : 상위 비트부터 읽어와서 MSB(Most Significant Bit)에 넣어준다.
  • Big Endian : 하위 비트부터 읽어와서 MSB로 넣어준다.

  • DWORD : 0x12345678
    • Big Endian : 0x12 0x34 0x56 0x78
    • Little Endian : 0x78 0x56 0x34 0x12
  • WORD : 0x1234
    • Big Endian : 0x12 0x34
    • Little Endian : 0x34 0x12
  • BYTE : 0x12

    • Big Endian : 0x12
    • Little Endian : 0x12
  • ARM은 Big Endian / Little Endian을 모두 지원하나, ARM core를 이용하여 구현한 chip이 어떻게 생겼느냐에 따라 달라짐.

b. 컴파일에 대한 단상

  • 프로세서가 해석할 수 있는 것은 명령어로, 기계어라 불리는 약속된 비트 패턴의 나열이다.
  • 오래전에는 사람들이 직접 이 비트 패턴을 직접 입력(Native code)하였으나, Native code와 1:1 매칭이 되는 표기를 만들어냈음. 이것이 Assembly.
  • Assembly를 Native code로 바꾸어주는 툴을 Assembler을 이용하여 코딩을 하였으나, Assembly는 특정 프로세서에만 동작하도록 되어있으므로, 이를 해결하기 위해 C, C++같은 High Level Language Compliler를 만들어냈음.
  • 프로세서에 맞는 Compiler를 사용하면, 대상 프로세서에 맞는 Assembly를 만들어냄.
  • 이렇게 만들어진 비트 패턴들을 Executable binary image라고 한다.

c. 컴파일 공장 이야기

  • 컴파일러의 목적은 Native code의 집합인 Binary image를 만들어내는 것.
  • Binary image를 만들어 내기 위해서는, Code(*.c), Header(*.h), ARM assembly(*.s) 파일이 필요하다.
  • Assembly 파일은 보통 *.c 파일을 컴파일 하여 생성하지만, 사람이 성능을 위하여 직접 코딩할 수도 있음.
  • Code, Header 파일을 컴파일러를 이용하여 Assembly로 만들고, Assembler를 이용하면 이것이 Symbol 정보를 가진 특정한 타입, ELF(Excutable and Linkable format)으로 변환된다. 그 다음 그 안에서 Native code만을 뽑아내는 과정을 거쳐 Binary image가 생성된다.

  • 하나의 c파일만으로 binary를 만들 수 있으면 좋겠지만, 그렇게 되기가 어렵기 때문에 link라는 개념이 생김.

  • 여러개의 assembly를 생성하고 이를 Object라는 기계어 형태로 만든 다음, 이들을 연결(link)한다.
  • Object는 혼자서 완성된 형태는 아니며 서로 다른 Object 끼리 연결할 수 있는 정보를 가진다.
  • 실제로는 *.c 파일을 *.s 파일로, 다음 *.s 파일을 *.o 파일로 변환한다.

  • *.c 파일을 *.s 파일로 만들기 전, 전처리(Preprocessor) 과정이 있다. MACRO를 처리하거나, syntax error 등을 검사한다.

d. 컴파일 순서에 따라 원하는 컴파일을 해보자

  • 하나의 c파일을 같은 이름의 o파일이 생긴다.

앞으로 사용할 예제 코드.

spaghetti.h

spaghetti.c

e. Preprocss (-E option)와 #Include

  • 전처리 과정은 -E 옵션을 사용하여서 한다. : tcc -E spaghetti.c > spaghetti.i
  • 전처리기에 대한 설명
  • include <>와 include “”의 차이점
  • 중복 include 처리에 대한 설명

f. Assembly로 만드는 방법

  • Assembly로 만드는 것은 -S 옵션을 사용한다. : tcc -S spaghetti.c
  • main 함수의 시작은 main PROC, 끝은 ENDP

g. Library - 남한테 보여주기 싫어

  • 라이브러리는 미리 컴파일해 놓은 Object file의 모음
  • 자주 사용하는 함수를 매번 컴파일하지 않아도 되고,
  • 소스를 공개하지 않아도 된다는 점.
  • Archivie라고도 부른다.

생성하는 법.

h. Lib을 까보자~

  • 내부에 어떠한 object들이 들어있는지 볼 때

  • 어떠한 심볼들이 있는지 볼 때

  • 심볼을 다른 심볼로 바꿔치기

i. 컴파일러 Option들

  1. -o : Ouput 이름을 지정할 때 사용
  2. -E, -C : Preprocessing 과정만 수행할 때 사용
  3. -S : Assembly로만 만들고 Object로는 만들지 않을 때 사용
  4. -c : Object만 생성할 때 사용
  5. -I : 헤더를 찾을 위치를 지정할 때 사용
  6. -D, -U : 매크로로 #define 선언을 한 것과 같은 효과
  7. -g : 디버깅 정보(DWARF)를 ELF file에 포함시킨다
  8. -W : Warning level을 정할 때
  9. -O1, -O2, .. : 최적화 수준을 정할 때 사용
  10. -l : 라이브러리를 지정해서 링크할 때 사용
  11. -L : 라이브러리가 있는 디렉토리를 지정할 때 사용

j. 변수의 scope와 그 생애 (Memory Map)

  • 변수의 유형은, auto, extern, static, volatile 이 있다.
  1. auto

local 변수라고 부르는데, 자신이 선언된 함수 또는 블럭이 동작 범위이다. 함수가 끝나거나 블럭을 넘어가면 사라짐. auto는 생략할 수 있다.

  1. extern

함수의 안쪽이 아닌 바깥쪽에 정의되어 파일 전체에 영향을 미친다. extern으로 선언만 해주면 프로그램 어느 부분에서도 사용할 수 있다.

  1. static

local의 static일 경우, 함수가 종료되더라도 값이 사리지지 않는다. glocal의 static일 경우, 다른 파일로부터 자신을 감추는 역할을 한다.

  1. volatile

volatile로 선언한 변수는 최적화에 참여하지 않는다.

k. Memory Map과 Symbol 이야기

  • Symbol이란 Linker가 알아볼 수 있는 기본 단위인데, link를 하고 난 뒤의 자신만의 주소를 가리키는 포인터.
  • ELF object 내에는 심볼 테이블이 존재하고 여기에 심볼들의 이름과 위치 정보가 들어있음.
  • 따라서 다른 파일의 심볼들은 확인할 수 없기 때문에 링커에 의해 따로 처리된다.
  • 함수, 전역변수, static 변수는 자기만의 주소를 갖고, local 변수는 자기만의 주소를 갖지 못한다.

  • ADS의 구분

    • RW(read-write) : 초기값이 있는 전역변수
    • ZI(zero-initialized) : 초기값이 0인 전역변수
    • RO(read-only) : const와 같이 수정이 불가능한 전역변수
  • RO는 ROM에, ZI는 RAM에 위치하여야 한다. RW의 경우, 초기값이 필요하기 때문에 ROM에도 위치하여야 하지만 수정해야하기때문에 RAM에도 위치하여야 한다.

l. ELF format Object File에 관한 진실. -c option (기계어 세상)

  • ELF 형식의 object file을 만들면, 이는 relocatable file이라고 한다. 아직 위치가 정해진 것이 아닌 나중에 링커를 통해 재배치가 가능하다는 의미.
  • ELF의 구조를 찾아보면 두가지 상태가 나오는데, linking view는 아직 배치가 되지 않은 상태, Execution view는 배치가 다 끝난 후의 상태를 말한다.
  • ELF파일의 내용은 readelf라는 툴로 살펴볼 수 있다.

m. Linker를 마무리 짓자 - ELF와 fromelf 까지!

  • 링커는 link시 실제 함수 정의부의 위치와 전역 변수들의 위치를 library와 object file에서 조사한 후에, table로 가지고 있다가 그 주소를 함소 호출부분에 기록해 넣는다.
  • 다시 말하면 executable ELF format image를 만드는 과정
  • 다른 파일에 있는 함수, 변수들까지 모두 조사하여 이들을 서로 연결. 따라서 ELF 파일에서는 다른 파일의 함수, 변수들은 빈칸으로 비워두었다가 다른 파일에서의 주소를 참조하여 이들을 최종적으로 써넣게 된다.

  • Memory Map을 그릴 때는 0x0을 맨 위에다 주로 그린다.

n. Scatter Loading/ Linker Description Script와 메모리 다루기

  • 메모리 구성 시, Load view와 Execution view로 나뉜다.
  • Load view는 플래시에 실행 image가 담겨 있을 때의 형태
  • Execution view는 실제 image가 실행될 때의 형태
  • 두 view가 다른 이유는,

    1. 플래시의 RW는 실행상태에서 RAM으로 복사되어야한다.
    2. RO의 경우에도, NOR 플래시의 경우에는 XIP가 가능하여 그 자리에서 바로 실행이 되지만, NAND 플래시를 사용하면 XIP가 불가능하기 때문에 다시 RAM으로 옮겨져야한다.
    3. ZI는 load view에서는 0이므로 공간을 차지하고 있지 않지만 execution view에서는 사용해야 할 부분이므로 공간을 차지하고 있다.
  • 이러한 메모리 구조를 Scatter loading 이라고 하며, 별도의 지시가 없으면 default memory map으로 적용되어 RO, RW, ZI 순으로 낮은 번지부터 쌓인다. 그리고 ZI가 끝나는 지점부터 Stack과 Heap을 잡게 된다.

o. Map file 분석

  • 링커의 출력으로 memory map 파일이 생성된다.
  • 가지고 있는 정보는 4가지
    1. Image symbol table
      • 링커가 만들어낸 symbol과 주소, region
      • User가 만들어낸 Symbol과 주소, size, 속해있는 object
    2. memory map of the image
      • Scatter loading 맞춘 region에 따라 구획을 나눈 주소와 size, type, section, object
    3. Image component sizes
      • 각 object 또하는 library에 대한 Ro, RW, ZI가 차지하는 size
    4. 전체 layout
      • 전체적인 memory의 RO, RW, ZI가 차지하는 지에 대한 정보

p. Memory Map과 Linker의 만남 - Locator

  • 메모리에서의 Ro, RW, ZI의 특정 위치를 지정할 수 있다.

  • 또한 Scatter loading script(*.scl)를 작성하여 이를 적용할 수도 있다.

  • 메모리맵 출력 또한 옵션이 필요하다

q. Makefile은 뭘 하는 녀석일까~?

Makefile의 구조.

  • 실행은 make -f sample.mak 와 같은 식으로 지정
  • makefile 명령을 내리면, 역순으로 파일을 찾는다. bin, elf, o, c 파일을 찾아 존재하지 않으면 순서대로 빌드한다.

r. 컴파일을 더더더 쉽게. MACRO와 SUFFIX

  • make 파일 내에서 MACRO를 사용할 수 있다.
  • VARIABLE = abc로 지정하고, $(VARIABLE) 으로 사용.
  • $@ : 현재 만들고 싶은 output 이름
  • $^ : 재료들의 이름
  • 예 : $(BINTOOL) -bin -o $@ $^
  • %.out : %.m
    • .out인 파일을 만나면 .m 파일을 생성하도록 한다. 명령은 그 아래에 지정

현재 디렉토리의 재료를 SRC로 등록하고, 타겟을 OBJECT로 등록한다.

s. 조금더~ Make 테크닉들

  • -C 옵션은 Change directory를 의미

  • vpath는 c나 h파일을 만났을 때 vpath로 지정된 path에서부터 찾아간다

  • VPATH 대문자로 사용하면, 재료가 없을 경우 탐색할 디렉토리를 지정한다

  • 다른 makefile도 include할 수 있다.

  • C에서의 Define처럼 사용할 수 있다.

  • @를 쓰면 현재 라인을 감추고 결과만 출력한다

  • .PHONY : 가짜 타겟, clean 등에 쓰이고 타겟 파일을 만들지는 않는다.

  • ifdef, endif 류의 명령도 존재한다.

  • Text를 조작할 수 있는 함수와 foreach 등이 있다.

  • target을 여러개 사용할 수 있다.

t. Make Option들

  • -C : 디렉토리 이동
  • -h : 도움말
  • -f : 이 옵션을 주지 않으면 Makefile을 찾아 실행하나 이 옵션을 통하여 원하는 .mak파일을 지정할 수 있다.
  • -r : make 내부의 정의된 규칙을 지우고 새로 시작한다
  • -t : touch 기능으로 파일의 생성 날짜를 현재로 바꾸어 수정하지 않은 파일도 다시 컴파일한다
  • -s : silence 모드로 출력을 표시하지 않는다
  • -v : version 출력
  • -p : 내부 세팅 값 출력
  • -k, -S : k는 문제가 생기더라도 계속 작업을 진행한다. S는 설정한 k를 무력화.
  • -d : 디버깅 메시지를 다 출력

Add a Comment Trackback