시험스포

ln

signal

until

컴파일 단계

 

gcc 다운로드

gcc --version
sudo apt install gcc

 

 

gcc 컴파일러

전처리 단계

전처리 지시문을 처리하는 단계

AI에서 전처리: 비정형 데이터를 정형화

 

nano hello.i 해보면 전처리 과정을 거쳐 자동으로 .i 파일이 작성된 것을 확인할 수 있다.

gcc -E hello.c -o hello.i ---> 전처리된 hello.i 파일 생성

 

컴파일 단계

전처리된 C 코드를 CPU가 이해할 수 있는 명령어에 더 가까운 어셈블리어로 바꾸는 단계

문법 검사, 중간코드 생성, 최적화, 어셈블리어 생성 수행

어셈블리어: CPU가 직접 실행할 수 있는 명령어(기계어)를 사람이 이해할 수 있도록 문자로 표현한 저수준 언어

 

어셈블 단계

어셈블리어 파일을 컴퓨터가 직접 실행가능한 기계어 명령어로 구성된 목적코드로 변환하는 단계

gcc -c hello.s -o hello.o

링크 단계

=링크 단계에서는 작성한 프로그램이 사용하는 다른 프로그램이나 라이브러리를 가져와서 연결한다.

대상파일을 지정하지 않으면 a.out으로 나오는데 실행 결과는 동일하다.

 

 

실행

 

각 단계에서 생성되는 중간파일들(.i, .s, .o)은 임시로 생성되며 자동으로 삭제된다.

gcc -save-temps hello.c -o hello  --> 명령어를 하면 중간파일이 유지된다.

중간 파일이 유지되는 것을 확인할 수 있다.

 

 

실습 -2개 파일 작성

gcc main.c hello.c -o hello

  • gcc 컴파일러로 main.c와 hello.c 둘 다 컴파일하고 링크하는 명령어
  • -o hello는 최종 실행파일 이름을 hello로 만든다는 뜻
  • 링크 과정에서 main()이 hello()를 찾을 수 있어야 하기 때문에, 둘을 같이 컴파일하고 링크해야함

 

gdb란

GNU Debugger의 줄임말

리눅스 환경에서 C, C++, 어셈블리어로 작성된 언어 디버깅하는 도구

 

2개 파일 생성 : gcc hello.c -o hello : 실행파일 hello가 생성되지만 디버깅 정보 포함 ㄴㄴ

gcc -g hello: 실행파일 a.out이 생성되며 디버깅 정보가 포함됨

 

 

gdb 실습

 

 

실습 - 코어덤프

p264

segmentation fault: 메모리에 접근하려고 할 때 허용되지 않은 메모리 접근

 

 

코어덤프 디버깅 순서

run: 프로그램을 GDB 안에서 실행. 죽는 지점에서 멈춤

bt: 죽은 이유를 확인할 수 있도록 backtrace(호출 스택) 출력

list: 죽은 부분 주변 코드를 보고 싶을때

gdb를 통해 16번째 줄이 문제인 것을 알 수 있음

*(volatile unsigned int*)(main+1) = 1;

 

  • main은 함수 포인터 (즉, 함수가 시작하는 메모리 주소를 가리킴)
  • main+1은 함수 주소에 1을 더한 것 → 말도 안 되는 메모리 주소
  • (volatile unsigned int*)로 강제로 포인터 변환하고 그 주소에 1을 쓰기 하려고 함
  • 프로그램의 코드 영역(text segment)에 쓰기를 시도한 거 Segmentation fault(세그멘테이션 오류) 발생!
int main()
{
    puts("hello");

    // *(volatile unsigned int*)(main+1) = 1;  ← 삭제!

    puts("world");
    return 0;
}

수정하고 gcc -g demo_SIGSEGV.c -o demo_SIGSEGV 다시 컴파일하고 ./demo_SIGSEGV 실행하면 오류 안남

 

 

dwarf

debugging With Attributed Record Formats

GCC, Clang 등 컴파일러가 생성라는 디버깅 심볼 형식

-g 옵션을 쓰면 컴파일러는 이 DWARF 정보를 바이너리에 포함

 

gcc -g -gdwarf-2 buggy.c

 

objdump: 컴파일 결과물을 디버깅하거나 내부 구조를 들여다볼 때 사용

 

dwarf 실습

 

 

help

gdb안에서

(gdb) help status

(gdb) status

(gdb)help list

(gdb)list

 

 

스택

backtrace

 

Defensive Code

예상하지 못한 잘못된 입력이나 상황에서 프로그램이 안전하게 동작하도록 코드를 작성하는 기법

 

scores3? -30 입력했더니 코드에 있는 assert(n >= 0); 에 걸려서 SIGABRT (abort) 신호로 죽음

assert를 무시하고(=비활성화하고) 디버깅하기 위해 -DNDEBUG 사용

gcc -g -DNDEBUG buggy.c -o buggy

 

gdb ./buggy
(gdb) run

assert에 안 걸리고 통과하는 거 확인 가능

 

break point

프로그램이 실행 중 특정 위치에 도달하면 자동으로 '멈추게' 하는 기능

 

[Inferior 1 (process 41912) exited normally]
(gdb) b sum
Breakpoint 1 at 0x5555555551e2: file buggy.c, line 22.
(gdb) run
Starting program: /home/veda/20250428/buggy 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
input 5 scores
scores1? 3
scores2? 232
scores3? 3
scores4? 2
scores5? 1

