C++ Exception Basics
TL;DR
-
C++ μμΈ μ²λ¦¬λ Itanium C++ ABIμ κ·μΉμ λ°λ₯Έλ€.
-
μ μ κ²½λ‘λ λΉμ©μ΄ μκ³ (=zero-cost), μμΈκ° λμ Έμ§ λλ§ μ€ν μΈμμΈλ©μ΄ μνλλ€.
-
μΈμμΈλ©μ DWARF μΈμμΈλ μ 보(.eh_frame) λ₯Ό μ΄μ©νμ¬ μ€ν νλ μμ ν λ¨κ³μ© λλ리며,
νλ μλ§λ€ personality ν¨μκ° βcatch λμμΈμ§/μ λ¦¬λ§ ν μ§βλ₯Ό νλ¨νλ€. -
μμΈ κ°μ²΄λ heap μ λ§λ€μ΄μ§λ©° reference count λ‘ μλͺ μ£ΌκΈ°λ₯Ό κ΄λ¦¬νλ€.
-
μΈμμΈλ© κ³Όμ μμ callee-saved λ μ§μ€ν°λ§ 볡μλκ³ , caller-saved λ μ§μ€ν°λ νμ μ landing pad μ½λκ° μ¬κ΅¬μ±νλ€.
-
μ±λ₯ λ³λͺ©μ λμ λΌμ΄λΈλ¬λ¦¬ λͺ©λ‘μ 보νΈνλ μ μ λ‘λ λ½κ³Ό .eh_frame νμ λΉμ©μ΄λ©°,
μΈμμΈλ ꡬν체(libgcc_s, LLVM libunwind λ±)λ μ΄λ₯Ό μΊμ± μ λ΅μΌλ‘ μ΅μ ννλ€.
Overview
1) μμΈ λ°μ μ μ 체 νλ¦
-
throwβ μ»΄νμΌλ¬κ° μμ±ν μ½λκ° μμΈ κ°μ²΄λ₯Ό heapμ ν λΉνκ³__cxa_throwνΈμΆ -
__cxa_throwβ Itanium ABIμ_Unwind_RaiseExceptionνΈμΆ -
μΈμμΈλκ° νμ¬ μ€ν νλ μ μμΉμμ DWARF CFI(unwind info) λ₯Ό μ½λλ€
-
1λ¨κ³(Search phase)
- κ° νλ μλ§λ€ personality ν¨μλ₯Ό νΈμΆν΄
βμ΄ νλ μμ΄ μ΄ μμΈλ₯Ό μ‘μ μ μλκ°?β κ²μ¬
- κ° νλ μλ§λ€ personality ν¨μλ₯Ό νΈμΆν΄
-
2λ¨κ³(Cleanup phase)
-
λ€μ μ²μλΆν° νλ μμ μννλ©°
-
destructor νΈμΆ
-
catch λμ νλ μκΉμ§ μ€ν λ‘€λ°±
-
-
λμ°©νλ©΄ landing padλ‘ μ ν
-
-
landing padμμ
__cxa_begin_catchμ€ν β μμΈ κ°μ²΄ μ°Έμ‘° νλ -
catch λΈλ‘ μ’ λ£ μ
__cxa_end_catchνΈμΆ β refcount κ°μ λ° νμ μ μμ
2) Itanium C++ ABIκ° λ³΄μ₯νλ κ²
-
μμΈ κ°μ²΄ λ©λͺ¨λ¦¬ λ μ΄μμ
-
__cxa_throw,__cxa_begin_catch,__cxa_end_catch,__gxx_personality_v0λ±μ μΈν°νμ΄μ€ -
personality ν¨μκ° μνν΄μΌ νλ λμκ³Ό νλ¨ κ·μΉ
-
DWARF κΈ°λ° μ€ν μΈμμΈλ© μ μ°¨
β μ»΄νμΌλ¬(gcc/clang)κ° λ¬λΌλ μμΈ λͺ¨λΈμ νΈνλ¨
3) DWARF μΈμμΈλ μ 보(.eh_frame)
-
κ° ν¨μμ μ€ν λ μ΄μμ λ³ν, νλ‘€λ‘κ·Έ/μνλ‘κ·Έμμ μ μ₯λ λ μ§μ€ν° μμΉ λ±μ κΈ°λ‘ν metadata
-
μΈμμΈλλ μ΄λ₯Ό ν΄μνμ¬ βμ΄μ νλ μμ SP/IP/FP/μ μ₯ λ μ§μ€ν°βλ₯Ό 볡μν μ μλ€
-
μμΈ μ²λ¦¬ μ μ©μ΄λ©°, λλ²κ·Έ μ 보(.debug_info)μλ λ³κ°
4) personality ν¨μ
νλ μλ§λ€ νΈμΆλλ βμΈμ΄λ³ μ²λ¦¬ μμ§β μν .
-
C++:
__gxx_personality_v0 -
μ± μ
-
μ΄ νλ μμ΄ ν΄λΉ μμΈ νμ μ catchν μ μλμ§ νλ¨
-
cleanup-only μμμΈμ§ νλ¨
-
landing padμ μμΉ(IP)λ₯Ό μΈμμΈλμ μλ €μ€
-
5) λ μ§μ€ν° 볡μ κ·μΉ
-
callee-saved λ μ§μ€ν°λ§ DWARFλ₯Ό ν΅ν΄ λ°λμ 볡μ
- (μ: x86-64: RBX, RBP, R12~15 λ±)
-
caller-savedλ landing pad μ½λκ° μ§μ νμ μ λ€μ λ‘λ©
-
SP, IP(PC), FP κ°μ νλ μ κ΄λ ¨ λ μ§μ€ν°λ νμ μΈμμΈλκ° λ³΅μ
6) μ±λ₯ λ³λͺ©κ³Ό μ΅μ ν
-
λμ λΌμ΄λΈλ¬λ¦¬ λͺ©λ‘μ λ‘λμ μ μ λ½(dl loader lock) μΌλ‘ 보νΈλ¨
β.eh_frameμμΉ νμ μ λ½ νλ νμ -
λκ·λͺ¨ νλ‘κ·Έλ¨μμ μμΈ λΉμ©μ΄ κΈμ¦νλ μ΄μ
-
νλ μλ§λ€ DWARFλ₯Ό νμ±
-
μ¦μ μ μ λ½ νλ
-
-
LLVM libunwind, libgcc_s λ±μ
-
IP β CFI μΊμ±
-
ν¨μ λ¨μ λλ νΈμΆ μ§μ λ¨μ μΊμ±
-
backtrace fast path μ΅μ ν
λ±μ μ¬μ©ν΄ μ±λ₯ κ°μ
-
Example (κ°λ νλ¦ μμ)
μμΈ λ°μ β __cxa_throw
β _Unwind_RaiseException
β Frame N personality κ²μ¬(λΆμ ν©)
β Frame Nβ1 personality κ²μ¬(λΆμ ν©)
β Frame Nβ2 personality κ²μ¬(catch κ°λ₯ β search phase μ’
λ£)
β cleanup phase μμ(μ νλ μλ€ destructor μ€ν)
β landing pad IPλ‘ μ ν
β __cxa_begin_catch
β catch λΈλ‘ μ€ν
β __cxa_end_catch β refcount 0 β μμΈ κ°μ²΄ delete
Takeaways
-
C++ μμΈ μ²λ¦¬λ zero-cost λͺ¨λΈμ΄λ©°, μ€ν μ€ μμΈκ° μμ λ λΉμ©μ΄ μ¬μ€μ μλ€.
-
μΈμμΈλ©μ DWARF + Itanium ABI + personality ν¨μμ μ‘°ν©μΌλ‘ λμνλ€.
-
μμΈ κ°μ²΄λ heapμ μμΌλ©° refcountλ‘ μλͺ μ£ΌκΈ° κ΄λ¦¬λλ€.
-
caller-saved / callee-saved ꡬλΆμ μΈμμΈλ© λΉμ© μ΅μ νλ₯Ό μν΄ μ€μνλ€.
-
λμ λΌμ΄λΈλ¬λ¦¬ νκ²½μμλ λ‘λ λ½ κ²½μμ΄ μμΈ λΉμ©μ μ νμν¬ μ μμΌλ©°,
νλ μΈμμΈλλ μ΄λ₯Ό μΊμ± μ λ΅μΌλ‘ μννλ€. -
GCC/Clang λ± μλ‘ λ€λ₯Έ C++ λ°νμμ΄λΌλ Itanium ABIλ₯Ό μ€μνλ ν μνΈ μ΄μ© κ°λ₯νλ€.
References
CppCon 2017: Dave Watson βC++ Exceptions and Stack Unwindingβ C++ Exceptions for Smaller Firmware - Khalil Estell - CppCon 2024