elf64 (x86-64) relocation questions

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
bradbobak
Member
Member
Posts: 26
Joined: Fri Apr 14, 2006 11:00 pm

elf64 (x86-64) relocation questions

Post by bradbobak »

Hi all. So I've started my elf64 relocatable loader. (just loads output files from gcc -c somefile -o load_this.o).
I have a few questions regarding relocation.

This is the reference i've been using.
https://docs.oracle.com/cd/E19120-01/op ... index.html

All entries are of the 'rela' type.

A refers to the addend,
S refers to the location of the symbol being applied.
P refers to the memory location of the relocation (what we are modifying).
P32 is a 32-bit pointer to P
P64 is a 64-bit pointer to P.

Code: Select all

...
{ // R_AMD64_64
  *P64 = S + A;
}
...
{ // R_AMD64_PC32
  *P32 = S + A - P;
}
...
{ // R_AMD64_32
  *P32 = S + A;
}
...
{ // R_AMD64_32S
  *P32 = S + A;
}
Now, these all seem to work, but I know I'm doing something wrong.
R_AMD64_32
The computed value is truncated to 32–bits. The link-editor verifies that the generated value for the relocation zero-extends to the original 64–bit value.

R_AMD64_32S
The computed value is truncated to 32–bits. The link-editor verifies that the generated value for the relocation sign-extends to the original 64–bit value.
I'm just not understanding those 2 relocations. Am I supposed to add (S + A) as a 64-bit value, then shove the bottom 32 bits into *P32 ?
It just doesn't seem right, with the sign-extending and all. Maybe i'm supposed to use a 64-bit value, manipulate, then shove that value into *P64? (where manipulate is result & 0x00000000ffffffff for the R_AMD64_32) and if (result & (1 << 31)) then result |= 0xffffffff00000000 for R_AMD64_32S ?

Any help would be appreciated.
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Re: elf64 (x86-64) relocation questions

Post by jnc100 »

For 32/32S, essentially you do as it says - calculate S + A as a 64 bit value and then truncate it and store it at the location of the relocation. If the relocation is a 32S relocation, the truncated value needs to sign extend to the original 64 bit value. If it is a 32 relocation it needs to zero extend, otherwise you throw an error at load time (the equivalent for the static library technique is for ld to emit an error like 'relocation truncated to fit ...').

The reason there are two different relocation types is to support the way amd64 register loads work. The mov r/m64, imm32 instruction (and others e.g. add/sub/and etc that use 32 bit immediates) zero extend the value loaded, whereas 32 bit displacements following ModR/M bytes sign extend the value. This is important when compiling with the kernel code model, for example, which makes heavy use of the -2GiB to 0 portion of the address space (and allows constructs like mov rax, [-0x1000]).

I suggest you reference the official ELF docs though (rather than the oracle web site - they define some extensions which are not universally supported). Particularly you would want the ELF64 generic document and the SysV ABI amd64 processor supplement (and possibly the original 32 bit ELF one too just for a general overview).

Regards,
John.
bradbobak
Member
Member
Posts: 26
Joined: Fri Apr 14, 2006 11:00 pm

Re: elf64 (x86-64) relocation questions

Post by bradbobak »

Thank you. My elf loader now verifies.
Post Reply