Breakpoint 1, sum () at buggy.c:22
22		int sum=0 ;			//TODO		//=0
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n)
  • (gdb) b sum → sum 함수 시작할 때 멈춰라
  • (gdb) run → 프로그램 시작
  • sum() 함수 도달 → 브레이크포인트 걸려서 멈춤
  • 현재 멈춘 코드: int sum = 0; 초기화하는 줄
  • 이제 next, step, continue 같은 걸 써서 계속 진행할 수 있음

 

문맥

현재 프로세스 또는 스레드가 실행되던 모든 정보의 스냅삿

 

 

툴 체인이란

소프트웨어 개발에 사용되는 프로그래밍 도구의 집합

종류: 네이티브, 크로스

 

cross 툴체인

 

QEMU 실습

QEMU는 가상 머신/에뮬레이터야
간단히 말하면, "다른 CPU를 흉내내서(에뮬레이션) 프로그램을 돌릴 수 있게 해주는 도구"

 

qemu가 할 수 있는 거 

  • 내 x86 PC에서 ARM 리눅스 실행하기
  • 내 PC에서 MIPS, RISC-V, PowerPC 같은 다른 CPU용 코드 실행
  • 임베디드 보드(라즈베리파이 등) OS 부팅 테스트
  • 리눅스 커널 부팅 실험
  • 크로스 컴파일한 프로그램 테스트 (ARM용 바이너리 실행 등)

 

원격 디버깅

디버깅 대상 프로그램이 로컬이 아닌 다른 시스템에서 실행 중일 때 로컬 개발 PC의 디버깅 도구를 통해 원격에서 디버깅을 수행하는 방식

sudo apt install gdbserver

왼쪽이 서버 오른쪽이 클라이언트

 

 

리눅스 라이브러리

정적 라이브러리 Static Library .a 컴파일할 때 프로그램 안에 코드를 복사해서 넣음. 실행 파일이 커짐. 실행 시 별도 파일 필요 없음.
공유 라이브러리 Shared Library .so 프로그램 실행할 때 링크해서 사용하는 라이브러리. 실행 파일은 작고, 여러 프로그램이 동시에 공유 가능.
표준 C 라이브러리 glibc (libc.so) .so C언어의 표준 함수 제공 (printf, malloc, open 등). 리눅스 시스템 필수 라이브러리.
수학 라이브러리 libm (libm.so) .so sin, cos, sqrt 같은 수학 함수 제공. (-lm 옵션으로 링크)
POSIX 스레드 라이브러리 libpthread (libpthread.so) .so 멀티스레드 프로그래밍 지원 (pthread_create, pthread_join 등).
동적 로딩 라이브러리 libdl (libdl.so) .so 프로그램 실행 중 동적으로 다른 라이브러리 로딩 (dlopen, dlsym 등).
실행 지원 라이브러리 ld-linux.so .so 프로그램 시작할 때 공유 라이브러리를 메모리에 로딩하고 연결하는 역할. (dynamic linker)
C++ 표준 라이브러리 libstdc++ (libstdc++.so) .so C++의 표준 기능 (iostream, vector, string 등)을 제공. gcc에 포함.
특수 목적 라이브러리 (ex: SSL, Zlib 등) .so, .a 암호화(OpenSSL), 압축(Zlib), 그래픽(OpenGL) 같은 특정 기능 지원 라이브러리.

 

소스코드
   ↓ (컴파일)
정적 라이브러리(.a) 포함
or
공유 라이브러리(.so) 링크
   ↓
실행 파일

 

 

공유 라이브러리 장점

1. 실행 파일 크기가 작아진다 라이브러리 코드를 복사하지 않고 연결만 하기 때문에, 실행파일 크기가 줄어든다.
2. 메모리를 절약할 수 있다 여러 프로그램이 같은 라이브러리를 메모리에서 "공유"해서, 메모리 사용량이 크게 줄어든다.
3. 유지보수가 쉽다 라이브러리만 업데이트하면, 그걸 사용하는 모든 프로그램이 자동으로 최신 버전을 쓸 수 있다. (프로그램 재컴파일 필요 없음)
4. 프로그램 배포가 가벼워진다 프로그램 자체에는 핵심 로직만 포함하고, 시스템에 설치된 공유 라이브러리를 이용할 수 있어서 배포 크기가 줄어든다.
5. 런타임 기능 확장이 가능하다 dlopen() 같은 함수를 이용하면 실행 중에 동적으로 라이브러리를 로딩할 수 있다. (플러그인 시스템 구현 가능)

 

 

 

정적 라이브러리 작성하기

ar은 목적파일들을 병합하여 라이브러리를 만들 때 사용하는 아카이브 유틸리티

.a라는 정적 라이브러리 파일을 생성

r 옵션은 아카이브에 파일을 추가하거나 교체

libmylib.a라는 이름으로 정적 라이브러리를 만들고, 그 안에 mylib.o를 포함

-o output: 생성될 실행파일 이름을 지정

-Lsearchdir 라이브러리를 찾을 디렉터리 경로를 추가

-lnamespec : libnamespec.a또는 libnamespec.so를 사용한다는 의미

lib 접두사와 .a또는 .so 확장자는 생략

 

 

경로 설정완

 

 

동적 라이브러리 사용하기

'임베디드' 카테고리의 다른 글

커널1  (0) 2025.05.26
임베디드 엔지니어 교과서 1-3정리  (0) 2025.05.01
라즈베리파이  (0) 2025.04.17