toolchain
toolchain copied to clipboard
ARCv2 relocation failure
While testing QEMU FPUv2 a GLibC test (test-fpucw-static) that didn't fail a few months ago, started failing with the most recent toolchain.
The issue seems to be because a relocation isn't completed with success.
The invocation line found by running make test t=math/test-fpucw-static
inside glibc-build folder is:
$ arc-linux-gnu-gcc -o $GLIBC_BUILD_PATH/math/test-fpucw-static \
-nostdlib \
-nostartfiles \
-static \
$GLIBC_BUILD_PATH/csu/crt1.o \
$GLIBC_BUILD_PATH/csu/crti.o \
`arc-linux-gnu-gcc --print-file-name=crtbeginT.o` \
$GLIBC_BUILD_PATH/math/test-fpucw-static.o \
$GLIBC_BUILD_PATH/support/libsupport_nonshared.a \
$GLIBC_BUILD_PATH/math/libm.a \
-Wl,--start-group \
$GLIBC_BUILD_PATH/libc.a \
-lgcc \
-lgcc_eh \
-Wl,--end-group \
`arc-linux-gnu-gcc --print-file-name=crtend.o` \
$GLIBC_BUILD_PATH/csu/crtn.o
We can see with arc-linux-gnu-objdump -d -r
that in libc.a the relocation is supposed to be
126: 0802 0000 bl 0 ;0 <__pthread_initialize_minimal>
126: R_ARC_S25W_PCREL_PLT __pthread_initialize_minimal
Linking seems to fail as the final binary has:
112d2: 0802 0000 bl 0 ;112d0 <__libc_start_main+0x74>
The symbol in question here is:
// sysdeps/generic/ldsodefs.h
# define weak_function __attribute__ ((weak))
void __pthread_initialize_minimal (void) weak_function;
// csu/libc-start.c
void
__pthread_initialize_minimal (void)
{
_init_routine (__libc_stack_end); // <-- static void function
}
And the problematic usage:
// csu/libc-start.c
if (__pthread_initialize_minimal != NULL)
__pthread_initialize_minimal ();
Attachment: comp.1.zip comp.2.zip
$ cat comp.{1,2}.zip > comp.tar.xz
There are a number of R_ARC_GOTPC32
which are resolved to point to the first entry in the .got
section. Here are the symbols in cause:
__call_tls_dtors
__mq_notify_fork_subprocess
__nss_database_fork_prepare_parent
__nss_database_fork_subprocess
__pthread_initialize_minimal
stderr
__timer_fork_subprocess
All the above with the exception of stderr
are weak undefined symbols. Needless to say the first location of .got
is initialized with the value of stderr
namely 00088398 D stderr
.
One of the errors is seen bellow:
112b0: 2730 7f82 0007 6b10 ld r2,[pcl,0x76b10] ;87dc0 <.got>
112b4: R_ARC_GOTPC32 __pthread_initialize_minimal
112b8: 7a4b tst_s r2,r2
112ba: 1100 2002 ld r2,[r17]
112be: 2700 7f83 0007 5d48 add r3,pcl,0x75d48 ;87004 <__stack_chk_guard>
112c2: R_ARC_PC32 __stack_chk_guard
112c6: 4244 ld_s r2,[r2,0]
112c8: 226c 01c2 bmskn r2,r2,0x7
112cc: 000a 0021 beq.d 10 ;112d6 <__libc_start_main+0x7a>
112d0: a340 st_s r2,[r3,0]
112d2: 0802 0000 bl 0 ;112d0 <__libc_start_main+0x74>
112d2: R_ARC_S25W_PCREL_PLT __pthread_initialize_minimal
The R_ARC_S25W_PCREL_PLT
is correctly resolved to zero, as the __pthread_initialize_minimal
symbol is undefined weak. However, the R_ARC_GOTPC32
is pointing to the first entry of .got
section which is actually the entry for stderr
. Thus, instead of returning zero in r2
register, it returns stderr
value. Hence, the error.
A reduced test case:
#include <stddef.h>
#include <stdio.h>
# define weak_function __attribute__ ((weak))
void __pthread_initialize_minimal (void) weak_function;
extern void abort (void);
int main (void)
{
if (stderr == NULL)
abort ();
if (__pthread_initialize_minimal != NULL)
__pthread_initialize_minimal ();
return 0;
}