Amd64 relocation R_X86_64_32S in a static lib

Torbjorn Granlund tg at gmplib.org
Tue Nov 5 18:03:45 CET 2013


nisse at lysator.liu.se (Niels Möller) writes:

  I don't understand the fine details of which reloc types make sense in
  pic code, but if I understand Philip correctly, the main problem is not
  a ABI change, but changed compiler default. And then you get link errors
  when linking together pic objects created by the compiler, with non-pic
  objects created from the gmp assembly files.
  
Let's look at a (non-GMP) example:

typedef int (*jumpent_t)(int);
jumpent_t (jumptab)[10];
int foo (int i)
{
  return jumptab[i](17);
}

On OpenBSD pre-5.3 using the system compiler, one gets

        movl    $17, %edi
        call    *jumptab(,%rax,8)

for the call through jumptab.

On OpenBSD 5.3 again with the system compiler, one gets

        movl    $17, %edi
        movq    jumptab at GOTPCREL(%rip), %rdx
        call    *(%rdx,%rax,8)

for the same code.  I didn't pass any PIC options in either case.  (On
any *BSD or GNU/Linux system, passing -fpic presumably causes the latter
code to be generated.)

The former is implicitly an R_X86_64_32S reloc and the latter is quite
explicitly an R_X86_64_GOTPCREL.

If one tries to assemble and link the former code on a 5.3/5.4 system,
one gets again the error "relocation R_X86_64_32S can not be used when
making a shared object; recompile with -fPIC".

I'd call this an ABI change since code valid under the AMD64 ELF ABI as
well as on older OpenBSD releases is no longer supported.

Using another S + A type reloc works, as demonstrated by code like

	movl	$17, %edi
	movabsq	$jumptab, %rcx
	call	*(%rcx,%rax,8)

and this makes no sense since this is not position independent without
ugly load-time patching.

  I think you'd get similar problems as if a user configures gmp with,
  e.g., --disable-shared CFLAGS=-fpic. Do you agree with this analysis?
  
I'd expect that to work on all present systems, actually.  Since -fpic
does not reserve any register, mixing in some PIC code will not hurt
(except perhaps performance).

  To figure out if an invocation $(CC) $(CFLAGS) generates pic code or
  not, one needs a configure test like
  
    AC_TRY_COMPILE(
    ...
    #if __PIC__
    #error
    bla bla
    #endif
    ...
    )
  
  Using the result of that test when deciding whether or not assembly
  files should use pic mode should give the correct behavior, both with
  compilers doing pic by default, and users enabling it explicitly.
  
That might work, but I wouldn't bet on that such a test would be as
resilient as one could hope for.  It is certainly not hard to make a gcc
configuration which generates PIC code always without setting __PIC__,
intensionally or unintensionally.

A more resilient test might use a few non-PIC relocs such as S + A and
try assembly+link.

(There are pros and cons with feature tests, though.  I consider the
free software OSes out there to be primary targets for GMP, and I'd like
to avoid creating GMP objects that cannot be moved between FooBSD x.y
and FooBSD x.y+k.  Knowing the ABIs and complying to them, using a
greatest common denominator of working code, might be better.  Then
compiled GMP and linked GMP application will move between OS releases.)


For reference, the AMD64 ABI document is here:

   http://www.x86-64.org/documentation/abi.pdf

The relocs are summarised on page 71 with explanation of the various
symbols like A (addend) and S (symbol) on page 70.

-- 
Torbjörn


More information about the gmp-devel mailing list