gcc 컴파일

Janice._.oooh·2022년 3월 14일
1

리눅스

목록 보기
1/3
post-thumbnail

컴파일러(Compiler)란?


프로그래밍 언어 = 고급언어(high-level language)       e.g. JAVA, C, Python, etc.
컴퓨터 언어 = 기계 언어(machin language)       e.g. 0, 1

개발자가 작성한 프로그래밍 언어를 컴퓨터가 해석 할 수 있도록 컴퓨터 언어로 변환시켜주는 역할을 Compiler가 합니다.



컴파일 과정



컴파일 과정은 4가지 단계(전처리 과정-컴파일 과정-어셈블리 과정-링킹 과정)로 나누어 집니다. 이 4가지 단계를 묶어서 컴파일 과정 또는 빌드 과정이라고 부르기도 합니다.


1. 전처리(Pre-processing) 과정

전처리기(Preprocessor)를 통해 소스코드 파일(*.c)전처리된 파일(*.i)으로 변환하는 과정입니다.

대표적인 작업)

  1. 주석 제거
  2. 헤더 파일 삽입: #include 지시문을 만나면 해당하는 헤더 파일을 찾아 헤더 파일에 있는 모든 내용을 복사해서 소스코드에 삽입합니다. 즉, 헤더 파일은 컴파일에 사용되지 않고 소스파일 내에 전부 복사 됩니다. 헤더 파일에 선언된 함수 원형은 후에 링킹 과정을 통해 실제로 함수가 정의되어있는 오브젝트 파일과 결합합니다.
  3. 매크로 치환 및 적용: #define 지시문에 정의된 매크로를 저장하고 같은 문자열을 만나면 #define된 내용으로 치환합니다. 즉, 매크로 이름을 찾아서 정의한 값으로 전부 바꿔줍니다.

2. 컴파일(Compilation) 과정

컴파일러(Compiler)를 통해 전처리된 파일(*.i)어셈블리어 파일(*.s)로 변환하는 과정입니다.

컴파일러는 프론트엔드-미들엔드-백엔드 단계로 구성되어 있습니다.

1. 프론트엔드(Front-end)
프론트 엔드에서는 언어 종속적인 부분을 처리합니다.
소스코드가 해당 언어로 올바르게 작성되었는지 확인(어휘, 구문, 의미분석)합니다.

2. 미들엔드(Middle-end)
미들엔드는 아키텍쳐 비종속적인 최적화를 수행합니다.
CPU 아키텍쳐가 무엇이든(e.g. ARM, x86, etc.) 상관없이 할 수 있는 최적화입니다.

3. 백엔드(Back-end)
백엔드는 아키텍쳐 종속적인 최적화를 수행합니다.
아키텍쳐 특성에 따라 최적화를 수행합니다. 같은 기능을 수행하는 명령이어도 CPU 아키텍쳐별로 더욱 효율적인 명령어로 대체하여 성능을 높이는 작업 등을 예로 들 수 있습니다.


3. 어셈블리(Assembly) 과정

어셈블러(Assembler)를 통해 어셈블리어 파일(*.s)오브젝트 파일(*.o)로 변환하는 과정입니다.

오브젝트 파일(Object File)이란?

사람이 알아볼 수 없는 기계어로 작석된 코드를 오브젝트 코드라고 부릅니다.
그리고 오브젝트 코드로 구성된 파일을 오브젝트 파일이라고 하며, 오브젝트 파일은 특정한 파일 포맷을 가집니다.

  • Windows: PE(Portable Executable)
  • Linux: ELF(Executable and Linkin Format)

4. 링킹(Linking) 과정

링커(Linker)를 통해 오브젝트 파일(*.o)을 묶어 실행 파일로 만드는 과정입니다.

이 과정에서 오브젝트 파일들과 프로그램에서 사용하는 라이브러리 파일들을 링크하여 하나의 실행 파일로 만듭니다.



gcc 컴파일러란?


GNU 컴파일러 모음 (GNU Compiler Collection)은 GNU 프로젝트의 일환으로 개발되어 널리 쓰이고 있는 컴파일러 입니다.



gcc 컴파일


gcc 옵션

// example_gcc.c
#include <stdio.h>

int main() {
    printf("Hello GCC\n");
    return 0;
}

$ gcc example_gcc.c    // 컴파일 수행 후에 링킹 과정을 거쳐 a.out 생성
$ ./a.out    // a.out 실행
Hello GCC

