libgmp.a text relocation error on powerpc-*
George Koehler
kernigh at gmail.com
Fri Sep 10 22:18:39 UTC 2021
Hello,
This report is for GMP 6.2.1. The powerpc32 asm in the static library
libgmp.a contains a text relocation; this causes a linker error when I
use LLD to link a program with libgmp.a. I have no problem with the
shared library.
The fix is simple: delete the quotes on `PIC_ALWAYS' in m4-asm.def:
--- mpn/asm-defs.m4.orig
+++ mpn/asm-defs.m4
@@ -1051,7 +1051,7 @@ dnl Normally PIC is defined (or not) by libtool, but
dnl systems which are always PIC. PIC_ALWAYS established in config.m4
dnl identifies these for us.
-ifelse(`PIC_ALWAYS',`yes',`define(`PIC')')
+ifelse(PIC_ALWAYS,`yes',`define(`PIC')')
dnl Various possible defines passed from the Makefile that are to be tested
configure has put define(<PIC_ALWAYS>,<yes>) in my config.m4, but
the ifelse had quotes around `PIC_ALWAYS', so it doesn't expand the
macro. It checks whether the literal string "PIC_ALWAYS" matches the
literal string "yes", which is never true, so it never does the
define(`PIC'), but this define would fix my problem.
I'm running OpenBSD-current on an old PowerPC Macintosh which uses
powerpc32 asm:
$ cc -v
OpenBSD clang version 11.1.0
Target: powerpc-unknown-openbsd6.9
Thread model: posix
InstalledDir: /usr/bin
$ ld -v
LLD 11.1.0 (compatible with GNU linkers)
$ uname -a
OpenBSD wisconsin.my.domain 7.0 GENERIC#7 macppc
$ ./config.guess
powerpc-unknown-openbsd7.0
$ ./configfsf.guess
powerpc-unknown-openbsd7.0
In the last release, OpenBSD 6.9, the default ld for macppc was ld.bfd
(GNU ld). I am running OpenBSD-current (between 6.9 and 7.0), where
the default ld has changed to ld.lld (LLD from LLVM). This is
important, because I get the linker error from LLD.
To demonstrate the linker error, I build GMP 6.2.1 with no patches.
I skip the shared library to save time,
$ cd gmp-6.2.1/
$ ./configure --disable-shared
...
checking whether compiler output is PIC by default... yes...
configure: summary of build options:
Version: GNU MP 6.2.1
Host type: powerpc-unknown-openbsd7.0
ABI: 32
Install prefix: /usr/local
Compiler: cc
Static libraries: yes
Shared libraries: no
$ make
...
My example divide.c calls mpz_fdiv_q(). When I try to link it to
libgmp.a, I see a linker error:
$ cd ..
$ cat divide.c
#include <err.h>
#include <gmp.h>
#include <stdio.h>
int
main(int argc, char **argv) {
mpz_t x, y;
if (argc != 3) errx(1, "usage: ./divide x y");
mpz_init_set_str(x, argv[1], 10);
mpz_init_set_str(y, argv[2], 10);
mpz_fdiv_q(x, x, y);
printf("%s\n", mpz_get_str(NULL, 10, x));
}
$ cc -o divide divide.c -Igmp-6.2.1 gmp-6.2.1/.libs/libgmp.a
ld: error: can't create dynamic relocation R_PPC_ADDR16_HA against local symbol in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
>>> defined in gmp-6.2.1/.libs/libgmp.a(invert_limb.o)
>>> referenced by tmp-invert_limb.s
>>> invert_limb.o:(__gmpn_invert_limb) in archive gmp-6.2.1/.libs/libgmp.a
ld: error: can't create dynamic relocation R_PPC_ADDR16_LO against local symbol in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output
>>> defined in gmp-6.2.1/.libs/libgmp.a(invert_limb.o)
>>> referenced by tmp-invert_limb.s
>>> invert_limb.o:(__gmpn_invert_limb) in archive gmp-6.2.1/.libs/libgmp.a
cc: error: linker command failed with exit code 1 (use -v to see invocation)
(If you are running OpenBSD 6.9 on macppc, where the default ld is
ld.bfd, then "cc -fuse-ld=lld" might reproduce the above error.)
These relocations come from gmp-6.2.1/mpn/powerpc32/invert_libm.asm
at LEA(r9, approx_tab); powerpc32/m4.elf defines LEA. This GMP has
no patches, so its libgmp.a didn't define PIC. The expansion of LEA
without PIC is,
lis r9, approx_tab at ha
la r9, approx_tab at l(r9)
This would load r9 with the 32-bit address of approx_tab, where the
address is in the program text. OpenBSD uses PIE position-independent
executables by default. PIEs are dynamically relocated, so the
address of approx_tab isn't known until runtime. The program would
need to overwrite the text with the relocated address of approx_tab.
This is awkward, because the program text is normally readonly.
A configure check, GMP_ASM_POWERPC_PIC_ALWAYS in acinclude.m4,
correctly observes that my clang outputs PIC by default, and does
define(<PIC_ALWAYS>,<yes>) in my config.m4. The problem is that
gmp ignores this check, unless I delete the quotes on `PIC_ALWAYS'
in asm-defs.m4. After I delete the quotes, the LEA expansion uses
the PIC asm and avoids the text relocation. I installed a libgmp.a
with the quote fix, and it works; floor(100 / 11) is 9:
$ cc -o divide divide.c $(pkg-config --cflags --libs gmp) -static
$ ./divide 100 11
9
PIC_ALWAYS is only relevant for powerpc32 and powerpc64. I have
another computer running OpenBSD/powerpc64; its 64-bit gmp works both
with and without the quote fix. If you want more info about my
problem, do reply to this mail.
--George
More information about the gmp-bugs
mailing list