컴퓨터 시스템 7장-링커(Linking) 1-2
2025. 4. 19. 10:24ㆍ개념 공부
7.6 링커는 여러 심볼을 어떻게 병합할까?
링커는 여러 개의 .o 파일을 하나의 실행 파일로 만들 때, 같은 이름의 심볼이 여러 파일에 있을 수 있다는 걸 고려해!
그래서 심볼의 우선순위 (강한/약한)을 기준으로 어떤 걸 쓸지 판단해.
정적 라이브러리란?
.a확장자를 가진 아카이브 파일- 여러 개의
.o파일을 묶은 것 ar명령어로 생성
ar rcs libfoo.a foo1.o foo2.o
r: 교체c: 생성s: 심볼 테이블 추가
gcc -L. -o main main.o -lfoo
-L.: 현재 디렉토리에서 라이브러리 검색-lfoo:libfoo.a사용
매우 중요한 주의점
- 링커는 왼쪽 → 오른쪽 순서로 처리!
gcc -lfoo main.o ❌ 링크 실패
gcc main.o -lfoo ✅ 올바른 순서
| 항목 | 설명 |
|---|---|
| 정적 라이브러리 | .a 확장자, 여러 .o 묶음 |
| 생성 도구 | ar rcs libfoo.a ... |
| 링크 명령 | gcc main.o -lfoo |
| 특징 | 필요한 .o만 꺼내 링크 |
| 주의 | main.o → -lfoo 순서 중요 |
7.8 실행 가능한 오브젝트 파일 (Executable Object File)
- 링커가
.o파일들을 합쳐 만든 최종 실행 파일 - 보통
a.out,prog,.exe등으로 생성됨
ELF 구조
┌────────────────────────────┐
│ ELF Header │ ← 진입점 등 정보
├────────────────────────────┤
│ Program Header Table │ ← 로딩 정보
├────────────────────────────┤
│ .text (.init 포함) │ ← 실행 코드
├────────────────────────────┤
│ .rodata │ ← 상수 문자열 등
├────────────────────────────┤
│ .data │ ← 초기값 있는 전역 변수
├────────────────────────────┤
│ .bss │ ← 초기값 없는 전역 변수
├────────────────────────────┤
│ .symtab, .debug │ ← 심볼 및 디버깅 정보
└────────────────────────────┘
실행 시
.text + .rodata→ 읽기/실행 세그먼트.data + .bss→ 읽기/쓰기 세그먼트
로딩 과정 (7.9)
- 디스크에서 실행파일 읽음
- ELF 헤더 분석
- 세그먼트들을 메모리에 배치
- Entry Point로 점프 (보통
_start()) →main()호출
실행 중 메모리 구조 (x86-64)
주소 ↓ 낮음
─────────────────────
코드 세그먼트 (.text)
읽기 전용 데이터 (.rodata)
초기화된 데이터 (.data)
초기화 안된 데이터 (.bss)
힙 영역 (malloc)
[ 중간 공간 ]
공유 라이브러리
스택 (위 → 아래 성장)
─────────────────────
주소 ↑ 높음
- ASLR로 인해 주소는 매 실행마다 달라질 수 있음 (보안)
7.11 런타임 공유 라이브러리 로딩
질문: 실행 중에 .so 파일을 불러와 사용할 수 있을까?
➡ 가능함! dlopen, dlsym, dlclose 함수 사용 (<dlfcn.h>)
실전 예시
- DLL 업데이트
- 웹서버 동적 처리
- 플러그인 시스템
| 함수 | 설명 |
|---|---|
dlopen() |
라이브러리 열기 |
dlsym() |
함수 주소 얻기 |
dlclose() |
라이브러리 닫기 |
dlerror() |
에러 메시지 확인 |
7.12 위치 독립 코드 (PIC)
문제: 공유 라이브러리는 어디든 로드될 수 있는데, 주소가 고정돼 있지 않음
해결 방법 👉 PIC + PLT + GOT
| 이름 | 설명 |
|---|---|
| PLT | 함수 호출을 위한 중간 점프 테이블 |
| GOT | 주소 테이블 (함수/데이터의 실제 주소 저장) |
| RIP-relative | 현재 명령어 위치 기준으로 접근 (x86-64 특징) |
printf() 호출 흐름
call printf@PLT실행- → PLT는 GOT의
printf주소를 참조 - → 처음엔 동적 링커 호출, 이후엔 실제
printf주소 저장
라이브러리 인터포지셔닝이란?
실행 중에 공유 라이브러리 함수 호출을 '가로채서'
내가 만든 함수(wrapping function)가 먼저 실행되게 만드는 기술이야!
대표적인 예: malloc(), free() 같은 함수 대신 my_malloc()을 실행시키는 경우
주요 사용 목적
- 함수 호출 로그 추적 / 모니터링
- 성능 측정 및 최적화
- 디버깅
- 라이브러리 함수 기능 변경 (ex: 고속 메모리 할당기)
인터포지셔닝 3가지 방식
① 컴파일 타임 인터포지셔닝
- 전처리기(
#define)를 이용해서 함수 호출 자체를 바꿔치기함 - 함수를 대체할 헤더 파일을 만들어 사용
#define malloc(size) mymalloc(size)
컴파일할 때 함수 이름이 아예 바뀌는 방식
gcc -DCOMPILETIME -c mymalloc.c
gcc -I. -o prog prog.c mymalloc.o
특징
- 간단하고 제어 쉬움
- 하지만 소스코드 수정 및 재컴파일 필요
② 링크 타임 인터포지셔닝
--wrap옵션을 사용해서 링커가malloc → __wrap_malloc으로 심볼 교체- 내가 만든
__wrap_malloc()이 호출되고, 진짜 함수는__real_malloc()로 호출 가능
gcc -Wl,--wrap,malloc -Wl,--wrap,free -o prog prog.o mymalloc.o
특징
- 소스코드 수정 없이도 가능
- 컴파일할 때 링커 옵션 필요
예시 함수 코드
// mymalloc.c
void *__wrap_malloc(size_t size) {
printf("[LOG] malloc called with size %zu\n", size);
return __real_malloc(size);
}
③ 런타임 인터포지셔닝 (LD_PRELOAD)
- 가장 강력하고 유연한 방법!
LD_PRELOAD환경변수를 이용해서 공유 라이브러리를 먼저 로딩- 내가 만든
malloc()이나free()가 먼저 호출됨
gcc -shared -fpic -o mymalloc.so mymalloc.c -ldl
LD_PRELOAD=./mymalloc.so ./myprog
특징
- 실행 파일 수정 불필요!
- 동적 링커가 내가 만든 .so를 먼저 로딩함
예시 함수 코드
// mymalloc.c
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
void *malloc(size_t size) {
static void *(*real_malloc)(size_t) = NULL;
if (!real_malloc)
real_malloc = dlsym(RTLD_NEXT, "malloc");
printf("[HOOKED] malloc(%zu)\n", size);
return real_malloc(size);
}
실행 방법
LD_PRELOAD=./mymalloc.so ./myprog
작동 원리 정리
- 내가 만든 .so 파일 안에
malloc(),free()등을 재정의 LD_PRELOAD로 이 파일을 먼저 로딩시킴- 프로그램이 해당 함수를 호출하면 → 내 함수가 먼저 실행됨
- 그 안에서
dlsym()으로 진짜 함수 주소를 얻어 다시 호출 가능
비교 요약
| 방식 | 설명 | 장점 | 단점 |
|---|---|---|---|
| 컴파일 타임 | 전처리기 이용 함수 이름 바꿈 | 간단함 | 소스코드 수정 필요 |
| 링크 타임 | --wrap 옵션으로 심볼 교체 | 소스 수정 없이 사용 가능 | 링커 옵션 필요 |
| 런타임 (LD_PRELOAD) | 실행 시 동적 링커가 먼저 내 .so 로딩 | 가장 유연, 코드 수정 불필요 | 환경변수 사용 필요 |
활용 예시
- 성능 분석기: malloc/free 호출 시간 측정
- 메모리 누수 추적: 호출 로그를 남겨서 추적
- 보안 검사기: 특정 함수의 인자 값을 검사
- 게임 치트 방지: 의심 함수 감시
즉, 프로그램을 건드리지 않고 외부에서 제어하거나 분석하고 싶을 때 매우 강력한 기술!
'개념 공부' 카테고리의 다른 글
| 컴퓨터 네트워킹 & 소켓 인터페이스 (0) | 2025.05.07 |
|---|---|
| 컴퓨터 시스템 8장 시그널 (0) | 2025.04.21 |
| 컴퓨터 시스템 7장-링커(Linking) 1-1 (0) | 2025.04.19 |
| 포인터 (0) | 2025.04.14 |
| 컴퓨터 시스템에서의 가상화 (1) | 2025.04.12 |