[PATCH u-boot 12/39] string: make memcpy() and memset() visible to fix LTO linking errors

Marek Behun marek.behun at nic.cz
Mon Mar 8 12:31:35 CET 2021


On Mon, 8 Mar 2021 11:55:32 +0100
Pali Rohár <pali at kernel.org> wrote:

> On Monday 08 March 2021 18:40:58 Bin Meng wrote:
> > On Mon, Mar 8, 2021 at 6:23 PM Pali Rohár <pali at kernel.org> wrote:  
> > >
> > > On Monday 08 March 2021 11:19:33 Marek Behun wrote:  
> > > > On Mon, 8 Mar 2021 15:56:01 +0800
> > > > Bin Meng <bmeng.cn at gmail.com> wrote:
> > > >  
> > > > > Hi Marek,
> > > > >
> > > > > On Sun, Mar 7, 2021 at 12:26 PM Marek Behún <marek.behun at nic.cz> wrote:  
> > > > > >
> > > > > > It seems that sometimes (happening on ARM64, for example with
> > > > > > turris_mox_defconfig) GCC, when linking with LTO, changes the symbol
> > > > > > names of some functions, for example lib/string.c's memcpy() function to
> > > > > > memcpy.isra.0.
> > > > > >
> > > > > > This is a problem however when GCC for a code such as this:
> > > > > >         struct some_struct *info = get_some_struct();
> > > > > >         struct some struct tmpinfo;
> > > > > >         tmpinfo = *info;
> > > > > > emits a call to memcpy() by builtin behaviour, to copy *info to tmpinfo.
> > > > > > memset() can be generated sometimes as well.
> > > > > >
> > > > > > This then results in the following linking error:
> > > > > >   .../lz4.c:93: undefined reference to `memcpy'
> > > > > >   .../uuid.c:206: more undefined references to `memcpy' follow
> > > > > >
> > > > > > Make memcpy() and memset() visible by using the __used macro to avoid
> > > > > > this error.  
> > > > >
> > > > > This sounds like a GCC bug of using -fno-builtin and -flto. Could you
> > > > > file a bugzilla to GCC people to get some comments?  
> > > >
> > > > This is not LTO related. -fno-builtin still generates memcpy() call for
> > > > the following code:
> > > >
> > > > typedef struct {
> > > >       int a[40];
> > > >       char b[50];
> > > >       int c[60];
> > > > } a;
> > > >
> > > > void cp(a *d, const a *s) {
> > > >       *d = *s;
> > > > }
> > > >
> > > > when compiled with
> > > >   armv7a-hardfloat-linux-gnueabi-gcc -O2 -fno-builtin -ffreestanding \
> > > >    -nostdlib -S
> > > >
> > > > it produces code
> > > >
> > > >       push    {r4, lr}
> > > >       mov     ip, #4096
> > > >       sub     ip, sp, ip
> > > >       str     r0, [ip, #4088]
> > > >       mov     r2, #452
> > > >       bl      memcpy
> > > >       pop     {r4, pc}
> > > >       .size   cp, .-cp
> > > >
> > > > I don't think this is a bug. Or if it is, it is a wontfix. Just
> > > > implement memcpy into your code, so that gcc does not have to emit
> > > > shitstorms of instructions because of assignment operator :)
> > > >
> > > > Marek  
> > >
> > > This is not a bug but rather a feature of gcc. Documentation for
> > > -nodefaultlibs and -nostdlib contains:
> > >
> > > The compiler may generate calls to "memcmp", "memset", "memcpy" and
> > > "memmove".  These entries are usually resolved by entries in libc.
> > > These entry points should be supplied through some other mechanism when
> > > this option is specified.  
> > 
> > Yeah I know this. My question was why when LTO is enabled, we have to
> > explicitly mark these APIs as __used? I should have asked clearly, is
> > this a bug of LTO?  
> 
> I see... What is the _exact_ command line arguments called when this
> linking issue happen? I know that when gcc's LTO is enabled it depends
> on other of objects and libraries which are linking. And I'm not sure if
> all -whole-archive option can make order of archives independent when
> dealing with these builtin function references. At least I cannot find
> exact gcc documentation about linking order.

remove the __used flag for memcpy, add -save-temps to the final linking
command in order not to delete ltrans assembly files,
compile for turris_mox_defconfig with V=1

the final linking fails and you can study the assembly file it
generated


More information about the U-Boot mailing list