1.3 It Pays to Understand How Compilation Systems Work
컴파일 시스템이 어떻게 작동하는지 이해하는 것이 중요하다.
간단한 프로그램인 hello.c에서는 컴파일 시스템이 올바르고 효율적인 기계어 코드를 생성한다고 믿고 사용할 수 있습니다.
하지만 프로그래머가 컴파일 시스템이 어떻게 작동하는지 이해해야 하는 중요한 이유들이 있습니다.
프로그램 성능 최적화
현대의 컴파일러는 보통 좋은 코드를 생성하는 고도화된 도구들입니다.
프로그래머로서 우리는 효율적인 코드를 작성하기 위해 컴파일러의 내부 작동 방식을 세세하게 알 필요는 없습니다.
하지만 우리의 C 프로그램에서 좋은 코딩 결정을 내리기 위해서는, 기계 수준의 코드와 컴파일러가 다양한 C 문장을 어떻게 머신 코드로 변환하는지에 대한 기본적인 이해가 필요합니다.
최적화 결정들
- switch 문이 if-else 문의 연속보다 항상 효율적인가?
- 함수 호출에서 발생하는 오버헤드는 얼마인가?
- while 루프가 for 루프보다 더 효율적인가?
- 포인터 참조가 배열 인덱스보다 더 효율적인가?
- 참조로 전달된 인수 대신 로컬 변수에 합산하면 왜 루프가 그렇게 더 빨리 실행되는가?
- 산술 표현식에서 괄호를 단순히 재배열하는 것만으로 함수가 어떻게 더 빨리 실행될 수 있는가?
3장에서는 x86-64를 소개합니다. 이는 최근 Linux, MacOS, Windows 컴퓨터들에서 사용되는 64비트 프로세서 아키텍처입니다.
해당 장에서는 컴파일러가 다양한 C 언어 구성 요소를 x86-64 아키텍처에 맞는 기계어로 어떻게 변환하는지 설명합니다.
5장에서는 C 프로그램의 성능을 조정하는 방법을 배울 것입니다. 이를 위해 C 코드에 간단한 변환을 적용하여 컴파일러가 더 잘 작업을 수행하도록 돕는 방법을 다룹니다.
6장에서는 메모리 시스템의 계층적 특성, C 컴파일러가 데이터 배열을 메모리에 어떻게 저장하는지, 그리고 이 지식을 C 프로그램이 어떻게 활용하여 더 효율적으로 실행할 수 있는지에 대해 배울 것입니다.
링크 시간 오류 이해하기
우리의 경험에 따르면, 링커의 동작과 관련된 프로그래밍 오류 중 일부는 가장 당혹스러운 오류입니다. 특히 대형 소프트웨어 시스템을 구축할 때 이런 오류가 자주 발생합니다.
링크 시간 오류들에 대한 질문
- 링커가 참조를 해결할 수 없다고 보고할 때, 그 의미는 무엇일까요?
- 정적 변수와 전역 변수의 차이는 무엇일까요?
- 다른 C 파일에 동일한 이름의 전역 변수를 두 개 정의하면 어떻게 될까요?
- 정적 라이브러리와 동적 라이브러리의 차이는 무엇일까요?
- 명령줄에서 라이브러리를 나열하는 순서가 왜 중요한가요?
- 그리고 가장 무서운 것, 왜 일부 링커 관련 오류는 실행 시간에만 나타나는가요?
이러한 종류의 질문에 대한 답은 7장에서 배울 것입니다.
보안 허점 피하기
수년간 버퍼 오버플로우 취약점은 네트워크와 인터넷 서버에서 큰 보안 문제를 일으켰습니다.
이런 취약점이 생기는 이유는, 많은 프로그래머들이 신뢰할 수 없는 출처에서 오는 데이터의 양과 형태를 신중하게 제한해야 한다는 중요성을 인식하지 못하기 때문입니다.
보안 프로그래밍을 배우는 첫 번째 단계는 프로그램 스택에 데이터와 제어 정보가 어떻게 저장되는지 그 결과를 이해하는 것입니다.
우리는 스택 규칙과 버퍼 오버플로우 취약점을 3장에서 어셈블리 언어 공부의 일환으로 다룰 것입니다.
또한 프로그래머, 컴파일러, 운영 체제가 공격의 위협을 줄이는 데 사용할 수 있는 방법들에 대해서도 배울 것입니다.
정리
hello.c와 같은 간단한 프로그램에서는 컴파일 시스템이 올바르고 효율적인 기계어 코드를 생성한다고 믿고 사용할 수 있습니다. 하지만 프로그래머는 컴파일 시스템이 어떻게 작동하는지 이해해야 할 중요한 이유들이 있습니다.
- 프로그램 성능 최적화
- 현대의 컴파일러는 일반적으로 좋은 코드를 생성하는 고도화된 도구들입니다.
프로그래머는 컴파일러의 내부 작동 방식을 세세하게 알 필요는 없지만, 좋은 코딩 결정을 내리기 위해서는 기계 수준의 코드와 컴파일러가 C 문장을 어떻게 머신 코드로 변환하는지에 대한 기본적인 이해가 필요합니다.
- 현대의 컴파일러는 일반적으로 좋은 코드를 생성하는 고도화된 도구들입니다.
- 기계어와 컴파일러의 변환 과정
- 3장에서는 x86-64 아키텍처를 소개합니다. 이 아키텍처는 최근 Linux, MacOS, Windows 컴퓨터에서 사용되는 64비트 명령어 집합입니다. 컴파일러가 다양한 C 언어 구성 요소를 이 x86-64 아키텍처에 맞는 기계어로 변환하는 과정을 설명합니다.
5장에서는 C 프로그램 성능 조정 방법을 다룹니다. 이를 통해 컴파일러가 더 잘 작업을 수행하도록 돕는 방법을 배웁니다.
6장에서는 메모리 시스템의 계층적 특성과 C 컴파일러가 데이터를 메모리에 어떻게 저장하는지, 그리고 이 지식을 어떻게 C 프로그램이 효율적으로 실행될 수 있게 활용할지 배우게 됩니다.
- 3장에서는 x86-64 아키텍처를 소개합니다. 이 아키텍처는 최근 Linux, MacOS, Windows 컴퓨터에서 사용되는 64비트 명령어 집합입니다. 컴파일러가 다양한 C 언어 구성 요소를 이 x86-64 아키텍처에 맞는 기계어로 변환하는 과정을 설명합니다.
- 링크 시간 오류 이해하기
- 링커의 동작과 관련된 오류는 매우 당혹스러운 오류일 수 있습니다. 특히 대형 소프트웨어 시스템을 구축할 때 자주 발생합니다. 이러한 링크 시간의 오류들은 7장에서 배울 것입니다.
- 보안 허점 피하기
- 3장에서는 스택 규칙과 버퍼 오버플로우 취약점을 다루고, 프로그래머, 컴파일러, 운영 체제가 공격을 줄이는 방법들을 배울 것입니다.