You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Clang下重写__cxa_throw遇重复符号错误(GCC无此问题)

问题描述

我希望增强__cxa_throw的信息输出,该方案仅计划用于Debug构建。相关代码在GCC 4.8.5下编译运行完全正常,但在Clang 12.0.1中链接时出现如下错误:

ld.lld: error: duplicate symbol: __cxa_throw
>>> defined at exc_override.cpp
>>>            exc.o:(__cxa_throw)
>>> defined at cxa_exception.cpp
>>>            cxa_exception.cpp.o:(.text.__cxa_throw+0x0) in archive /opt/compilers/clang-12.0.1/bin/../lib/x86_64-unknown-linux-gnu/c++/libc++.a

涉及代码文件

main.cxx

#include <iostream>
#include <stdexcept>
#include "exc_override.h"

int main(int argc, char** argn) {

    try {
        throw std::runtime_error("boom");
    } catch(...)
    {
        std::cout << "caught" << std::endl;
    }

    return 0;
}

exc_override.h

#pragma once

extern "C"
void __cxa_throw (void *thrown_exception, void *pvtinfo, void (*dest)(void *)) ;

exc_override.cpp

#include "exc_override.h"
#include <cstdlib>
#include <dlfcn.h>
#include <execinfo.h>
#include "stdio.h"

typedef void (*cxa_throw_type)(void *, void *, void (*) (void *));
cxa_throw_type orig_cxa_throw = 0;

void load_orig_throw_code()
{
    orig_cxa_throw = (cxa_throw_type) dlsym(RTLD_NEXT, "__cxa_throw");
}

extern "C"
void __cxa_throw (void *thrown_exception, void *pvtinfo, void (*dest)(void *)) {
    printf(" ################ DETECT A THROWN !!!!! #############\n");
    if (orig_cxa_throw == 0)
        load_orig_throw_code();
    
    orig_cxa_throw(thrown_exception, pvtinfo, dest);
}

编译命令

GCC编译命令

gcc main.o exc_override.o -o testprogram
g++ main.o exc_override.o -o testprogram
g++ main.o exc_override.o -o testprogram -ldl

Clang编译命令

clang++ -c main.cxx -o main.o
clang++ -c exc_override.cpp -o exc.o
clang++ main.o exc.o -o testprogram

请问该如何解决Clang下的重复符号问题?


解决方法

冲突根源是Clang默认链接静态版本的libc++,其中已包含__cxa_throw的实现,而你的代码又定义了同名符号,导致链接器报错。以下是几种针对性的解决方式:

1. 动态链接libc++(推荐适配Debug场景)

既然你的方案仅用于Debug构建,可通过动态链接方式让自定义实现优先加载,同时保证能找到原函数:
修改Clang链接命令,添加-ldl(支持dlsym)并指定动态版libc++:

clang++ main.o exc.o -o testprogram -ldl -shared-libc++

动态库版本的libc++会通过RTLD_NEXT被你的自定义函数找到原实现,完全避开静态库的符号冲突。

2. 将自定义__cxa_throw标记为强符号优先

通过链接器选项强制指定使用你实现的__cxa_throw,忽略静态库中的版本:

clang++ main.o exc.o -o testprogram -ldl -Wl,--exclude-libs=libc++.a -Wl,--defsym=__cxa_throw=exc.o:__cxa_throw

该命令直接告诉链接器,__cxa_throw符号采用exc.o中的定义,排除静态库中的同名符号。

3. 仅在Debug构建中编译自定义实现

利用编译宏控制,只在Debug模式下包含__cxa_throw的自定义代码:
修改exc_override.cpp:

#ifdef DEBUG
extern "C"
void __cxa_throw (void *thrown_exception, void *pvtinfo, void (*dest)(void *)) {
    printf(" ################ DETECT A THROWN !!!!! #############\n");
    if (orig_cxa_throw == 0)
        load_orig_throw_code();
    
    orig_cxa_throw(thrown_exception, pvtinfo, dest);
}
#endif

编译Debug版本时添加-DDEBUG宏:

clang++ -c exc_override.cpp -o exc.o -DDEBUG
clang++ main.o exc.o -o testprogram -ldl -shared-libc++ -DDEBUG

Release构建不会包含自定义符号,自然不会有冲突。

内容的提问来源于stack exchange,提问作者Steve

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 12:52:55