ELF, Executable and Linkable Format (재배치 가능 목적파일)

2025. 8. 8. 22:09·CS:APP

ELF란?

ELF (Executable and Linkable Format)
리눅스에서 사용되는 실행 파일, 목적 파일 (.o), 공유 라이브러리 (.so)의 표준 포맷

  • 목적: 프로그램을 효율적으로 연결(link), 실행(load) 하도록 정보 구조화
  • 사용처: 링커(ld), 로더(execve), 디버거(gdb)

구체적 설명

오브젝트 파일은 “반쪽짜리 실행파일”

주소가 확정되지 않았기 때문에 재배치가 가능하고, 링크 과정을 통해 최종 주소가 정해짐.


구조

ELF Header

  • ELF 파일임을 알리는 시작 지점
  • 파일 전체의 구조를 정의
  • 어떤 CPU용인지, 32비트/64비트인지, 실행파일인지 목적파일인지 등을 기록
| **섹션** | **설명** |
| --- | --- |
| .text | **기계어 코드**가 들어가는 곳 (함수 본체 등) |
| .data | **초기화된 전역/정적 변수** |
| .bss | **초기화되지 않은 전역/정적 변수** (int x;) → 실행 시 0으로 초기화됨 |
| .rodata | 읽기 전용 데이터 (ex: "hello" 문자열 상수) |

예: ELF64, x86-64, Type: REL (Relocatable)

코드 & 데이터 섹션

프로그램의 실질적 실행 내용을 구성

심볼 테이블 (.symtab) & 문자열 테이블 (.strtab)

  • .symtab에는 함수와 변수의 이름, 주소, 크기, 소속 섹션 같은 메타정보가 담김
  • 이름 자체는 .strtab이라는 문자열 테이블에 저장되고, .symtab이 인덱스로 참조함
int x = 10;  // → 심볼: 이름=x, 위치=.data, 크기=4바이트

링커와 디버거가 변수나 함수 이름을 이해하는 핵심 요소

재배치 정보 (.rel.text, .rela.text 등)

  • 아직 주소가 확정되지 않은 함수 호출/전역 변수 접근 등을 나중에 채워 넣기 위한 정보
  • .o 파일에는 주소가 확정되지 않으므로 이걸 통해 링커가 주소를 확정함
printf("hi");
// → printf의 실제 주소를 모름 → 링커가 이 위치에 진짜 주소를 채워줌

디버깅 정보 (선택적)

  • .debug_info, .debug_line, .line 등은 gdb 같은 디버거가 소스와 ELF를 연결할 때 사용
  • 변수 이름, 줄 번호, 파일 이름 등의 정보가 포함됨

필수는 아니지만, 디버깅을 할 때 매우 중요

섹션 헤더 테이블 (Section Header Table)

  • ELF 파일 내의 모든 섹션의 위치, 크기, 이름을 정의
  • 이걸 통해 readelf -S 같은 도구가 섹션을 찾아냄
  • 섹션 이름은 .shstrtab에 저장됨

한 장 요약

이름 역할 필수?
.text 함수 코드 저장 ✅
.data / .bss 전역 변수 저장 ✅
.rodata 상수 문자열 등 읽기 전용 데이터 ✅
.symtab / .strtab 함수/변수 이름과 메타데이터 ✅
.rel.* / .rela.* 주소 채워넣기 정보 ✅
.debug_*, .line 소스코드 정보 (gdb용) ⛔ 선택
.shstrtab 섹션 이름들 저장소 내부적으론 필수지만 학습 시는 간략화 가능

예시 (코드)

int g = 10;              // .data
int h;                   // .bss
const char *s = "hi";    // .rodata

int f() { return g + h; } // .text
  • .data : g = 10 → 값이 이미 지정됨
  • .bss : h → 초기화 안 됨 → 실행 시 0으로 채워짐
  • .rodata : "hi"는 읽기 전용 상수 → .rodata에 들어가고, s는 .data에서 .rodata 주소를 참조
  • .text : f() 함수 → 기계어 코드
  • .rel.text 정보로 링커가 g와 h의 실제 주소를 코드에 삽입

