undefined reference to __udivdi3问题之解决

本文详细介绍了在Linux内核中处理64位整数除法的方法,特别是针对ARM平台上的实现细节。文章解释了为什么直接使用简单的除法运算符会导致链接错误,并提供了正确的做法,即使用do_div函数来完成除法运算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

编译时有时会遇到这种错误:

undefined reference to `__udivdi3'

嵌入式中,32位系统中(目前多数系统都是,比如ARM的片子),对于普通的a除以b(b为32位):

(1)当a为32位,Linux 内核中,常用uint32_t 类型,可以直接写为 a/b

(2)但是,对于a是64位,uint64_t的时候,就要用到专门的除操作相关的函数,linux内核里面一般为

do_div(n, base),注意,此处do_div得到的结果是余数而真正的a/b的结果,是用a来保存的

do_div(n,base)的具体定义,和当前体系结构有关,对于arm平台,在include/asm-arm/div64.h

因此,如果你当前写代码,a/b,如果a是uint64_t类型,那么一定要利用do_div(a,b),而得到结果a,

而不能简单的用a/b,否则编译可以正常编译,但是最后链接最后出错,会提示上面的那个错误:

undefined reference to "__udivdi3"

<think>我们正在讨论如何链接compiler-rt库。compiler-rt是LLVM项目的一部分,为硬件不支持的操作提供运行时支持(如32位平台上的64位除法)。通常,编译器(如Clang)在需要时会自动链接compiler-rt中的函数,但有时可能需要显式操作。 根据引用[1]和[2]: - 在32位目标上,由于硬件不支持64位除法,编译器会生成对compiler-rt中相应函数的调用。 - 在64位目标上,可能不需要compiler-rt的协助,因为一条指令就能完成。 因此,链接compiler-rt通常是在编译时由编译器自动处理的。但在某些情况下(如交叉编译、自定义目标或使用非标准运行时库),可能需要显式链接。 以下步骤说明如何在编译时链接compiler-rt库: ### 1. **理解编译器自动链接行为** - 对于Clang(LLVM的C/C++编译器),当检测到目标平台需要compiler-rt支持时(如32位x86的64位除法),会自动链接compiler-rt中的函数。 - 这些函数通常包含在`libclang_rt.builtin-<arch>.a`等静态库中,存放在编译器的资源目录下。 - 使用以下命令查看Clang的资源目录(其中包含预编译的compiler-rt库): ```bash clang -print-resource-dir ``` ### 2. **手动链接compiler-rt(当自动链接失效时)** 如果编译器没有自动链接compiler-rt(例如,使用了`-nostdlib`或`-nodefaultlibs`选项),则需要显式指定。 **步骤1: 确定目标平台和库文件** - 根据目标架构(如`i386`、`x86_64`、`arm`等)和操作系统(如Linux、Darwin),compiler-rt库的名称不同。 - 常见的库文件名模式:`libclang_rt.builtin-<arch>.a` 或 `libclang_rt.builtin-<arch>-<os>.a`。 - 例如,32位Linux的库:`libclang_rt.builtin-i386.a`。 **步骤2: 在链接命令中添加库** - 使用`-l`选项链接compiler-rt库,同时用`-L`指定库路径(通常是Clang的资源目录下的`lib`子目录)。 - 示例命令(32位Linux程序): ```bash clang -m32 -o myapp myapp.c \ -L$(clang -print-resource-dir)/lib/linux \ # 指定库路径 -lclang_rt.builtin-i386 # 链接特定的compiler-rt库 ``` - 注意:库名省略了前缀`lib`和后缀`.a`,因此`libclang_rt.builtin-i386.a`应写为`-lclang_rt.builtin-i386`。 **替代方案:使用编译器包装标志** - Clang提供了`-rtlib`选项来指定运行时库(compiler-rt或libgcc)。例如,强制使用compiler-rt: ```bash clang -m32 -o myapp myapp.c -rtlib=compiler-rt ``` 这会让Clang自动查找并链接正确的compiler-rt库。 ### 3. **验证compiler-rt是否被链接** - 检查可执行文件中的符号。例如,在32位程序中,64位除法函数通常命名为`__divdi3`(有符号64位除法)或`__udivdi3`(无符号)。 - 使用`nm`工具查看: ```bash nm myapp | grep __divdi3 ``` 如果找到该符号,说明compiler-rt已链接。 ### 4. **特殊情况:构建自定义compiler-rt** 如果预编译的compiler-rt不满足需求(如自定义目标平台),可自行构建: - 从LLVM项目获取compiler-rt源码(通常与LLVM一起)。 - 使用CMake构建,并指定安装目录。 - 在编译时用`-L`和`-l`链接自定义构建的库。 ### 注意事项 - **自动链接优先**:大多数情况下无需手动操作,除非遇到链接错误(如`undefined reference to __divdi3`)。 - **与libgcc的互斥性**:compiler-rt是libgcc的替代品,两者功能重叠。避免同时链接,以免冲突。 - **交叉编译**:为其他目标平台编译时,确保链接的compiler-rt库与目标平台匹配。 通过以上步骤,您可以在编译时显式或隐式地链接compiler-rt库,确保程序在目标平台上正确运行。 §§相关问题§§ 1. 如何解决编译时出现的`undefined reference to __divdi3`错误? 2. 在交叉编译时如何指定compiler-rt库? 3. compiler-rt提供了哪些功能? 4. 如何为自定义目标平台构建compiler-rt?</think>### 如何在编译时链接 Compiler-RT 库 Compiler-RT 是 LLVM 的运行时库,为硬件不支持的底层操作(如 32 位系统上的 64 位除法)提供优化实现。以下是链接步骤和原理: #### 1. **理解 Compiler-RT 的作用** - 当编译器遇到硬件不支持的指令(如 32 位系统的 64 位除法)时,会自动生成对 Compiler-RT 函数的调用[^2] - 例如 32 位系统上的 64 位整数除法会被替换为对 `__divdi3()` 的调用[^1] - 在 64 位系统上,这些操作通常由单条指令完成,无需 Compiler-RT[^1] #### 2. **自动链接(推荐)** 大多数现代编译器(Clang/GCC)会自动链接所需的 Compiler-RT 函数: ```bash clang -m32 myprogram.c -o myprogram # 32位编译自动引入Compiler-RT ``` - 使用 `-m32` 标志时,编译器检测到需要 64 位运算支持,自动插入 `__divdi3` 等函数调用[^1] - 验证方法:检查生成的汇编代码 ```bash clang -m32 -S myprogram.c -o myprogram.s grep __divdi3 myprogram.s # 查看是否引用了Compiler-RT函数 ``` #### 3. **手动链接(特殊情况)** 当自动链接失效时(如使用 `-nostdlib` 或交叉编译): ```bash # 获取Compiler-RT库路径 CLANG_RES_DIR=$(clang -print-resource-dir) # 手动链接特定架构的库 clang -m32 myprogram.c -o myprogram \ -L${CLANG_RES_DIR}/lib/linux/ \ -lclang_rt.builtin-i386 ``` - 库命名规则:`libclang_rt.builtin-<架构>.a` - 常见库路径:`/usr/lib/clang/<版本>/lib/<系统>/` #### 4. **CMake 项目配置** 在 CMakeLists.txt 中添加: ```cmake # 启用Compiler-RT set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rtlib=compiler-rt") # 32位编译明确需要 set_target_properties(myapp PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32") ``` #### 5. **验证链接结果** ```bash # 检查可执行文件符号 nm myprogram | grep __divdi3 # 检查动态依赖(应无外部依赖) ldd myprogram # 静态链接时显示"statically linked" ``` #### 关键原理 - **硬件支持差异**:32 位系统需要软件模拟 64 位运算,而 64 位系统有原生指令[^1][^2] - **函数映射**: | 运算类型 | 32 位系统函数 | 64 位系统指令 | |----------------|-------------------|--------------| | 64 位有符号除法 | `__divdi3()` | `idivq` | | 64 位取模 | `__moddi3()` | `idivq`+余数 | | 128 位加法 | `__addti3()` | `addq` | > **注意**:Compiler-RT 是 libgcc 的替代品,提供相同功能但针对 LLVM 优化[^2]。当出现 `undefined reference to __divdi3` 错误时,通常表示 Compiler-RT 未正确链接。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值