Questions about ld h->pointer_equality_needed on x86-64

Michael Matz matz@suse.de
Thu Mar 27 17:20:41 GMT 2025


Hello,

On Thu, 27 Mar 2025, Jens Remus wrote:

> IIUC and (over)simplified scan_relocs sets h->pointer_equality_needed
> on x86-64 [2] in case of the following relocation types.  Presumably
> the intention is that these are assumed to be used in address taking
> context, requiring pointer equality, whereas e.g. R_X86_64_PLT32
> would be assumed to be used in function call context, which does
> not require pointer equality.

That's basically the modus operandi, yes.  But history or rather existing 
code needed to be taken into account, the pointer_equality_needed checking 
came after the initial x86-64 implementation.  Those initial 
implementation could use PC32 also for calls (we weren't always rewriting 
into PLT32), and so including them into pointer_equality_needed would 
break old existing .o files (or regress speed/functionality in different 
context).

Oh, and pointer_equality_needed was introduced mostly for adress-taking of 
function symbols, not for data objects.  It's used for both, but really 
necessary in the real world it is only for function symbols.  That also 
needs to be taken into account when thinking about strange aspects of it 
:)

> - R_X86_64_8
> - R_X86_64_16
> - R_X86_64_32
> - R_X86_64_32S
> - R_X86_64_64, iff in SEC_READONLY
> - R_X86_64_PC8
> - R_X86_64_PC16
> - R_X86_64_PC32, iff not in SEC_CODE
> 
> Why are/were R_X86_64_PC64 and previously also R_X86_64_PC32 explicitly
> excluded?  I could not find any explanation in the Git history.

PC32, see above.  PC64: not 100% certain, but my guesses are: (a) 
people didn't even know that it's a thing :) or (b) to do the same as 
PC32, which somewhat makes sense.

> Wouldn't lea with R_X86_64_PC32 instead of movl with R_X86_64_32S also
> be valid?
> Then restricting R_X86_64_PC32 to non-SEC_CODE would be wrong.

The pointer_equality_needed flag is basically set optimistically to false 
on x86-64 (in the sense that it's sometimes not set, even though it would 
be correct to do so).  Only in situations where we know that a use 
certainly must be an address-taken, do we set it.  PC32 in non-CODE 
sections fits that, it's unrealistic to have that situation and then not 
somehow using the address such that equality might matter.  For PC32 in 
CODE sections, again see above.  It could be a non-address-use, so we 
don't record it as address-use.

PC32S is similar, just that it cannot occur (realistically) in non-CODE 
sections anyway, so all occurrences are regarded as 
might-be-non-address-use.

In a way, pointer_equality_needed was introduced and implemented such that 
the use-cases for which it was invented do work (with toolchains from that 
time), without disturbing other realistic usecases.  The end result is a 
bit confusing, as you found out :)

For a new architecture, or one where one has relatively tight control, it 
may be better to implement what might make most sense in the obvious way.

> Why are R_X86_64_8, R_X86_64_16, R_X86_64_32 included?

Any realistic use of these relocations will definitely be interested in 
the address (or parts of it), and not in the value, so it's regarded as 
address-use.

> How are addresses of functions taken using these? 

What do you mean?  With the _8/16 relocs?  I guess a conceivable toolchain 
could use those relocs for such C construct, however strange it may be:

   extern int foo(void);
   unsigned char lowbitsoffooaddress = 0xff & ((long)&foo);

Clearly you can't do very many interesting things with low bits of 
addresses, except inspecting them for what they are: pieces of an 
address.  So that's regarded as address-use.


Ciao,
Michael.


More information about the Binutils mailing list