A couple of folks have come across the following relocation error when running their applications on AMD64:

  $ prog
  ld.so.1: prog: fatal: relocation error: R_AMD64_32: file \\
      libfoo.so.1: symbol (unknown): value 0xfffffd7fff0cd457 does not fit

The culprit, libfoo.so.1 has been built using position dependent code (often referred to as non-pic).

Shared objects are typically built using position independent code, using compiler options such as -Kpic. This position independence allows the code to execute efficiently at a different address in each process that uses the code.

If a shared object is built from position-dependent code, the text segment can require modification at runtime. This modification allows relocatable references to be assigned to the location that the object has been loaded. The relocation of the text segment requires the segment to be remapped as writable. This modification requires a swap space reservation, and results in a private copy of the text segment for the process. The text segment is no longer sharable between multiple processes. Position-dependent code typically requires more runtime relocations than the corresponding position-independent code. Overall, the overhead of processing text relocations can cause serious performance degradation.

When a shared object is built from position-independent code, relocatable references are generated as indirections through data in the shared object’s data segment. The code within the text segment requires no modification. All relocation updates are applied to corresponding entries within the data segment.

The runtime linker attempts to handle text relocations should these relocations exist. However, some relocations can not be satisfied at runtime.

The AMD64 position-dependent code sequence typically generates code which can only be loaded into the lower 32-bits of memory. The upper 32-bits of any address must all be zeros. Since shared objects are typically loaded at the top of memory, the upper 32-bits of an address are required. Position-dependent code within an AMD64 shared object is therefore insufficient to cope with relocation requirements. Use of such code within a shared object can result in runtime relocation errors cited above.

This situation differs from the default ABS64 mode that is used for 64-bit SPARCV9 code. This position-dependent code is typically compatible with the full 64-bit address range. Thus, position-dependent code sequences can exist within SPARCV9 shared objects. Use of either the ABS32 mode, or ABS44 mode for 64-bit SPARCV9 code, can still result in relocations that can not be resolved at runtime. However, each of these modes require the runtime linker to relocate the text segment.

Build all your shared objects using position independent code.

Update – Wednesday March 21, 2007

If you believe you have compiled all the components of your shared object using -Kpic, and still see an error of this sort, look a little more closely. First, determine if the link-editor thinks the shared object contains text relocations.

$ elfdump -d library | fgrep TEXTREL

If this flag is found, then the link-editor thinks this file contains non-pic code. One explanation might be that you have include an assembler file in the shared library. Any assembler must be written using position-independent instructions. Another explanation is that you might have included objects from an archive library as part of the link-edit. Typically, archives are built with non-pic objects.

You can track down the culprit from the link-editors debugging capabilities. Build your shared object.

$ LD_OPTIONS=-Dreloc,detail cc -o library .... 2> dbg

The diagnostic output in dbg can be inspected to locate the non-pic relocation, and from this you can trace back to the input file that supplied the relocation as part of building your library.

Update – Wednesday April 14, 2010

A question arose on how to interpret the diagnostic output so as to determine which input file is non-pic. You can look for the “creating output relocations” information. These are the relocation records that are created in the output file, and must be processed at runtime. The non-pic relocations will probably be against the .text section. So, if you have:

debug: creating output relocations
debug:        type             offset     addend  section        symbol
debug:      R_SPARC_HI22        0x4d4          0  .SUNW_reloc    foo1

Then you can associate the offset with an output section:

% elfdump -cN.text output-file.so 
  Section Header[7]:  sh_name: .text
    sh_addr:      0x4c0           sh_flags:   [ SHF_ALLOC SHF_EXECINSTR ]
    sh_size:      0x28            sh_type:    [ SHT_PROGBITS ]
    sh_offset:    0x4c0           sh_entsize: 0
    ...

Another aid might be to also use the link-editors -znocombreloc option. This suppresses the normal combination of output relocations sections, and might provide for a more informative diagnostic:

debug: creating output relocations
  debug:      type             offset     addend  section        symbol
  debug:    R_SPARC_HI22        0x4d4          0  .rela.text     foo1

Here you can now see that the relocation is against the .text section.

Having found a non-pic relocation, search back in the diagnostics and try and find the matching input relocation using the relocation type and symbol name. You should find something like:

debug: collecting input relocations: section=.text, file=foo.o
  debug:        type            offset     addend  section        symbol
  debug:   in R_SPARC_HI22        0x14          0  [13].rela.text foo1
  debug:  out R_SPARC_HI22        0x14          0  .text          foo1

Here, the input relocation is against the text section (.rela.text), and to provide for this, an output relocation must be produced against the .text section. The non-pic culprit is the file foo.o.

You might be able to discover your non-pic relocations by just scanning through the “collecting input relocations” information. But for large links this can be a substantial amount of information to digest.