임베디드 OS 개발 프로젝트를 읽고 작성하였습니다.
A.2 ABI
- Application Binary Interface의 약자
- 바이너리 수준에서 애플리케이션이 호환 가능하도록 만든 인터페이스
(*바이너리 수준 = 컴파일이 완료된 오브젝트 파일)
💡 ABI는 링커가 오브젝트 파일(라이브러리 포함)들을 링킹할 수 있도록 함수 호출 방법을 정의한 인터페이스
호출 방법
= 실행 파일 형식, 자료형, 레지스터 사용, 스택 프레임 조직, 호출 규칙
호출 방법 | |
실행 파일 형식 | 컴파일러가 생성하는 바이너리 파일의 구조를 정의 |
자료형 | 프로그래밍 언어가 사용하는 자료형의 실제 크기를 정의 |
레지스터 사용 | 파라미터와 로컬 변수가 레지스터를 몇 개나 사용하는지에 대한 내용을 정의 |
스택 프레임 조직 | 스택을 어떻게 만들지 정의. ex) 스택에 변수가 정의될 때 파라미터가 우선인지 로컬 변수가 우선인지 / 선언 순서대로 저장되는지 혹은 선언 순서의 반대로 저장되는지 |
호출 규칙 | 함수의 인수가 전달되는 방식을 정의 ex) 모든 파라미터가 스택으로 전달되는지 또는 일부는 레지스터를 사용하는지 |
우리가 사용하는 GCC의 파일명은 arm-none-eabi-gcc임
eabi ? Embedded ABI임
임베디드 환경에서 사용하는 ABI를 정해 놓은 것
EABI와 ABI의 가장 큰 차이점 = 동적 링크의 지원 유무
윈도우 운영체제에서 확장자가 dll인 파일이나 리눅스 운영체제에서 확장자가 so인 동적 라이브러리 EABI에서는 지원되지 않음
무조건 정적 링크만 지원
? 운영체제가 없는데 누가 동적 라이브러리를 관리하고 동적 링킹을 해 줌?
펌웨어는 그 자체로 필요한 모든 기능을 다 포함하고 있는 바이너리여야 함!
A.3 실행 파일 형식
GCC 등의 컴파일러로 오브젝트 파일을 만들고 링커로 라이브러리를 링킹하고나면 최종 결과물로 파일이 나옴
= 실행 파일이라 부르며, 대부분 ELF 파일 형식으로 만들어짐
ELF
- Executable and Linkable Format의 약자
- 크게 두 부분으로 구분됨
ELF 헤더
: ELF 포맷이 지정하는 여러 정보를 담고 있는 자료 구조
운영체제나 임베디드 시스템의 로더는 이 ELF 헤더를 읽은 후 필요한 데이터를 찾아서 메모리에 복사하고 CPU의 레지스터 값을 조정해서 파일을 실행하는 것
섹션
: 섹션의 이름은 점으로 시작하는 단어임
섹션 | |
.text | 컴파일러가 만든 기계어가 위치하는 섹션 (컴파일러가 생성한 바이너리 파일을 역어셈블하면 나오는 어셈블리어 = .text 섹션의 기계어를 어셈블리어로 바꾼 출력 결과) |
.rdata | 읽기 전용(read only) 데이터 (C 언어를 기준으로 const로 선언된 값이나 코드 안에 직접 숫자로 써 넣은 값) |
.data | 초기화된 전역 변수. 전역 변수를 선언할 때 초기화를 같이 하면 해당 전역 변수는 이 위치에 정보가 기록됨 |
.bss | 초기화되지 않은 전역 변수. 이 섹션에 위치한 전역 변수들은 나중에 0으로 초기화됨 (자리 차지를 안하며 크기 정보만 가지고 있음) |
.symtab | 심벌 테이블(symbol table) 전역 변수와 함수에 대한 심벌을 저장링커가 링킹을 할 때 다른 바이너리 파일의 rel.text와 rel.data에 있는 심벌 정보와 이 섹션에 있는 심벌 정보를 연결해서 메모리 오프셋을 지정해 줌 |
.rel.text .rel.data |
다른 파일에 선언된 전역 변수나 함수를 호출할 때 컴파일러는 소스 파일 내에서 해당 심벌을 찾을 수 없으므로 일단 비워두고 이 섹션에 정보를 기록. 나중에 링커가 이 섹션의 데이터를 읽어서 다른 파일의 정보와 연결해 줌 |
.debug | 디버거로 디버깅할 때 바이너리 파일을 읽으면 변수 이름과 함수 이름이 보임 -> 해당 정보가 전역 변수나 함수 이름이면 .symtab에서 읽고 로컬 변수일 때는 이 섹션에서 읽어옴. GCC의 컴파일 옵션에서 -g 옵션을 주어야만 이 섹션이 생성됨 |
.line | 디버거로 디버깅할 때 C 언어 한 줄이 어셈블리어 여러 줄로 연결되어서 보여짐. 이 정보가 이 섹션에 기록되어 있음.debug와 마찬가지로 GCC에서 -g 옵션을 주어야만 생성되는 섹션 |
.strtab | ELF 파일 전체에 사용되는 문자열 정보가 이 섹션에 기록됨. 문자열 정보는 정적 데이터이므로 이 섹션에 기록된 값을 그대로 사용 |
링커는 ELF 파일의 헤더와 섹션 정보를 읽어서 오브젝트 파일들을 하나로 묶은 다음 실행 가능한 최종 바이너리 파일(ELF 파일)을 만들어 냄
각 섹션별로 메모리의 어느 주소에 위치해야 하는지에 대한 정보도 같이 가지고 있음이 메모리 위치에 대한 정보를 제공하는 파일이 링커에 입력으로 전달하는 스캐터 파일임
모든 정보를 다 가지고 있는 실행 가능한 최종 바이너리 파일은 로더에 의해 조각 조각 분해되어 메모리에 복사됨윈도우나 리눅스라면 운영체제가 로더의 역할을 담당임베디드 시스템에서는 아예 이 실행 가능한 최종 바이너리 파일을 로더가 필요없게 만들거나 별도의 로더를 만들어서 먼저 실행시키고 로더가 펌웨어 바이너리 본체를 읽어서 메모리에 올리는 식으로 만듦
형태가 보이지 않을 뿐 어떤 식으로든 로더의 역할을 하는 절차는 임베디드 시스템에서도 필요함!
'개발 > 임베디드 os 개발 프로젝트' 카테고리의 다른 글
13장 동기화 (1) | 2023.11.28 |
---|---|
12장 메시징 (0) | 2023.10.31 |
11장 이벤트 (1) | 2023.10.16 |
10장 컨텍스트 스위칭 (0) | 2023.10.12 |
9장 스케줄러 (0) | 2023.10.09 |