4

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?


[Update]

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.

Candle
  • 41
  • 1
  • 5
  • `-lgcc` still doesn't show up in the compiler output you posted. Are you sure you edited the right Makefile? – kfunk Jan 06 '16 at 08:02
  • @kfunk, The error log is original log without my Makefile changing, with my changing, the log is: + arm-eabi-ld -EL -p --no-undefined -X --build-id -L/my_workplace/gcc/linux-x86/arm/arm-eabi-4.7/lib/gcc/arm-eabi/4.7 -lgcc -o . ... ... ... ... undefined reference to `__aeabi_ldivmod' make[2]: *** [vmlinux] Error 1 make[1]: *** [sub-make] Error 2 – Candle Jan 06 '16 at 08:45
  • `libgcc` is *user-space* library. It cannot be used when link *kernel* code. – Tsyvarev Jan 06 '16 at 09:59
  • @Tsyvarev, I don't agree you, please see my update in the question :) – Candle Jan 06 '16 at 15:18
  • Did you try to load kernel compiled such way ( with -lgcc appended)? And where exactly(link) you have found this description of `-lgcc`? – Tsyvarev Jan 06 '16 at 16:30
  • 3
    Your topic seems to be a duplicate for [this one](http://stackoverflow.com/q/25623956/3866447). Does it answer your question? And no, kernel shouldn't be linked with libgcc in any circumstances, it's basically bare-metal program and it implements all needed library routines by itself. If some routine isn't implemented -- it's almost certainly that it was done for a reason. – Sam Protsenko Jan 06 '16 at 22:02

1 Answers1

2

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)