gcc - 为 arm32 构建内核时对 __aeabi_ldivmod 的 undefined reference

标签 gcc linux-kernel embedded-linux

为arm32平台构建一个内核镜像时,在最后的链接中,报错为:

arm-eabi-ld -EL -p --no-undefined -X --build-id -o .tmp_vmlinux1 -T obj/KERNEL/arch/arm/kernel/vmlinux.lds arch/arm/kernel/head.o init/built-in.o --start-group usr/built-in.o arch/arm/vfp/built-in.o arch/arm/kernel/built-in.o arch/arm/mm/built-in.o arch/arm/common/built-in.o arch/arm/net/built-in.o arch/arm/crypto/built-in.o arch/arm/mach-sc/built-in.o kernel/built-in.o mm/built-in.o fs/built-in.o ipc/built-in.o security/built-in.o crypto/built-in.o block/built-in.o arch/arm/lib/lib.a lib/lib.a arch/arm/lib/built-in.o lib/built-in.o drivers/built-in.o sound/built-in.o firmware/built-in.o arch/arm/oprofile/built-in.o net/built-in.o --end-group drivers/built-in.o:

undefined reference to `__aeabi_ldivmod'

make[2]: *** [vmlinux] Error 1



我知道原因是我对 arm32 使用 64 位 divison,不支持 64 位,并且使用 do_div() 可以摆脱 __aeabi_ldivmod 错误。我知道 __aeabi_ldivmod 是在 libgcc.a 中定义的,所以我在内核 Makefile 中添加了以下代码:
--- a/Makefile  
+++ b/Makefile  
@@ -677,6 +677,7 @@   
LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,\  
                          $(call cc-ldoption, -Wl$(comma)--build-id,))  
KBUILD_LDFLAGS_MODULE += $(LDFLAGS_BUILD_ID)  
LDFLAGS_vmlinux += $(LDFLAGS_BUILD_ID)  
+LDFLAGS_vmlinux += -L$(MY_LIBPATH) -lgcc  

但它仍然无法工作,所以任何人都可以帮助解决我的问题:
1)为什么libgcc.a在内核构建中没有默认链接?
2)如何链接libgcc.a来修复链接错误?

[更新]

好的,我在 OSDev wiki 中找到了以下关于 -lgcc 的注释:

-lgcc
You disable the important libgcc library when you pass -nodefaultlibs (implied by -nostdlib). The compiler needs this library for many operations that it cannot do itself or that is more efficient to put into a shared function. You must pass this library near the end of the link line, after all the other object files and libraries, or the linker won't use it and you get strange linker errors.



所以我硬编码 -L${MYLIB_PATH} -lgcc into进入脚本/链接-vmlinux.sh:
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -55,7 +55,7 @@ vmlinux_link()
        if [ "${SRCARCH}" != "um" ]; then
                ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2}                  \
                        -T ${lds} ${KBUILD_VMLINUX_INIT}                     \
-                       --start-group ${KBUILD_VMLINUX_MAIN} --end-group ${1}
+                       --start-group ${KBUILD_VMLINUX_MAIN} --end-group ${1} -L${MYLIB_PATH} -lgcc
        else
                ${CC} ${CFLAGS_vmlinux} -o ${2}                              \
                        -Wl,-T,${lds} ${KBUILD_VMLINUX_INIT}                 \

然后构建没有 __aeabi_ldivmod 错误。
虽然我想找到比硬编码更好的修改,并想知道为什么内核不链接 libgcc 默认值。

最佳答案

不要编辑 scripts/link-vmlinux.sh,只编辑某些 Makefile。例如,如果您遇到此错误:

drivers/power/reset/msm-poweroff.c:249: undefined reference to `lge_set_restart_reason'
在linux内核源代码目录顶部运行cscope -R,然后找到lge_set_restart_reason的全局定义,它在include/soc/qcom/lge/lge_handle_panic.h中找到文件定义
但是lge_handle_panic.h只有lge_set_restart_reason的定义,你需要lge_handle_panic.c,它有这个功能,看起来像这样:
    void lge_set_restart_reason(unsigned int reason)
{
        writel_relaxed(reason, RESTART_REASON);
        if(use_hardreset) {
                qpnp_pon_set_restart_reason(map_imem_reboot_to_pmic(reason));
                qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET);
        }
}
所以你需要编辑 drivers/power/reset/Makefile 以包含 lge_handle_panic.o 目标文件:
obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o lge_handle_panic.o
在自定义内核中,很多功能都是通过配置启用的,我的意思是:
#ifdef CONFIG_LGE_HANDLE_PANIC
static void __iomem *msm_timer0_base;

void __iomem *wdt_timer_get_timer0_base(void)
{
        return msm_timer0_base;
}

static void wdt_timer_set_timer0_base(void __iomem * iomem)
{
        msm_timer0_base = iomem;
}
#endif
如果再次出现此错误,您需要启用 CONFIG_LGE_HANDLE_PANIC 或任何配置,或者删除“ifdef”和“endif”(我不建议这样做)

关于gcc - 为 arm32 构建内核时对 __aeabi_ldivmod 的 undefined reference ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34627213/

相关文章:

linux - 我需要 -D_REENTRANT 和 -pthreads 吗?

linux - 如何在 Arago 项目构建中为配方编写自己的包

linux - GCC 4.8.0 构建大小在 OS X 和 Ubuntu 上差异很大

gcc - 树莓派上的 scikit-learn/python3

c - switch_dev_register的使用场景是什么

c - 在内核空间中存储结构数组,Linux

c - Linux 内核函数 dm_per_bio_data 有什么作用?

Linux 为 DECLARE_WORK 中的函数传递参数

linux-kernel - 如何为 iMX6 sabre lite 板准备新的 SD 卡以运行 Linux

linux - 有效地在 ELF 文件中添加新部分