.data와 .bss가 나뉘는 이유

구분 .data .bss
초기화 여부 초기화된 변수 초기화되지 않은 변수
실행 파일 내 저장 여부 있음 없음 (공간만 기록됨)
목적 값 저장 공간 절약

예제

int g = 10;   // → .data
int h;        // → .bss
  • g는 값을 10으로 초기화했으므로, 실행파일에 10이라는 값이 저장됨.
  • h는 초기화 안 됐으므로, 실행파일에 값은 저장하지 않고 크기만 기록함.
  • → 실행 시 메모리에 0으로 자동 초기화됨.

그래서 왜?

1. 실행 파일 크기를 줄이기 위해

  • .bss 섹션은 실제 데이터 없이 “여기 몇 바이트 필요해요”만 기록함
  • 초기화된 변수(.data)는 값까지 기록해야 하므로 실행파일 용량이 커짐

예를 들어:

char huge_array[1000000]; // .bss

→ 이걸 .data에 넣으면 실행파일이 수 MB 커짐

2. 메모리 초기화 방식이 다름

  • .data: 값이 있으므로 파일에서 읽어서 메모리에 복사
  • .bss: OS가 0으로 자동 초기화 (실제로 값이 파일에 없음)

링커 입장에서도 유리

  • 링커는 .bss는 그냥 “여기 메모리만 잡아줘“라고 OS에 알려주면 되고,
  • .data는 파일에 저장된 값들을 메모리에 올려야 함

ELF 파일에서도 이렇게 표시됨

readelf -S a.out 했을 때:

  [ 3] .data      PROGBITS  0000000000601020 ...
  [ 4] .bss       NOBITS    0000000000601030 ...
  • .data는 PROGBITS → 실제 데이터 있음
  • .bss는 NOBITS → 데이터 없이 크기만 표시

요약

  • .bss는 공간은 필요하지만 초기화값이 없는 전역/정적 변수용
  • 실행 파일 크기를 줄이고, OS가 0으로 초기화하도록 맡긴다
  • .data는 초기값이 있는 변수만 담는다

728x90

'CS:APP' 카테고리의 다른 글

예외상황  (0) 2025.08.10
실행 가능 목적파일의 로딩  (0) 2025.08.09
컴파일러 드라이버  (0) 2025.08.04
함수는 추상화의 결과다 - CS:APP 3.7 프로시저 호출  (0) 2025.04.08
스택은 사실 아래로 자란다(push,pop) - CS:APP 3.4.4  (0) 2025.04.07
'CS:APP' 카테고리의 다른 글
  • 예외상황
  • 실행 가능 목적파일의 로딩
  • 컴파일러 드라이버
  • 함수는 추상화의 결과다 - CS:APP 3.7 프로시저 호출
ahpicl64
ahpicl64
in the clouds
  • ahpicl64
    구름
    ahpicl64
  • 전체
    오늘
    어제
    • 분류 전체보기 (95)
      • WIL (4)
      • Jungle (36)
      • AWS (2)
      • SQL (2)
      • CS:APP (17)
      • Algorithm (10)
      • K8s (7)
      • 자료 구조 (10)
      • Spring (4)
      • React (0)
      • 운영체제 (1)
      • 기타등등 (2)
      • 이야기 (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • github
  • 공지사항

  • 인기 글

  • 태그

    queue
    DB
    python
    트러블슈팅
    CSAPP
    EC2
    Spring boot
    알고리즘
    어셈블리
    CloudFront
    github actions
    IAM
    Spring
    k8s
    부하테스트
    자료구조
    컴퓨터시스템
    S3
    AWS
    DevOps
  • 02-21 07:23
  • hELLO· Designed By정상우.v4.10.3
ahpicl64
ELF, Executable and Linkable Format (재배치 가능 목적파일)
상단으로

티스토리툴바