This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: REL vs. RELA: how to choose?


Hi Greg,

: What are the processor-architecture features that might make one or 
: the other of REL vs. RELA necessary or more convenient?

Generally speaking I would always recommend using RELA relocations if
you have the choice.  I would only suggest using REL relocations if
the ABI requires it, or if it is really important to keep down the
size of object files (or executables that still contain relocs).

: With REL, Is the "implicit addend" referred to above those bits 
: assembled into the relocatable field of the insn?  E.g., assembler
: stores `jmp 0x100', the text segment is linked at 0x2000, so after
: relocation the insn becomes `jmp 0x2100'.  The target address is
: computed as 0x2000+0x100, with 0x2000 coming from the start of the
: .text segment, and the 0x100 coming from the contents of the jmp insn
: field (the "implicit addend"?).  Is this correct, or am I confused?

No, you are correct.

: How would the jmp insn in the previous example be assembled for
: RELA?  Would the assembler store `jmp 0', and put 0x100 into the
: r_addend field of the relocation entry?  Is this correct, or am I
: confused?

You are correct.


One reason for preferring RELA relocations is that the REL format can
have some hidden restrictions.  Consider for example an ISA where a 32
bit constant cannot be loaded by a single instruction but has to be
done in two parts - a high 16 bit load followed by a low 16 bit load.
The assembler to load the address of element 0xffffff of an array 'foo'
into register 1 might look something like this:

  LOAD_HI r1, hi(foo + 0xffffff)
  ADD     r1, lo(foo + 0xffffff)

which would generate two separate relocs, one for the hi() expression
and one for the lo() expression.  If the file format uses REL
relocations then the 0xffffff value would have to be stored in the
LOAD_HI or ADD instructions, which presumably only have a 16 bit
relocatable field - not big enough to hold 0xffff.

In theory though, you could split the constant between the two relocs,
like this:

  LOAD_HI r1, 0xff
    RELOC_HIGH_16_BITS (foo)
  ADD     r1, 0xffff
    RELOC_LOW_16_BITS (foo)

But the problem here is overflow.  Suppose the address of 'foo' is
0x000000001.  The computation for the RELOC_HIGH_16_BITS will be:

    ((0xff << 16) + 0x00000001) >> 16
or
    0x00ff

but the computation for the RELOC_LOW_16_BITS will be:

    (0xffff + 0x00000001) & 0xffff
or
    0x0000

So the final address loaded into register 1 will be:

  0x00ff0000
 +0x00000000
  ----------
  0x00ff0000

instead of the correct address of:

  0x00ffffff
 +0x00000001
  ----------
  0x01000000

So the RELOC_LOW_16_BITS needs to be able to tell the
RELOC_HIGH_16_BITS that its computation overflow, which can be tricky
if the two relocs are not next to each other, and very tricky when
clever compiler decide that multiple references to elements of 'foo'
can be optimised into only on LOAD_HI with multiple ADD instructions
afterwards...

Cheers
	Nick

  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]