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