如何对比zero-cost exceptions与旧异常编译方案的汇编代码?
零开销异常与旧异常方案的汇编对比方法(Linux x64)
一、通过GCC选项直接切换异常模型
GCC支持用编译选项直接切换两种异常实现,无需更换版本:
- 零开销异常(DWARF模型):Linux x64下GCC默认启用,也可显式指定:
-fexceptions -fdwarf2-exceptions - 旧方案(SJLj模型):使用选项:
-fexceptions -fsjlj-exceptions
具体操作步骤:
- 编写包含异常逻辑的测试代码,比如:
#include <stdexcept> int test(int a) { if (a < 0) { throw std::runtime_error("negative value"); } return a * 2; } int main() { try { test(-1); } catch (...) { return 1; } return 0; }
- 分别编译生成汇编文件:
- 零开销方案:
g++ -O2 -fexceptions -fdwarf2-exceptions -S test.cpp -o dwarf.s - SJLj旧方案:
g++ -O2 -fexceptions -fsjlj-exceptions -S test.cpp -o sjlj.s
- 零开销方案:
- 对比两个汇编文件:零开销方案的正常执行路径无额外指令,异常处理信息存在独立的DWARF调试段;SJLj方案会在函数入口插入
setjmp相关指令,正常路径有固定开销。
二、在Godbolt Compiler Explorer上快速对比
无需本地编译,直接在线对比:
- 选择任意支持
-fsjlj-exceptions的GCC版本(如GCC 12、13) - 左侧输入测试代码,右侧分栏添加两组编译选项:
- 第一组:
-O2 -fexceptions(默认启用零开销DWARF模型) - 第二组:
-O2 -fexceptions -fsjlj-exceptions(启用旧SJLj模型)
- 第一组:
- 直观对比两组汇编结果的差异。
- 若想使用默认旧方案的GCC版本,可选择Godbolt上的GCC 3.4.6——它在x64 Linux下默认采用SJLj异常模型,直接和新版本默认的DWARF方案对比即可。
三、核心差异总结
- 零开销(DWARF):正常执行路径无额外指令开销,异常处理依赖编译生成的DWARF unwind信息,开销集中在异常抛出阶段。
- SJLj旧方案:每个函数入口都会插入
setjmp保存上下文,正常路径有固定开销,异常抛出时直接通过longjmp跳转至捕获点,异常触发开销相对较低。
内容的提问来源于stack exchange,提问作者svick
相关产品推荐
相关产品推荐

