ARM-software / LLVM-embedded-toolchain-for-Arm

A project dedicated to building LLVM toolchain for Arm and AArch64 embedded targets.
Apache License 2.0
405 stars 94 forks source link

Duplicate symbols in `libclang_rt.builtins.a` and `libc.a` #427

Closed carlescufi closed 5 months ago

carlescufi commented 5 months ago

I get this error when linking:

ld.lld: error: duplicate symbol: __aeabi_memcpy4
>>> defined at aeabi_memcpy.S.obj:(__aeabi_memcpy) in archive /Users/carles/bin/LLVMEmbeddedToolchainForArm-17.0.1-Darwin/bin/../lib/clang-runtimes/arm-none-eabi/armv7m_soft_fpv4_sp_d16/lib/libclang_rt.builtins.a
>>> defined at memcpy.c:71 (../../../../../src/picolibc/newlib/libc/machine/arm/../../string/memcpy.c:71)
>>>            memcpy.c.o:(memcpy) in archive /Users/carles/bin/LLVMEmbeddedToolchainForArm-17.0.1-Darwin/bin/../lib/clang-runtimes/arm-none-eabi/armv7m_soft_fpv4_sp_d16/lib/libc.a

which suggests that memcpy exists both in the runtime and the C standard lib?

smithp35 commented 5 months ago

Thanks very much for the report. It is true that both compiler-rt and picolibc/newlib both define __aeabi_memcpy4 for some architectures, for example: https://github.com/picolibc/picolibc/blob/main/newlib/libc/machine/arm/aeabi_memcpy-armv7a.S (picolibc) https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/builtins/arm/aeabi_memcpy.S (compiler-rt)

What I would expect to happen is that whichever library was first on the link-line (normally picolibc as libc.a) would be used to resolve the reference to __aeabi_memcpy4 this would mean that there was no need to extract the object from compiler-rt as both objects look like they define the same symbols. This could happen with somthing like --whole-library though.

Would you be willing to give us some more information about how you are linking so we can try and reproduce? In particular are you using something like --whole-library?

There is also a linker command called --why-extract=<filename> which might help us. Would you be able to add -Wl,--why-extract=<filename> and see what it says for the appropriate object files in picolibc and compiler-rt.

For example on my system I get:

LLVMEmbeddedToolchainForArm-19.0.0-Linux-x86_64/bin/../lib/clang-runtimes/arm-none-eabi/armv7em_soft_nofp_exceptions_rtti/lib/libc.a(memcpy.c.o) __aeabi_memcpy4

For my simple test case that calls __aeabi_memcpy4.

carlescufi commented 5 months ago

Thanks for the reply.

What I would expect to happen is that whichever library was first on the link-line (normally picolibc as libc.a) would be used to resolve the reference to __aeabi_memcpy4 this would mean that there was no need to extract the object from compiler-rt as both objects look like they define the same symbols. This could happen with somthing like --whole-library though.

Indeed we are using --whole-archive, which is then likely the cause of the error. We need to use it due to the fact that we have plenty of linker sections and symbols that are only referenced indirectly at runtime by the code, and so the linker does not know it needs to preserve them. This is in the context of the Zephyr build system, which is reasonably complex and in fact uses multiple linker passes as well. I don't currently have any good (simple) ideas on how to overcome this issue, but I will ping the build system maintainer in Zephyr to see what they think.

smithp35 commented 5 months ago

If it helps, the driver puts -lc -lm and -llibclang_rt.builtins.a at the end of the link line. Assuming that the --whole-archive is only needed for Zephyr and application libraries only then adding --no-whole-archive as an option at the end of link-line should fix this as it will turn it off for all libraries after it. Essentially you would have --whole-archive <zephyr-libraries> --no-whole-archive. The driver will add the system libraries at the end.

carlescufi commented 5 months ago

If it helps, the driver puts -lc -lm and -llibclang_rt.builtins.a at the end of the link line. Assuming that the --whole-archive is only needed for Zephyr and application libraries only then adding --no-whole-archive as an option at the end of link-line should fix this as it will turn it off for all libraries after it. Essentially you would have --whole-archive <zephyr-libraries> --no-whole-archive. The driver will add the system libraries at the end.

I see, thank you for the insight. I will now close this issue since this is not technically a problem with the toolchain, but rather our use of it.