-
[2024.08.14] 컴파일 과정 파헤치지 01공부/TIL 2024. 8. 18. 23:45
이렇게 알아야 에러를 이해할 수 있다고?
개발을 시작하기 앞서 환경설정을 해보고, 이게 원하는데로 작동하는지 살펴보면서 정말 여러가지 에러들을 만나게 됩니다.
개발 초기에는 많은 사람들이 접해봐서 많은 자료가 있는 반면, 개발 중에 나는 몇몇 에러는 정말 stack overflow에도 잘 없거나 저랑 비슷하지만 다른 케이스의 문제라서 찾기 까다로운 경우도 여럿 있었습니다.
후자의 경우 깊이 파고들게 되면 결국 답을 찾긴 하는데 답을 올려준 사람도 이게 정확히 어떻게 해서 기인했는지 모르는 경우가 많아서 답답한 적도 많았습니다. 어떻게 기인했는지 설명해주시는 고마운 글을 찾았을 때는 해당 라이브러리나 언어의 작동방식의 특징에 의해서 기인해서 일반적인 개발 API 문서에서는 찾기 어려운 부분까지 설명해주시는 것을 볼 수 있었습니다.
때문에! 궁금해졌습니다. 이놈의 언어와 라이브러리가 구체적으로 즉, 컴퓨터라는 하드웨어가 어떻게 처리하는지 궁금해서 최근에 읽기 시시작한 것이 컴퓨터 밑바닥의 비밀이라는 책입니다.
https://www.yes24.com/Product/Goods/125299750?pid=123487&cosemkid=go17107581468846387
컴퓨터 밑바닥의 비밀 - 예스24
코드를 실행하면 컴퓨터 내부에서는 어떤 일이 벌어질까?운영 체제부터 CPU, 동기화, 입출력을 구현하는 원리까지,내 코드를 바꿔줄 컴퓨터 밑바닥의 비밀을 들여다보자!`어? 이 코드가 왜 돌아
www.yes24.com
이 책을 찾기 전에 정말 컴퓨터를 이루는 하드웨어가 자세하게 어떤것이 설명해주는 책을 한번 펼쳤다가 처음부터 이해하지 못할 말들이 난무해서 금방 덮었던 기억이 있어서 좀 더 개발자에게 필요한 내용들로 정리해둔 책이 어디 없을까 찾다가 발견한 책입니다. 사실 처음 고른 이유는 표지 디자인이 트렌디하고 제 취향이라 눈길을 끌었기 때문인데 내용도 제 취향인 것 같아서 읽어보게 되었습니다.
오늘 읽은 부분은 1.2장과 1.3 장 일부입니다.
1.2 컴퍼일러는 어떻게 작동하는 것일까?
컴퍼일러는 인간이 알아볼 수 있는 C, Python 등의 고수준 언어로 작성된 source file을 여러 과정을 거쳐 실행 파일 형태로 내보냅니다. 이 실행 파일은 컴퓨터가 그 중에서도 CPU가 직접 실행할 수 있는 기계 명령어로 번역된 것이죠. 때문에 컴파일러는 크게 보면 번역기이고 작게 보면 텍스트 처리 프로그램(text processe)인거죠.
토큰으로 쪼개기
컴파일러가 인간이 알아들을 수 있는 코드를 번역하기 위해 가장 먼저 수행하는 것은 각 코드를 잘게 쪼개어 토큰을 추출하는 거예요.
int a = 1;
위의 간단한 변수 선언문을 토큰으로 쪼갠 예시는 다음과 같습니다.
토큰 값 T_Keyword int T_Identifier a T_Assign = T_Int 1 T_Semicolon ; 토큰은 첫줄의 int가 키워드라는 것, 그 중에서도 int라는 키워드라는 추가 정보가 포함되어 있습니다. 이처럼 각 항목에 추가 정보를 결합한 것을 토큰이라고 합니다. 제가 이해하기로는 토큰은 코드가 의미할 수 있는 최소 단위라고 이해하고 넘어갔어요. 마치 데이터 정규화 작업과 비슷했습니다.
파싱
그리고 이렇게 쪼갠 토큰은 표현하고자하는 의미 즉, 코드의 맥락을 포함할 수 있어야 합니다. 쉽게 말해 문법을 규칙을 잘 지키고 있는지 검사할 필요가 있다는 뜻인데요. 아래 while 문을 예시로 설명되었습니다.
while (표현식) { 반복 내용 }
컴파일러가 while 키워드 토큰을 찾으면 다음 토큰은 (이 있어야 함을 알고 있는 상태로 기다리게 됩니다. 다음 키워드가 (가 아니라면 문법 오류(syntax error)를 보고하는 것입니다. ( 잘 와 있다면 다음 토큰이 bool 표현식이어야 한다는 것을 알고 기다립니다. 이어서 )과 {를 거치고 마지막 }를 만날 때까지 계속 기다리고 처리하는 과정을 반복하죠. 다음과 같은 짤처럼 구문에러를 발생 시키는 이유는 컴파일러는 다 구분하기 때문이죠.
이런 과정을 해석(pasing)이라고 하며, 컴파일러는 구문에 따라 한 글자도 놓치지 않고 꼼꼼하게 작업을 진행하죠. 컴파일러가 구문에 따라 해석해낸 내용은 트리로 표현하는 것이 적합한 방법입니다. 토큰을 해석하고 구문트리를 생성하는 전체 과정을 '구문 분석'이라고 부릅니다.
정리하자면 구문 분석 안에는 토크으로 쪼개고 파싱하는 과정이 포함된 것이죠.
의미 분석
구문 트리가 생성되고 나면 우리는 구문 트리에 이상이 없는지 확인해야 합니다. 정수 값에 문자열을 더하거나 비교 기호의 좌우에 있는 값의 형식이 다르면 안되는 것처럼요. 이 단계를 통과하면 프로그램에 이상이 없이 때문에 컴파일 오류가 없음이 증명됩니다. 이 과정을 의미 분석이라고 합니다.
중간 코드
의미 분석이 끝나면 컴파일러는 구문 트리를 탐색한 결과를 바탕으로 좀 더 다듬어진 형태인 중간 코드(Intermediate Representation Code, IR Code)를 생성합니다. 다음과 같이요
int a = 1; int b = 2; while (a < b) { b = b+1; }
a = 1 b = 2 goto B A : b = b - 1 B : if a < b goto A
위에는 예시 코드이고 아래는 이를 중간코드로 표현한 모습입니다. 어떤 경우에는 중간 코드에 추가적인 최적화가 진행되기도 합니다. 순환 구문 내 순환 상태와 관계없이 계산 가능한 값이 있다면, 이런 계산은 순환 구문 외부에서 먼저 진행 될 수 있도록 하는 등 말이죠.
코드 생성
이제 컴파일러는 중간 코드를 어셈블리어 코드로 변환하게 됩니다.
movl $0x1,-0x4(%rbp) // a=1 movl $0x2,-0x8(%rbp) // b=1 jmp B // B로 점프 A: subl $0x1,-0x8(%rbp) // b=b-1 B: movl -0x4(%rbp),%eax cmp -0x8(%rbp),%eax // a<b ? jl A // a<b이면 A로 점프
컴파일러는 앞의 과정을 거쳐 기계 명령어로 번역하면 해당 데이터를 대상 파일(object file)에 저장하게 됩니다.
그리고 우리는 웹사이트 하나를 만들 때 보통 하나의 파일에서 작업하지 않고 여러 파일에서 작업하게 되죠. 그리고 소스파일은 각각의 대상파일이 있습니다. 즉 대상 파일도 여러개가 있다는 것입니다. 하지만 저희가 원하는 것은 하나의 실행파일이죠. 이 여러 대상파일을 합쳐 주어야 합니다.
대상 파일을 병합하는 작업은 링크(link) 라는 매우 직관적인 이름의 과정을 통해 이루어집니다. 컴파일을 담당하는 프로그램의 이름이 컴파일러인 것과 마찬가지로, 링크를 담당하는 프로그램을 링커라고 합니다.
1.3 링커의 말할 수 없는 비밀
일반적으로 개발할 때 저희는 언어에서 기본으로 제공해주는 라이브러리부터 누군가가 만들어둔 라이브러리를 설치해서 사용하는 등 외부에서 제공되는 소스 코드를 자주 사용합니다. 그리고 이 라이브러리는 정적 라이브러리(static liabrary) 또는 동적 라이브러리(dynamic library) 형태로 제공되죠. 이 라이브러리들은 어떻게 내 프로젝트에 코드를 가져와 사용할 수 있을지 알아봅니다.
또 C/C++ 언어를 배우다 보면 마주치는 "undefined reference to ~"라는 오류를 어떻게 해결해야할지 이 링커를 이해하면 해결 할 수 있습니다.
링커가 일하는 방법
링커는 컴파일러처럼 일반적인 프로그램입니다. 압축 프로그램이 파일 여러 개를 하나의 압축 파일로 묶어 주는 것처럼, 컴파일러가 생성한 대상 파일 여러개를 하나로 묶어 하나의 최종 실행 파일을 생성해요. 링커는 컴파일러가 번역한 대상 파일을 한데 묶어 EXE나 ELF 파일 같이 실행파일을 구성합니다.
특정한 소스 파일에서 다른 모듈에 정의되어 있는 함수를 참조할 때, 컴파일하는 시점에는 함수가 어느 메모리 주소(memory addres)에 위치할지 정확히 알 수 없습니다. 따라서 컴파일러는 이 함수를 N으로 표시해 두고 넘어갑니다. 이후 링크 과정에서 링커가 이런 표시들을 확인하고 한데 모아 실행 파일을 생성하는 과정에서 함수의 정확한 주소를 확인하고, N을 실제 메모리 주소 대체하는 것이죠.
이 이후의 내용은 링크 과정을 더 자세하기 설명하는 부분으로 이어집니다. 출, 퇴근하면서 읽은 내용을 정리하는데 자꾸 졸려서 많은 내용을 나가진 못해서 간간히 정리할 이렇게 정리할 양만 읽게 되는것 같습니다ㅋㅋㅋㅋ
'공부 > TIL' 카테고리의 다른 글
[2024.08.28]퇴사 D-2 (2) 2024.08.29 [2024.08.23] 정적 라이브러리와 동적 라이브러리의 차이 (0) 2024.08.24 [2024.08.13] electron IPC 통신할 때 (0) 2024.08.16 [2023.09.19]git과 Legacy spring (0) 2023.09.19 [2023.08.30]제 1회 서울대학교 AI빅데이터 캠프 후기 (0) 2023.08.30