오늘 어디 강의에서 C언어에서 기계어 까지 변환 되는 과정을 직접 실습해 보라고 하셨는데
나도 어셈블리어랑 북치고 장구치고 다 해봤지만 전처리, 링크 과정을 안봐서 흥미를 가지고 실습을 했다.
먼저 C언어가 실행파일 까지 되는 과정은 이러하다
1. 전처리 (Preprocessing)
2. 컴파일 (Compilation)
3. 어셈블 (Assembly)
4. 링킹 (Linking)
먼저 실습하기 전 코드는 이렇다
// complier.c
#include "stdio.h"
int main(){
printf("Hello WhiteHat School");
return 0;
}
이 코드로 모든 과정을 체험해 보자
1. 전처리
먼저 전처리 과정이다
gcc -E complier.c -o complier.i
앞서 전처리(preprocessing) 이라는 과정은 컴파일 과정의 첫번째로 수행되는 단계다.
실제 컴파일을 수행하기 전 소스 코드에 대한 여러 변환 작업을 수행한다.
여러가지 변환 작업은 다음과 같다.
1.매크로 정의
예시:
#define PI 3.14159
이런식으로 매크로를 정의하고 이름이 소스코드 내에서 발견 될 때 이름을 정의된 값이나 코드로 대체한다
2. 파일 포함
예시:
#include <string.h>
이 과정은 주로 include한 헤더 파일을 현재 소스에 포함하는 작업을 주로 수행한다.
3. 조건부 컴파일
#if, #ifdef, #ifnndef, #elif, #else와 같은 지시문을 사용하여 특정 조건에 따라 코드를 포함하거나 제외 한다.
이를 통해 다양한 상황에 맞게 코드를 조건부로 컴파일 할 수 있다
4. 코멘트 제거
전처리기는 소스 코드의 코멘트(주석)를 제거하여 최종 소스코드에서 코멘트가 없도록 한다.
5. 매크로 함수 확장
함수와 유사한 형태의 매크로를 정의하고 사용하게 할 수 있다.
6. 문자열화
# 연산자를 사용하여 매크로 인수를 문자열로 변환한다.
좀 길지만 전처리의 과정을 여러 단계로 나누었다.
그리고 전처리한 파일 complier.i를 집적 열어 보자
뭔가 좀 많아 보인다. 이게 전부 파일 포함, 매크로 정의로 인해 코드가 뻥튀기 된 것 뿐이다.
2. 컴파일
전처리된 소스 코드를 컴파일러에 의해 어셈블리 코드로 변환된다.
컴파일러는 C 코드의 구문과 의미를 분석하여 해당 아키텍처의 어셈블리 언어로 변환한다.
gcc -S complier.i -o complier.s
gcc 코드는 이러하다 그리고 이 파일을 집적 확인하자
리버싱이 주 분야인 나한테는 꽤나 친숙하다.
그리고 컴파일이라는 과정과 단계를 세부적으로 나누면 이렇게 된다.
3. 어셈블(Assembly)
gcc -c complier.s -o complier.o
이 과정을 통해 작성된 어셈블리어 언어의 소스 코드를 기계어로 변환하는 과정을 말한다. 어셈블리 언어는 기계어에 가까운 저수준 프로그래밍 언어로 만들어져 있다. 아키텍쳐 마다 자신만의 어셈블러와 기계어 코드가 존재한다
이젠 cat으로는 알아보지 못하는 수준으로 되어 버렸다.
4. 링킹 (Linking)
여러 오브젝트 파일과 라이브러리는 링커에 의해 하나의 실행 파일로 결합된다.
링커는 각 오브젝트 파일의 기호(Sysbol)을 해석하여 참조가 완결된 실행 가능한 바이너리를 생성 한다.
결과물은 실행 가능한 프로그램이며 UNIX 계열의 OS에서는 ELF파일 Window에서는 PE 파일 형식으로 생성 된다.
이제 cat은 의미가 없으니 objdump이라는 명령어로 살펴보자
리버싱을 주로 하는 사람으로서 되게 좋은 경험이 되었다
'컴퓨터' 카테고리의 다른 글
[NOOBHACK] cmd 사용 방법 (0) | 2023.10.27 |
---|---|
[NOOBHACK] GDB를 통한 언더플로우 관찰 (0) | 2023.09.13 |
[NOOBHACK] GPU의 원리 (1) | 2022.10.18 |
[NOOBHACK] CPU의 작동 원리 (1) | 2022.10.17 |