728x90

컴파일러와 리버스 컴파일러

- 컴파일러 : 소스 코드 -> 기계어

- 리버스 컴파일러 : 기계어 -> 어셈블러/소스코드

 

 

인터프리터와 컴파일러

- 인터프리터 : 소스코드 한줄 씩 즉시 실행

- 기계어 : 소스코드 전체 기계어로 변환 후 실행

 

 

컴파일러 도구 정리

- 컴파일러 : 소스 코드 -> 어셈블리어

- 어셈블러 : 어셈블리어 -> 기계어(오브젝트 파일)

- 링커 : 오브젝트 파일들을 연결시켜 하나의 실행 가능한 파일(기계어) 생성

 

 

MCU와 고급언어

- 고급언어로 작성한 소스코드는 컴파일러에의해 어셈블리어로 변환, 이후 어셈블러로 각 MCU에 맞는 기계어로 변환됨

- ARM 어셈블리어 -> ARM 기계어

- AVR 어셈블리어 -> AVR 기계어

- x86 어셈블리어 -> X86기계어

 

 

기계어, 어셈블리어

- 기계어 : 0과 1로 이루어진 바이너리 코드

- 어셈블리어 : 기계어와 사람이 이해할 수 있는 명령어를 매칭시켜 만든 언어

- 아래의 그림은 고급언어, 어셈블리어, 기계어 사이 차이를 보여주고 있음

https://asecurity.dev/2017/07/%EC%97%AD%EB%B6%84%EC%84%9D-%EA%B8%B0%EA%B3%84%EC%96%B4%EB%A5%BC-%EB%B6%84%EC%84%9D%ED%95%9C%EB%8B%A4-disassemblers/

 

 

 

ARM 명령어 집합과 포멧

- ARM은 고정 크기와 형식을 갖는 명령어 사용. 아래의 그림은 32비트 고정 길이 명령어 집합을 보여줌.

- 아래와 같은 포멧으로 요소별 의미를 이해하여 올바른 값을 주면 곱샘, 인터럽트 등 기능 수행

https://damduc.tistory.com/115

- 좌측은 ARM 기계어 명령어, 우측은 디스어셈블한 어셈블리어 코드

http://www.jkelec.co.kr/img/lecture/arm_arch/arm_arch_4.html

 

 

 

명령어 처리기와 기계어

- 명령어 처리기가 해석하는 방식에 다라 기계어 코드가 달라야 함

 => 동일한 기계어 코드도 명령어 처리기가 다르면 다르게 해석

- 대표적인 명령어 처리기 구조 : RISC와 CISC

 

 

RISC와 CISC

- RISC Reduced Instruction Set Computer

  리스크. 축약된 명령어 집합. 적은 수의 명령어들만 제공 -> 단순구조, 고속

           => RISC 명령어 셋을 가진 경우. RISC머신(대표적으로 ARM)

- CISC Complex Instruction Set Computer

   씨스크. 복잡한 명령어 집합. 수많은 명령어들 제공 ->복잡구조, 저속 

          => CISC 명령어 셋을 가진 경우. CISC 머신(대표적으로 x86)

- 곱셈 연산에서의 리스크와 씨스크의 차이

 -> CISC는 mul 명령어로 곱샘 수행. RISC는 값들을 레지스터에 담은 후 반복문 수행

 -> CISC가 단순하다

 

 

 

통합 개발환경

- GUI 환경에서 개발을 편리하게 할수록 도와주는 도구

- 텍스트 에디터(소스 편집기)

- 빌드 도구 : 컴파일러, 어셈블러, 링커

- 디버거 : 실제 MCU를 동작시키며 MCU 변수, 레지스터 등의 상태 변화 학인

- 에뮬레이터 : MCU와 개발 환경을 연결시켜줌

- 시뮬레이터 : 가상의 기계와 개발 환경을 연결시킴

 

 

 

 

 

 

 

 

 

컴파일 과정

1. 전처리 preprocessing

- c언어에서 #define이나 #include 명령어들이 존재 

 => #define은 해당 단어 치환하고, #include는 관련 해더파일 복붙

 

2. 낱말 분석 lexical analysis

- 어셈블리어는 명령어와 데이터만으로 구성 => C언어도 명령어와 데이터로 구분하자

 => 몇개의 데이터, 명령어 등이 필요한지 알 수 있음.

- 아래의 그림은 낱말 분석 입력 예시

- 낱말 분석의 결과 아래와 같이 지시자, 식별자, 연산자, 값 등으로 정리됨

https://www.youtube.com/watch?v=edZfw9Yp7h4

 

3. 코드 최적화 code optimization

- 실행 공간을 절약하거나, 사용하지 않는 변수 제거하는 등 작업 수행

- 아래의 그림은 공간 낭비를 줄여주는 최적화 예시

https://atadiat.com/en/e-application-note-tips-tricks-optimize-c-code/

 

 

4. 메모리 테이블화 (심볼 테이블)

- 코드에 존재하는 변수들을 읽고 저장하기 위해 메모리 필요. -> 메모리 주소와 변수 명을 연결

 => 심볼 테이블 작성 : 해당 변수가 어느 메모리를 사용하는가?

- 심볼 테이블은 변수들을 ID로 관리. 변수들은 고유의 수납장 번호(이름을 갖고 있음)

 

https://victorydntmd.tistory.com/241

 

 

5. 구문 분석 syntax analysis

- 구문 syntax의 의미 : 단어들이 모여서 만든 의미

 => 코드가 언어의 문법을 따르는지 분석. 구문 나무 syntax tree 사용

- 구문 나무 사용 이유 : 명령어와 변수 구분이 편하고, 어셈블리어로 변환이 쉬움

- 아래의 그림은 구문 나무를 이용하여 명령어와 데이터 정리 형태를 보여줌

http://chirucprogvideos.blogspot.com/2015/06/compiler-and-interpreter.html

 

- 단어 분석과 구문분석의 결과 예시

https://homoefficio.github.io/2019/01/31/Back-to-the-Essence-Java-%EC%BB%B4%ED%8C%8C%EC%9D%BC%EC%97%90%EC%84%9C-%EC%8B%A4%ED%96%89%EA%B9%8C%EC%A7%80-1/

 

 

 

6. 어셈블리어 명령어 치환

- 구문 분석과정에서 명령어와 데이터가 구분됨

 => 데이터는 심볼테이블 ID(주소), 명령어는 어셈블러로 치환하자

 

7. 어셈블리어 완성

- 데이터들을 실제 메모리로 할당

 

8. 완성된 어셈블리어로 기계어 생성

- 어셈블리를 이용해서 기계어 작성

https://www.slideserve.com/barny/assembly-machine-language

 

300x250

+ Recent posts