https://sourceware.org/bugzilla/show_bug.cgi?id=23870
Bug ID: 23870
Summary: gold does not resolve the address of main when main is
in a shared library
Product: binutils
Version: 2.31
Status: NEW
Severity: normal
Priority: P2
Component: gold
Assignee: ccoutant at gmail dot com
Reporter: stephen.kim at oracle dot com
CC: ian at airs dot com
Target Milestone: ---
This is reproducible on aarch64. I got notice this issue due to the Go tools.
However, here is the reduced test case purely in C.
When a PIC shared library that has the "main" function is linked against a
non-PIC .o file to form a non-PIE executable, Gold and the GNU linker both use
crti.o. Only Gold does not find the address of main properly. The address is 0
in the generated executable, which leads the segmentation fault at runtime.
Here is my reduced example:
$ cat main.c
#include
extern int foo(int, int);
int main()
{
printf("%d\n", foo(1, 3));
return 0;
}
$ cat foo.c
int __attribute__ ((noinline)) foo(int x, int y)
{
return x & y;
}
$ gcc -o main.o -fPIC -c main.c
$ gcc -shared -o libmain.so main.o
$ gcc -o foo.o -c foo.c
$ gcc -fuse-ld=gold -o a.out -lmain -L$PWD -Wl,-v,-rpath=$PWD foo.o
collect2 version 4.8.5 20150623 (Red Hat 4.8.5-28.0.4)
/usr/bin/ld.gold --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu
-dynamic-linker /lib/ld-linux-aarch64.so.1 -X -o a.out
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64/crt1.o
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64/crti.o
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/crtbegin.o -L/home/aion1223/shared
-L/usr/lib/gcc/aarch64-redhat-linux/4.8.5
-L/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64 -L/lib/../lib64
-L/usr/lib/../lib64 -L/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../.. -lmain
-v -rpath=/home/aion1223/shared foo.o -lgcc --as-needed -lgcc_s --no-as-needed
-lc -lgcc --as-needed -lgcc_s --no-as-needed
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/crtend.o
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64/crtn.o
GNU gold (version 2.27-28.base.0.2.el7_5.1) 1.12
$ ./a.out
Segmentation fault (core dumped)
If I replace -fuse-ld=gold with -fuse-ld=bfd, it works. The crti.o is still
preferred over Scrti.o.
This started to happen once glibc is updated. The difference is start.S in
glibc has changed to use so called MOVL macro. It is defined in glibc's
sysdep.h.
/* Load an immediate into R.
Note R is a register number and not a register name. */
#ifdef __LP64__
# define MOVL(R, NAME) \
movzPTR_REG (R), #:abs_g3:NAME; \
movkPTR_REG (R), #:abs_g2_nc:NAME; \
movkPTR_REG (R), #:abs_g1_nc:NAME; \
movkPTR_REG (R), #:abs_g0_nc:NAME;
#else
# define MOVL(R, NAME) \
movzPTR_REG (R), #:abs_g1:NAME; \
movkPTR_REG (R), #:abs_g0_nc:NAME;
#endif
The start.S has a code like MOVL(0, main), and after linking, 0 is assigned to
x0. That code is only for non-PIC/PIE.
Also, if main is in the .o file rather than in the .so file, both linkers had
no problem:
$ gcc -fPIC -o foo.o -c foo.c
$ gcc -shared -o libfoo.so foo.o
$ gcc -o main.o -c main.c
$ gcc -fuse-ld=gold -o a.out -lfoo -L$PWD -Wl,-v,-rpath=$PWD main.o
collect2 version 4.8.5 20150623 (Red Hat 4.8.5-28.0.4)
/usr/bin/ld.gold --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu
-dynamic-linker /lib/ld-linux-aarch64.so.1 -X -o a.out
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64/crt1.o
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64/crti.o
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/crtbegin.o -L/home/aion1223/shared2
-L/usr/lib/gcc/aarch64-redhat-linux/4.8.5
-L/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64 -L/lib/../lib64
-L/usr/lib/../lib64 -L/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../.. -lfoo -v
-rpath=/home/aion1223/shared2 main.o -lgcc --as-needed -lgcc_s --no-as-needed
-lc -lgcc --as-needed -lgcc_s --no-as-needed
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/crtend.o
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64/crtn.o
GNU gold (version 2.27-28.base.0.2.el7_5.1) 1.12
$ ./a.out
1
$ gcc -fuse-ld=bfd -o a.out -lfoo -L$PWD -Wl,-v,-rpath=$PWD main.o
collect2 version 4.8.5 20150623 (Red Hat 4.8.5-28.0.4)
/usr/bin/ld.bfd --build-id --no-add-needed --eh-frame-hdr --hash-style=gnu
-dynamic-linker /lib/ld-linux-aarch64.so.1 -X -o a.out
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64/crt1.o
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64/crti.o
/usr/lib/gcc/aarch64-redhat-linux/4.8.5/crtbegin.o -L/home/aion1223/shared2
-L/usr/lib/gcc/aarch64-redhat-linux/4.8.5
-L/usr/lib/gcc/aarch64-redhat-linux/4.8.5/../../../../lib64 -L/lib/../lib64
-L/usr/lib/../lib64 -L/usr/lib/gcc/aarch64-redhat-linux/4.8.5/.