$ gcc -o [example_restult] example_gcc.c    // 아웃풋 파일의 이름을 지정
$ ./example_restult    // example_restult 실행
Hello GCC

$ gcc -c -o example_gcc.o example_gcc.c    // 오브젝트 파일 생성
$ ls
example_gcc.o example_gcc.c

$ gcc -o [example_restult] example_gcc.o    // 오브젝트 파일로 컴파일
$ ./example_restult
Hello GCC

// add_gcc.h
int Add(int a, int b);
// add_gcc.c
#include <stdio.h>
#include "add_gcc.h"

int Add(int a, int b) {
    return a+b;
}
// add_gcc2.c
#include <stdio.h>
#include "add_gcc.h"

int main() {
    printf("result:%d\n", Add(3,4));
    return 0;
}

$ gcc -c add_gcc.c    // 컴파일 수행 후, 목적 파일(add_gcc.o)생성

$ gcc -o [example_restult] add_gcc.o add_gcc2.c  // 목적 파일을 포함한 컴파일 수행
$ ./example_restult
result:7

gcc -o [example_restult] add_gcc.c add_gcc2.c  // 여러개 소스 파일 열거하여 컴파일
$ ./example_restult
result:7

$ gcc -o [example_result] add_gcc.c add_gcc2.c -I [header directory path]
// 옵션 I로 헤더파일이 위차한 디렉토리를 지정
$ ./example_restult
result:7

// macro_gcc.c
#include <stdio.h>

int main() {
#ifdef Defined
    printf("Hello Defined -> %d\n", Defined);
#else
    printf("Bye Defined\n");
#endif
    return 0;
}

$ gcc -o [example_result] macro_gcc.c
$ ./example_result
Bye Defined

$ gcc -o [example_result] -D Defined macro_gcc.c
$ ./example_result
Hello Defined -> 1

$ gcc -o [example_result] -D Defined=7 macro_gcc.c
$ ./example_result
Hello Defined -> 7



gcc -g / gdb 디버거


gdb(GNU Debugger)란?

GNU 소프트웨어 시스템을 위한 기본 디버거입니다.

GDB같은 디버거의 목적은 다른 프로그램 수행 중에 그 프로그램 내부에서 무슨 일이 일어나고 있는지 혹은 프로그램이 잘못 실행되었을 때 무슨 일이 일어나고 있는지 보여주는 것입니다. GDB는 C, C++,etc. 로 짠 프로그램을 디버그 할 수 있습니다.

gdb를 하기 위한 컴파일 방법

일반적으로 Linux에서는 C 또는 C++프로그램을 컴파일 하기위해 터미널 창에 아래와 같은 명령어를 입력합니다.

$ gcc test.c      // c언어 컴파일
$ g++ test.c     // c++언어 컴파일

하지만 위와 같은 명령어는 프로그램 소스파일실행 파일로 만드는 명령어로서 gdb로는 돌릴 수 있는 파일이 아닙니다.

gdb로 돌리기 위해서는 gcc명령어에 -g 옵션을 추가해야 합니다.

$ gcc -g test.c
$ g++ -g test.c


gdb 시작 및 종료

// gdbTest.c
#include <stdio.h>

int main() {
    printf("Hello GDB\n");
    return 0;
}

// gdb 시작
gdb [프로그램명]
gdb [프로그램명][core파일명]
gdb [프로그램명][실행중인프로세스pid]

$ gcc -g -o test gdbTest.c

// gdb 종료
1. q -> (gdb) q
2. ctrl + d -> (gdb) quit


gdb 옵션

1. 소스 찾아가기

// main 함수를 기점으로 소스의 내용이 출력
(gdb) list
(gdb) l

// 5행 주변의 소스가 출력
// 5행 주변의 +-5행까지 출력 -> 총 10행 출력
(gdb) list
(gdb) l

// func 함수의 소스를 출력
(gdb) list [func]
(gdb) l [func]

// .c 파일의 func 함수 부분을 출력
(gdb) list [*.c]:[func]
(gdb) l [*.c]:[func]

// .c 파일의 5행을 기준으로 출력
(gdb) list [*.c]:5
(gdb) l [*.c]:5

TIP)
기본 default 출력 행이 10으로 설정되어 있습니다.
해당 설정은 아래 명령어로 조정할 수 있습니다.

$ set listsize 30


2. 프로그램 실행 및 종료

// 프로그램 수행(재시작)
(gdb) r
(gdb) run

