Bug 1160986

Summary: gcc9 -fPIC creates unreproducible assembler code
Product: [openSUSE] openSUSE Tumbleweed Reporter: Bernhard Wiedemann <bwiedemann>
Component: DevelopmentAssignee: Michael Matz <matz>
Status: VERIFIED FIXED QA Contact: E-mail List <qa-bugs>
Severity: Normal    
Priority: P5 - None CC: rguenther
Version: Current   
Target Milestone: ---   
Hardware: x86-64   
OS: All   
See Also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93274
Found By: Development Services Priority:
Business Priority: Blocker: ---
Marketing QA Status: --- IT Deployment: ---
Attachments: test1.c

Description Bernhard Wiedemann 2020-01-15 10:27:26 UTC
Created attachment 827567 [details]

While working on reproducible builds for openSUSE, I found that
our darktables package had multiple unreproducible .o files that resulted in unreproducible .so output.

I used gcc -E $MANYARGS introspection_toneequal.c
to produce the attached test1.c reproducer.

Steps to Reproduce:
for i in 1 2 ; do gcc-9 -fPIC -S test1.c && md5sum test1.s ; done

Actual Result:
produces a different md5sum output for every run.

Expected Result:
output should be fully deterministic.

same for gcc
Comment 1 Richard Biener 2020-01-15 11:17:20 UTC
Confirmed.  Differences are all in ifunc resolver calls:

-       call    dt_simd_memcpy._GLOBAL___t.i_3D085019_0x561944bc33c36f7b.ifunc@PLT
+       call    dt_simd_memcpy._GLOBAL___t.i_3D085019_0x2106691e4ac81b0a.ifunc@PLT

where without -fPIC we don't "mangle" the symbols this way:

        call    dt_simd_memcpy._GLOBAL___dt_module_dt_version.ifunc

the testcase uses

__attribute__((target_clones("default", "sse2", "sse3", "sse4.1", "sse4.2", "popcnt", "avx", "avx2", "avx512f", "fma4")))
static inline void dt_simd_memcpy(const float *const __restrict__ in,
                                  float *const __restrict__ out,
                                  const size_t num_elem)

that the function is static is important, the following is a reduced testcase:

__attribute__((target_clones("default", "sse3")))
static void dt_simd_memcpy (const float *const __restrict__ in,
                     float *const __restrict__ out,
                     const int num_elem)
  for(int k = 0; k < num_elem; k++)
    out[k] = in[k];

void bar(float *in, float *out, int num_elem)
  dt_simd_memcpy (in, out, num_elem);
Comment 2 Richard Biener 2020-01-15 11:31:00 UTC
A workaround is to avoind making dt_simd_memcpy and friends 'static'.  GCC has
to make the ifunc resolver globally visible and has to choose a "unique" name
for this purpose.  Which is of course hard, so it tries with randomness.
Comment 3 Bernhard Wiedemann 2020-03-26 08:42:13 UTC
should be fixed in gcc10
Comment 4 Bernhard Wiedemann 2021-04-06 03:08:59 UTC
indeed, darktable builds reproducibly since gcc10