Crash when cross compiling for ARM with GCC-8-2-0 and -ftree-loop-distribute-patterns

Josef Wolf jw@raven.inka.de
Thu Oct 17 11:40:00 GMT 2019


Thanks for your Help, Martin!

On Wed, Oct 16, 2019 at 12:18:15PM -0600, Martin Sebor wrote:
> On 10/16/19 7:17 AM, Josef Wolf wrote:
> >Hello all,
> >
> >I experience target crashing when cross compiling for ARM with
> >-ftree-loop-distribute-patterns, which is enabled by the -O3 flag.
> >
> >The crash happens in the startup code, before main() is called. This startup
> >code looks like this:
> >
> >  extern unsigned long _sidata; /* Set by the linker */
> >  extern unsigned long _sdata;  /* Set by the linker */
> >  extern unsigned long _sbss; /* Set by the linker */
> >  extern unsigned long _ebss;  /* Set by the linker */
> >   void Reet_Handler (void)
> >   {
> >     unsigned long *src = &_sidata
> >     unsigned long *src = &_sdata
> >     /* Copy data segment into RAM */
> >     if (src != dst) {
> >       while (dst < &_edata)
> >         *(dst++) = *(src++);
> >     }
> >     /* Zero BSS segment */
> >     dst = &_sbss;
> >     while (dst < &_ebss)
> >       *(dst++) = 0;
> >     main();
> >   }
> >
> >
> >With -ftree-loop-distribute-patterns those two loops are replaced by calls to
> >memcpy() and memset().
> >
> >The memcpy function finishes just fine. But the memset function doesn't seem
> >to finish.  It looks like this:
> >
> >   void memset (void *s, int c, size_t n)
> >   {
> >     int i;
> >     for (i=0; i<n; i++)
> >       ((char *)s)[i] = c;
> >   }
> 
> This is probably not the cause of the crash but it's worth keeping
> in mind.  The standard memset function returns void* and (unless
> disabled) recent versions of GCC will issue a warning:

Ooops!

This was actually my fault. Since the computer doesn't have network, I
had typed the code by hand into the mail.

Although I double-checked multiple times, I managed to introduce several
typos :-///

Sorry for the confusion!


The code of Reset_Handler() and memset() actually looks like this:

    void Reset_Handler (void)
    {
      unsigned long *src = &_sidata
      unsigned long *dst = &_sdata

      /* Copy data segment into RAM */
      if (src != dst) {
        while (dst < &_edata)
          *(dst++) = *(src++);
      }

      /* Zero BSS segment */
      dst = &_sbss;
      while (dst < &_ebss)
        *(dst++) = 0;
 
      main();
    }

    void *memset (void *s, int c, size_t n)
    {
         int i;
         for (i=0; i<n; i++)
/* B */   ((char *)s)[i] = c;
   
/* B */ return s;
    }

> >Any ideas why this function is crashing? I can't see anything suspicious here.
> 
> I doubt it's the cause of the crash either but only addresses of
> bytes of the same object can be used in relational expressions
> (i.e., the two less-than controlling expressions).

Hmm, you are talking about the two loops in Reset_Handler(), right?

> Using address to unrelated objects is undefined.

Hmmm... I am not an expert on this topic. But I tend to think the BSS segment
is an object, which in turn is an array of uint8_t and/or uint32_t.
Taking the address one past the last element of an array for comparison is
a perfectly valid operation, AFAIK.

So what would be the proper way to communicate the dimensions of the BSS
segment from the linker to the runtime of the compiled program?

The memset() function is called with the right parameters. And it seems to
work when I single-step it on instruction level (that is, "stepi" command in
gdb). But it crashes if I set breakpints to the two instructions marked above
and use the "cont" statement or the "step" statement in gdb.

> Concerns about invalidating
> code like the above prevents compilers from implementing useful
> optimizations.

Hmmm...

> GCC doesn't issue a warning for this bug yet but it might in
> the future.   To avoid the undefined behavior and future
> warnings, convert the addresses to uintptr_t first and compare
> those instead.

Changing the code to use uintptr_t did not change anything. Still crashing.

BTW: The official documentation of gnu-ld contains an example with almost
     the same code, but using char* instead:
      https://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_chapter/ld_toc.html#TOC21
     Maybe this needs an update?

-- 
Josef Wolf
jw@raven.inka.de



More information about the Gcc-help mailing list