Bug 26522 - sysdeps/powerpc/powerpc32/power4/memset.S does not memset everything
Summary: sysdeps/powerpc/powerpc32/power4/memset.S does not memset everything
Status: RESOLVED MOVED
Alias: None
Product: glibc
Classification: Unclassified
Component: string (show other bugs)
Version: 2.32
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-08-22 13:51 UTC by Sergei Trofimovich
Modified: 2020-08-25 18:14 UTC (History)
5 users (show)

See Also:
Host:
Target: powerpc-unknown-linux-gnu
Build:
Last reconfirmed:


Attachments
ppc7450-config.log (9.13 KB, text/x-log)
2020-08-24 18:26 UTC, Sergei Trofimovich
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Sergei Trofimovich 2020-08-22 13:51:37 UTC
Bug is initially reported by Daniel Gurney as https://bugs.gentoo.org/737996.

There the system is -mcpu=7450 (32-bit power7). The bug manifests as a hangup in __internal_atexit() for every binary linket with libc due to uninitialized memory in '__exit_funcs_lock' lock. 

"""
backtrace:
#0  0x6fe03c60 in __lll_lock_wait_private (futex=futex@entry=0x6ff4aea8 <__exit_funcs_lock>)
    at ./lowlevellock.c:35
#1  0x6fdb8e68 in __internal_atexit (func=0xb7be4a74 <_dl_fini>, arg=arg@entry=0x0, d=d@entry=0x0, 
    listp=0x6ff4adec <__exit_funcs>) at cxa_atexit.c:43
#2  0x6fdb8ef0 in __GI___cxa_atexit (func=<optimized out>, arg=arg@entry=0x0, d=d@entry=0x0) at cxa_atexit.c:70
#3  0x6fd9cba4 in generic_start_main (main=0x6ffc1310, argc=1, argv=0xbfc5da80, auxvec=0xbfc5de34, 
    init=0x6ffcc090, rtld_fini=<optimized out>, stack_end=<optimized out>, fini=<optimized out>)
    at ../csu/libc-start.c:240
#4  0x6fd9cdc8 in __libc_start_main (argc=<optimized out>, argv=<optimized out>, ev=<optimized out>, 
    auxvec=<optimized out>, rtld_fini=<optimized out>, stinfo=<optimized out>, stack_on_entry=<optimized out>)
    at ../sysdeps/unix/sysv/linux/powerpc/libc-start.c:98
#5  0x00000000 in ?? ()
"""

Working glibs was built as

    ../glibc/configure --host=powerpc-unknown-linux-gnu --prefix=/usr \
        CC="powerpc-unknown-linux-gnu-gcc" \
        CFLAGS="-O2 -ggdb3"

Problematic glibc was built as:

    ../glibc/configure --host=powerpc-unknown-linux-gnu --prefix=/usr \
        CC="powerpc-unknown-linux-gnu-gcc" \
        CFLAGS="-O2 -ggdb3 -mcpu=7450"

What works:

in '-O2' mode sysdeps/powerpc/powerpc32/rtld-memset.c (aka string/memset.c) is used: https://sourceware.org/git/?p=glibc.git;a=blob;f=string/memset.c;h=9c213e82dc90f3eb426bc0b6c97ec5312b9d5c46;hb=HEAD

What does not work:

in '-O2 -mcpu=7450' mode ./sysdeps/powerpc/powerpc32/power4/multiarch/rtld-memset.S (aka sysdeps/powerpc/powerpc32/power4/memset.S) is used:  https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/powerpc/powerpc32/power4/memset.S;h=f4ada9afc991bdbddedc99815bc17209b64cae6e;hb=HEAD

When it attempts to initialize .sbss / .iplt /.bss (all should be zeroed out) it fails to do so. __exit_funcs_lock is in .sbss.

https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/powerpc/powerpc32/rtld-memset.c;h=f3ed8ad1e74b6bbf9af8764b37c140179767744e;hb=HEAD says why memset.c is preferred because sysdeps/powerpc/powerpc32/power4/memset.S does not really work not many CPUs due to hardcoded cache-block=128:

"""
   1 /* PPCA2 has a different cache-line size than the usual 128 bytes.  To avoid
   2    using code that assumes cache-line size to be 128 bytes (with dcbz
   3    instructions) we use the generic code instead.  */
   4 #include <string/memset.c>
"""

For me qemu sets cache-block-size to 64 bytes and thus memsets only 64 of 128 bytes at each iteration leaving uninitialized holes in large chunks.
Comment 1 Sergei Trofimovich 2020-08-23 09:55:36 UTC
sysdeps/powerpc/powerpc32/power7/memset.S used by sysdeps/powerpc/powerpc32/power4/multiarch/memset-power7.S also assumes dcbz to cover 128 bytes at a time. This breaks memset() for normal (non-rtld) case.
Comment 2 Tulio Magno Quites Machado Filho 2020-08-24 14:43:35 UTC
AFAICS, powerpc 7450 can't run POWER4 code.  So, this processor shouldn't be running POWER4 or POWER7 code.
The question that needs to be answered is: why is your build getting them?

I tried to reproduce your build, but I did not get any POWER4 files:
configure --host=powerpc-linux-gnu --prefix=/usr CC="powerpc-linux-gnu-gcc" CFLAGS="-O2 -ggdb3 -mcpu=7450"

$ grep submachine config.log 
libc_cv_cc_submachine=''
submachine=''

I used commit ID 756c306502498f999fdd494477b9cea1b45e4faf.

What are you getting in your config.log?
Comment 3 Sergei Trofimovich 2020-08-24 18:26:51 UTC
Created attachment 12793 [details]
ppc7450-config.log

ppc7450-config.log is a config.log from

    ../glibc /configure --host=powerpc-unknown-linux-gnu --prefix=/usr \
        CC="powerpc-unknown-linux-gnu-gcc -mcpu=7450" \
        CFLAGS="-O2 -ggdb3 -mcpu=7450"
