[Bug c/84908] New: retpoline weirdness: 7.3.0-1 and 4.8.5-16: with -fPIC: R_X86_64_PC32 against undefined symbol `__x86_indirect_thunk_rax'
jason.vas.dias at gmail dot com
gcc-bugzilla@gcc.gnu.org
Fri Mar 16 14:48:00 GMT 2018
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84908
Bug ID: 84908
Summary: retpoline weirdness: 7.3.0-1 and 4.8.5-16: with -fPIC:
R_X86_64_PC32 against undefined symbol
`__x86_indirect_thunk_rax'
Product: gcc
Version: unknown
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c
Assignee: unassigned at gcc dot gnu.org
Reporter: jason.vas.dias at gmail dot com
Target Milestone: ---
This bug occurs under Linux x86_64 with
gcc-4.8.5-16, as delivered in the latest RHEL7-4x package:
gcc-4.8.5-16.el7_4.2.x86_64
and with the compiler used by kernel.org's automated patch tester:
kbuild test robot<lkp@intel.com>
config: x86_64-rhel
compiler: gcc-7 (Debian 7.3.0-1) 7.3.0 ,
ONLY when trying to build the Linux vDSO,
ONLY IFF the switch in
${LINUX_KERNEL_SOURCE}/arch/x86/entry/vclock_gettime.c 's
__vdso_gettime() function contains MORE THAN 5 CLAUSES,
such as:
<quote><pre><code>
notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
{
switch (clock) {
case CLOCK_REALTIME:
if (do_realtime(ts) == VCLOCK_NONE)
goto fallback;
break;
case CLOCK_MONOTONIC:
if (do_monotonic(ts) == VCLOCK_NONE)
goto fallback;
break;
case CLOCK_MONOTONIC_RAW:
if (do_monotonic_raw(ts) == VCLOCK_NONE)
goto fallback;
break;
case CLOCK_REALTIME_COARSE:
do_realtime_coarse(ts);
break;
case CLOCK_MONOTONIC_COARSE:
do_monotonic_coarse(ts);
break;
default:
goto fallback;
}
return 0;
fallback:
return vdso_fallback_gettime(clock, ts);
}
</code></pre></quote>
The 7.3.0-1 compiler and 4.8.5-16 compilers both now complain
on the final link :
<quote><pre><code>
arch/x86/entry/vdso/vclock_gettime.o: In function `__vdso_clock_gettime':
vclock_gettime.c:(.text+0xf7): undefined reference to
`__x86_indirect_thunk_rax'
/usr/bin/ld: arch/x86/entry/vdso/vclock_gettime.o: relocation R_X86_64_PC32
against undefined symbol `__x86_indirect_thunk_rax' can not be used when making
a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
</code></pre></quote>
Note all objects are being compiled with -fPIC in this case.
I can reproduce this with the 4.8.5-16 compiler under RHEL-7.4 :
<quote><pre><code>
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/4.8.5/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man
--infodir=/usr/share/info --with-bugurl=http://bugzilla.redhat.com/bugzilla
--enable-bootstrap --enable-shared --enable-threads=posix
--enable-checking=release --with-system-zlib --enable-__cxa_atexit
--disable-libunwind-exceptions --enable-gnu-unique-object
--enable-linker-build-id --with-linker-hash-style=gnu
--enable-languages=c,c++,objc,obj-c++,java,fortran,ada,go,lto --enable-plugin
--enable-initfini-array --disable-libgcj
--with-isl=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/isl-install
--with-cloog=/builddir/build/BUILD/gcc-4.8.5-20150702/obj-x86_64-redhat-linux/cloog-install
--enable-gnu-indirect-function --with-tune=generic --with-arch_32=x86-64
--build=x86_64-redhat-linux
Thread model: posix
gcc version 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)
$ cd $LINUX_KERNEL_SOURCE
$ make arch/x86/vdso/
...
make KBUILD_MODULES=1 \
-f scripts/Makefile.build obj=arch/x86/vdso
gcc -Wp,-MD,arch/x86/vdso/.vclock_gettime.o.d -nostdinc -isystem
/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include -I./arch/x86/include
-Iarch/x86/include/generated -Iinclude -I./arch/x86/include/uapi
-Iarch/x86/include/generated/uapi -I./include/uapi -Iinclude/generated/uapi
-include ./include/linux/kconfig.h -D__KERNEL__ -Wall -Wundef
-Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common
-Werror-implicit-function-declaration -Wno-format-security
-fno-delete-null-pointer-checks -std=gnu89 -Werror -O2 -m64 -mno-mmx -mno-sse
-mpreferred-stack-boundary=3 -mtune=generic -mno-red-zone -mcmodel=kernel
-funit-at-a-time -maccumulate-outgoing-args -Wframe-larger-than=2048
-DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1 -DCONFIG_AS_CFI_SECTIONS=1
-DCONFIG_AS_FXSAVEQ=1 -DCONFIG_AS_AVX=1 -DCONFIG_AS_AVX2=1 -DCONFIG_AS_AVX512=1
-DCONFIG_AS_SHA1_NI=1 -DCONFIG_AS_SHA256_NI=1 -pipe -Wno-sign-compare
-fno-asynchronous-unwind-tables -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx
-mindirect-branch=thunk-extern -mindirect-branch-register -DRETPOLINE
-Wframe-larger-than=2048 -fstack-protector-strong -Wno-unused-but-set-variable
-fno-omit-frame-pointer -fno-optimize-sibling-calls -g -mfentry
-DCC_USING_FENTRY -fno-inline-functions-called-once
-Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow
-fconserve-stack -DCC_HAVE_ASM_GOTO -mcmodel=small -fPIC -O2
-fasynchronous-unwind-tables -m64 -g -fno-stack-protector
-fno-omit-frame-pointer -foptimize-sibling-calls -D"KBUILD_STR(s)=#s"
-D"KBUILD_BASENAME=KBUILD_STR(vclock_gettime)"
-D"KBUILD_MODNAME=KBUILD_STR(vclock_gettime)" -c -o
arch/x86/vdso/.tmp_vclock_gettime.o arch/x86/vdso/vclock_gettime.c
if [ "" = "-pg" ]; then if [ arch/x86/vdso/vclock_gettime.o !=
"scripts/mod/empty.o" ]; then ./scripts/recordmcount
"arch/x86/vdso/vclock_gettime.o"; fi; fi;
gcc -nostdlib -o arch/x86/vdso/vdso.so.dbg -fPIC -shared
-Wl,--hash-style=sysv -m64 -Wl,-soname=linux-vdso.so.1 -Wl,--no-undefined
-Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
-Wl,-T,arch/x86/vdso/vdso.lds arch/x86/vdso/vdso-note.o
arch/x86/vdso/vclock_gettime.o arch/x86/vdso/vgetcpu.o && sh
./arch/x86/vdso/checkundef.sh 'nm' 'arch/x86/vdso/vdso.so.dbg'
arch/x86/vdso/vclock_gettime.o: In function `__vdso_clock_gettime':
/home/devel/redhat/BUILD/kernel-3.10.0-693.21.1.el7/linux-3.10.0-693.21.1.el7.jvd.x86_64/arch/x86/vdso/vclock_gettime.c:279:
undefined reference to `__x86_indirect_thunk_rax'
/usr/bin/ld: arch/x86/vdso/vclock_gettime.o: relocation R_X86_64_PC32 against
undefined symbol `__x86_indirect_thunk_rax' can not be used when making a
shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
objcopy -S arch/x86/vdso/vdso.so.dbg arch/x86/vdso/vdso.so
objcopy: 'arch/x86/vdso/vdso.so.dbg': No such file
make[1]: *** [arch/x86/vdso/vdso.so] Error 1
</code></pre><quote>
The problem is very simply fixed, by simply making sure that
the switch statement has no more than 5 clauses:
<quote><pre><code>
notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
{
switch (clock) {
case CLOCK_MONOTONIC_RAW:
if (do_monotonic_raw(ts) == VCLOCK_NONE)
goto fallback;
break;
default:
switch (clock) {
case CLOCK_REALTIME:
if (do_realtime(ts) == VCLOCK_NONE)
goto fallback;
break;
case CLOCK_MONOTONIC:
if (do_monotonic(ts) == VCLOCK_NONE)
goto fallback;
break;
case CLOCK_REALTIME_COARSE:
do_realtime_coarse(ts);
break;
case CLOCK_MONOTONIC_COARSE:
do_monotonic_coarse(ts);
break;
default:
goto fallback;
} }
</code></pre></quote>
So with only that change, the code compiles fine and
no relocation against __x86_indirect_thunk_rax remains.
This problem did not happen with the previous version
of the RHEL compiler (4.8.5-16.el7_4.2.x86_64), which
compiled the 6 clause version of the switch shown at
the top with no problems, when I first developed the
patch against kernel-3.10.0-693.17.1.el7 .
In order for the bug to be triggered, the extra clause
in the switch must invoke some function that returns
the 'ret' value and references &vvar_vsycall_gtod_data:
<quote><pre><code>
static inline __always_inline int test(void)
{ unsigned long seq;
do{ seq = read_seqcount_begin(>od->seq);
} while(unlikely(read_seqcount_retry, >od->seq, seq));
return 0;
}
notrace int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
{ ... int ret;
switch (clock) {
case CLOCK_REALTIME:
ret = do_realtime(ts);
break;
case CLOCK_MONOTONIC:
ret = do_monotonic(ts);
break;
case CLOCK_MONOTONIC_RAW:
ret = test();
break;
case CLOCK_REALTIME_COARSE:
ret = do_realtime_coarse(ts);
break;
case CLOCK_MONOTONIC_COARSE:
ret = do_monotonic_coarse(ts);
break;
default:
break;
}
if (ret == VCLOCK_NONE)
return vdso_fallback_gettime(clock, ts);
return 0;
}
</code></pre></quote>
So the problem is not to do with my implementation of
do_monotonic_raw() , but with accessing the special
vvar_vsyscall_gtod_data, and possibly with an interaction
between the 'smp_rmb' used by read_seqcount_begin()
(now gtod_read_begin() in modern kernels).
So now when I've upgraded the patch to the latest 4.16 / 4.15
version (shown at the top of this bug report) the 7.3.0-1
compiler used by the Kernel's automated tester is also
getting this problem.
It is a shame to have to insert an extra test of the 'clock'
parameter here, just to work around this problem, but it
appears to be the only way.
I don't think GCC should be inserting any relocations with -fPIC
in this situation, should it ?
And since the previous RHEL-7 compiler compiled the same code fine,
I think this is a regression / bug.
I'd greatly appreciate any advice on what the precise cause of this
is and how to fix without inserting the extra test / switch statement.
Thanks & Best Regards,
Jason
More information about the Gcc-bugs
mailing list