Reputation: 41
When building one kernel image for arm32 platform, in the final linking, the error is:
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
I know the reason is my using 64bit divison for arm32 which 64bit is not supported, and using do_div() can get rid of the __aeabi_ldivmod error. I know __aeabi_ldivmod is defined in the libgcc.a, so I added the following code in my Kernel 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
But it still can't work, so can anybody help on my questions:
1) Why the libgcc.a is not linked default in the kernel building?
2) How to link the libgcc.a to fix the link error?
OK, I found the following note for -lgcc in OSDev wiki:
-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.
So I hard coded -L${MYLIB_PATH} -lgcc into
into scripts/link-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} \
Then the build went without __aeabi_ldivmod error.
While I want to find the better modifying than just harding coding and to know why kernel doesn't link libgcc default.
Upvotes: 4
Views: 9491
Reputation: 41
Don't edit scripts/link-vmlinux.sh, edit only certain Makefiles. For example if you have this error:
drivers/power/reset/msm-poweroff.c:249: undefined reference to `lge_set_restart_reason'
run cscope -R inside top of linux kernel source code directory, then find global definition for lge_set_restart_reason, it finds file definition in include/soc/qcom/lge/lge_handle_panic.h
But lge_handle_panic.h has only definition of lge_set_restart_reason, you need lge_handle_panic.c, which has this function, looking like this:
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);
}
}
so you need to edit drivers/power/reset/Makefile to include lge_handle_panic.o object file:
obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o lge_handle_panic.o
In custom kernels, a lot of functions is enabled by config, what I mean is:
#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
You need enable CONFIG_LGE_HANDLE_PANIC, or any config if you have again this error, or remove "ifdef" and "endif" (I'm not recommending doing this)
Upvotes: 2