프로그래밍 언어 = 고급언어(high-level language) e.g. JAVA, C, Python, etc.
컴퓨터 언어 = 기계 언어(machin language) e.g. 0, 1
개발자가 작성한 프로그래밍 언어를 컴퓨터가 해석 할 수 있도록 컴퓨터 언어로 변환시켜주는 역할을 Compiler가 합니다.
컴파일 과정은 4가지 단계(전처리 과정-컴파일 과정-어셈블리 과정-링킹 과정)로 나누어 집니다. 이 4가지 단계를 묶어서 컴파일 과정 또는 빌드 과정이라고 부르기도 합니다.
전처리기(Preprocessor)를 통해 소스코드 파일(*.c)을 전처리된 파일(*.i)으로 변환하는 과정입니다.
컴파일러(Compiler)를 통해 전처리된 파일(*.i)을 어셈블리어 파일(*.s)로 변환하는 과정입니다.
컴파일러는 프론트엔드-미들엔드-백엔드 단계로 구성되어 있습니다.
1. 프론트엔드(Front-end)
프론트 엔드에서는 언어 종속적인 부분을 처리합니다.
소스코드가 해당 언어로 올바르게 작성되었는지 확인(어휘, 구문, 의미분석)합니다.
2. 미들엔드(Middle-end)
미들엔드는 아키텍쳐 비종속적인 최적화를 수행합니다.
CPU 아키텍쳐가 무엇이든(e.g. ARM, x86, etc.) 상관없이 할 수 있는 최적화입니다.
3. 백엔드(Back-end)
백엔드는 아키텍쳐 종속적인 최적화를 수행합니다.
아키텍쳐 특성에 따라 최적화를 수행합니다. 같은 기능을 수행하는 명령이어도 CPU 아키텍쳐별로 더욱 효율적인 명령어로 대체하여 성능을 높이는 작업 등을 예로 들 수 있습니다.
어셈블러(Assembler)를 통해 어셈블리어 파일(*.s)을 오브젝트 파일(*.o)로 변환하는 과정입니다.
사람이 알아볼 수 없는 기계어로 작석된 코드를 오브젝트 코드라고 부릅니다.
그리고 오브젝트 코드로 구성된 파일을 오브젝트 파일이라고 하며, 오브젝트 파일은 특정한 파일 포맷을 가집니다.
링커(Linker)를 통해 오브젝트 파일(*.o)을 묶어 실행 파일로 만드는 과정입니다.
이 과정에서 오브젝트 파일들과 프로그램에서 사용하는 라이브러리 파일들을 링크하여 하나의 실행 파일로 만듭니다.
GNU 컴파일러 모음 (GNU Compiler Collection)은 GNU 프로젝트의 일환으로 개발되어 널리 쓰이고 있는 컴파일러 입니다.
// 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
GNU 소프트웨어 시스템을 위한 기본 디버거입니다.
GDB같은 디버거의 목적은 다른 프로그램 수행 중에 그 프로그램 내부에서 무슨 일이 일어나고 있는지 혹은 프로그램이 잘못 실행되었을 때 무슨 일이 일어나고 있는지 보여주는 것입니다. GDB는 C, C++,etc. 로 짠 프로그램을 디버그 할 수 있습니다.
일반적으로 Linux에서는 C 또는 C++프로그램을 컴파일 하기위해 터미널 창에 아래와 같은 명령어를 입력합니다.
$ gcc test.c // c언어 컴파일
$ g++ test.c // c++언어 컴파일
하지만 위와 같은 명령어는 프로그램 소스파일을 실행 파일로 만드는 명령어로서 gdb로는 돌릴 수 있는 파일이 아닙니다.
gdb로 돌리기 위해서는 gcc명령어에 -g 옵션을 추가해야 합니다.
$ gcc -g test.c
$ g++ -g test.c
// 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
// 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
// 프로그램 수행(재시작)
(gdb) r
(gdb) run
// arg1과 arg2를 인자로 프로그램 수행
(gdb) r [arg1][arg2]
(gdb) run [arg1][arg2]
// 프로그램 수행종료
(gdb) k
(gdb) kill
// 오류가 발생한 함수를 역으로 찾아감
(gdb) bt
(gdb) backtrack
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 : 임시 중단점을 사용하는 것으로 한 번만 설정되며, 그 이후에는 삭제됨
1) condition 2 var == 0 : 고유번호가 2번인 브레이크 포인트에 var변수가 0일 때 동작하라고 설정
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 : 모든 브레이크 포인트 지움
1) info b : 현재 설정된 브레이크 포인트의 정보를 보여줌
2) 방향키 Up/Down : 방향키 Up/Down을 누르면 히스토리 기능을 제공
3) info br + TAB : info br로 시작하는 키워드가 히스토리에 있다면 뿌림
4) info TAB + TAB : info 뒤에 올 수 있는 인자 리스트를 보임
5) TAB + TAB : 현재 사용 가능한 모든 명령어 리스트를 보임
1) disable 2 : 고유번호 2번인 브레이크 포인트 비활성화
2) enable 2 : 고유번호 2번인 브레이크 포인트 활성화
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 : 현재의 인스트럭션을 수행, 함수 호출 시 내부로 들어가지 않는다.
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 : 레지스트 값 전체를 한 번에 확인
1) p lval = 1000 : 변수값 확인 이외에는 설정도 가능