Comment 4 Sergei Trofimovich 2020-08-24 18:49:57 UTC
(In reply to Tulio Magno Quites Machado Filho from comment #2)
> AFAICS, powerpc 7450 can't run POWER4 code.  So, this processor shouldn't be
> running POWER4 or POWER7 code.
> The question that needs to be answered is: why is your build getting them?

Oh, I had no idea.

Mechanically power7 is detected at sysdeps/powerpc/preconfigure.ac:

$ echo 'int foo () { return 0; }' | powerpc-unknown-linux-gnu-gcc-10.2.0 -S -frecord-gcc-switches -xc -o - - | fgrep machine
        .machine ppc
$ echo 'int foo () { return 0; }' | powerpc-unknown-linux-gnu-gcc-10.2.0 -mcpu=7450 -S -frecord-gcc-switches -xc -o - - | fgrep machine
        .machine power7

Is it a gcc bug?

> I tried to reproduce your build, but I did not get any POWER4 files:
> configure --host=powerpc-linux-gnu --prefix=/usr CC="powerpc-linux-gnu-gcc"
> CFLAGS="-O2 -ggdb3 -mcpu=7450"
> 
> $ grep submachine config.log 
> libc_cv_cc_submachine=''
> submachine=''

For me -mcpu=7450 enabled mutilarch as well. Do you get it as well?

> I used commit ID 756c306502498f999fdd494477b9cea1b45e4faf.
> 
> What are you getting in your config.log?

Attached https://sourceware.org/bugzilla/attachment.cgi?id=12793, should be done against the same commit.
Comment 5 Sergei Trofimovich 2020-08-24 19:22:02 UTC
(In reply to Sergei Trofimovich from comment #4)
> (In reply to Tulio Magno Quites Machado Filho from comment #2)
> > AFAICS, powerpc 7450 can't run POWER4 code.  So, this processor shouldn't be
> > running POWER4 or POWER7 code.
> > The question that needs to be answered is: why is your build getting them?
> 
> Oh, I had no idea.
> 
> Mechanically power7 is detected at sysdeps/powerpc/preconfigure.ac:
> 
> $ echo 'int foo () { return 0; }' | powerpc-unknown-linux-gnu-gcc-10.2.0 -S
> -frecord-gcc-switches -xc -o - - | fgrep machine
>         .machine ppc
> $ echo 'int foo () { return 0; }' | powerpc-unknown-linux-gnu-gcc-10.2.0
> -mcpu=7450 -S -frecord-gcc-switches -xc -o - - | fgrep machine
>         .machine power7
> 
> Is it a gcc bug?

CCing gcc power maintainers.

My naive grep suggests -mcpu=7450 should be ppc+altivec only and not power7:

gcc/config/rs6000/driver-rs6000.c:

"""
    { "7450",   "-mppc %{!mvsx:%{!maltivec:-maltivec}}" },
""

gcc/config/rs6000/rs6000.c derives '.machine' as:

"""
#ifdef USING_ELFOS_H
const char *rs6000_machine;

const char *
rs6000_machine_from_flags (void)
{
  HOST_WIDE_INT flags = rs6000_isa_flags;

  /* Disable the flags that should never influence the .machine selection.  */
  flags &= ~(OPTION_MASK_PPC_GFXOPT | OPTION_MASK_PPC_GPOPT);

  if ((flags & (ISA_3_1_MASKS_SERVER & ~ISA_3_0_MASKS_SERVER)) != 0)
    return "power10";
  if ((flags & (ISA_3_0_MASKS_SERVER & ~ISA_2_7_MASKS_SERVER)) != 0)
    return "power9";
  if ((flags & (ISA_2_7_MASKS_SERVER & ~ISA_2_6_MASKS_SERVER)) != 0)
    return "power8";
  if ((flags & (ISA_2_6_MASKS_SERVER & ~ISA_2_5_MASKS_SERVER)) != 0)
    return "power7";
  if ((flags & (ISA_2_5_MASKS_SERVER & ~ISA_2_4_MASKS)) != 0)
    return "power6";
  if ((flags & (ISA_2_4_MASKS & ~ISA_2_1_MASKS)) != 0)
    return "power5";
  if ((flags & ISA_2_1_MASKS) != 0)
    return "power4";
  if ((flags & OPTION_MASK_POWERPC64) != 0)
    return "ppc64";
  return "ppc";
}

void
emit_asm_machine (void)
{
  fprintf (asm_out_file, "\t.machine %s\n", rs6000_machine);
}
#endif
"""
Comment 6 Andreas Schwab 2020-08-25 13:15:13 UTC
"power7" is selected because (ISA_2_6_MASKS_SERVER & ~ISA_2_5_MASKS_SERVER) contains OPTION_MASK_ALTIVEC, and mcpu=7450 adds OPTION_MASK_ALTIVEC to rs6000_isa_flags.  The whole logic in rs6000_machine_from_flags is busted.  It should check that _all_ flags are present.  Please file a bug with gcc.
Comment 7 Sergei Trofimovich 2020-08-25 14:21:02 UTC
(In reply to Andreas Schwab from comment #6)
> "power7" is selected because (ISA_2_6_MASKS_SERVER & ~ISA_2_5_MASKS_SERVER)
> contains OPTION_MASK_ALTIVEC, and mcpu=7450 adds OPTION_MASK_ALTIVEC to
> rs6000_isa_flags.  The whole logic in rs6000_machine_from_flags is busted. 
> It should check that _all_ flags are present.  Please file a bug with gcc.

Sounds good. What should '.machine' contain for -mcpu=7450? 'ppc'?

I'm asking because I'm not sure what '.machine' means for gas: upper bound on available ISA or lower bound?
Comment 8 Andreas Schwab 2020-08-25 14:44:34 UTC
.machine sets the upper bound accepted by the assembler.  It should match the mapping in the asm_names table in driver-rs6000.c.
Comment 9 Tulio Magno Quites Machado Filho 2020-08-25 16:07:02 UTC
Nice catch!
This is only happening with GCC 10:

$ gcc-10 -S -m32 -mcpu=7450 -frecord-gcc-switches -xc -o - - < /dev/null | grep -E 'mcpu|machine'
        .machine power7
        .ascii  "-mcpu=7450"
$ gcc-9 -S -m32 -mcpu=7450 -frecord-gcc-switches -xc -o - - < /dev/null | grep -E 'mcpu|machine'
        .ascii  "-mcpu=7450"
Comment 10 Segher Boessenkool 2020-08-25 18:14:44 UTC
This is gcc.gnu.org/PR96786 now.  Thanks!