// arg1과 arg2를 인자로 프로그램 수행
(gdb) r [arg1][arg2]
(gdb) run [arg1][arg2]

// 프로그램 수행종료
(gdb) k
(gdb) kill


3. 역추적하기

// 오류가 발생한 함수를 역으로 찾아감
(gdb) bt
(gdb) backtrack


4. 중단점 사용하기 (break point, temporary breakpoint)

1) b func : func 함수에 브레이크 포인트 설정
2) b 10 : 10행에 브레이크 포인트 설정
3) b a.c:func : a.c파일의 func함수에 브레이크 포인트 설정
4) b a.c:10 : a.c파일의 10행에 브레이크 포인트 설정
5) b +2 : 현재 행에서 2개 행 이후 지점에 브레이크 포인트 설정
6) b -2 : 현재 행에서 2개 행 이전 지점에 브레이크 포인트 설정
7) *0x8049000 : 0x8049000 주소에 브레이크 포인트 설정(어셈블리로 디버깅 시 사용)
8) b 10 if var == 0 : 10행에 브레이크 포인트를 설정하되, var 변수 값이 0일 때 작동
9) tb : 임시 중단점을 사용하는 것으로 한 번만 설정되며, 그 이후에는 삭제됨

5. 중단점 설정하기 (condition)

1) condition 2 var == 0 : 고유번호가 2번인 브레이크 포인트에 var변수가 0일 때 동작하라고 설정

6. 중단점 삭제하기 (clear, delete)

1) cl func : func 함수의 시작 부분에 브레이크 포인트 지움
2) cl 10 : 10행의 브레이크 포인트 지움
3) delete 1 : 고유번호 1번의 브레이크 포인트를 지움
4) cl a.c:func : a.c 파일의 func함수의 브레이크 포인트 지움
5) cl a.c:10 : a.c 파일의 10행의 브레이크 포인트 지움
6) cl : 모든 브레이크 포인트 지움

7. 중단점 정보보기 (information)

1) info b : 현재 설정된 브레이크 포인트의 정보를 보여줌
2) 방향키 Up/Down : 방향키 Up/Down을 누르면 히스토리 기능을 제공
3) info br + TAB : info br로 시작하는 키워드가 히스토리에 있다면 뿌림
4) info TAB + TAB : info 뒤에 올 수 있는 인자 리스트를 보임
5) TAB + TAB : 현재 사용 가능한 모든 명령어 리스트를 보임

8. 중단점 비활성화, 활성화 하기 (enable, disable)

1) disable 2 : 고유번호 2번인 브레이크 포인트 비활성화
2) enable 2 : 고유번호 2번인 브레이크 포인트 활성화

9. 디버깅하기 (step, next, continue, until, finish, return, step instruction, next instruction)

1) s : 현재 출력된 행을 수행하고 멈추지만, 함수의 경우 함수의 내부로 들어가서 수행
2) s 5 : s를 5번 입력한 것과 동일
3) n : 현재 행을 수행하고 멈추지만, 함수의 경우 함수를 수행하고 넘어감
4) n 5 : n을 5번 입력한 것과 동일
5) c : 다음 브레이크 포인트를 만날 때까지 계속 수행
6) u : for 문에서 빠져나와서 다음 브레이크 포인트까지 수행한다.
7) finish : 현재 함수를 수행하고 빠져나감
8) return : 현재 함수를 수행하지 않고 빠져나감
9) return 123 : 현재 함수를 수행하지 않고 빠져나감, 단, 리턴 값은 123
10) si : 현재의 인스트럭션을 수행, 함수 호출 시 내부로 들어간다.
11) ni : 현재의 인스트럭션을 수행, 함수 호출 시 내부로 들어가지 않는다.

10. 변수 정보 보기 (info, print)

1) info locals : 현재 상태에서 어떤 지역변수들이 있으며, 값은 어떠한지를 알 수 있음
2) info variables : 현재 상태에서의 전역 변수 리스트를 확인할 수 있음
3) p lval : lval 값 확인
4) p func : func 함수의 주소 값 확인
5) p pt : pt가 구조체라면 구조체 주소 확인
6) p *pt : pt가 구조체라면 구조체 값 확인
7) p *pt : pt가 구조체라면 구조체 값 확인
8) info registers : 레지스트 값 전체를 한 번에 확인

11. 변수 값 설정

1) p lval = 1000 : 변수값 확인 이외에는 설정도 가능

12. 기타

https://mk28.tistory.com/134



Reference)

0개의 댓글