relative GOT relocs in gold

David Miller davem@davemloft.net
Fri Apr 4 19:23:00 GMT 2008


Unlike other platforms, when there is a GOT reloc (f.e.
R_SPARC_GOT{10,13,22}) that results in emitting a R_SPARC_RELATIVE
relocation for the dynamic linker, the relocation doesn't go into the
GOT slot, it ends up in the R_SPARC_RELATIVE reloc's addend instead.

The GOT entry in this case is cleared to zero.

For the curious, the existing BFD bits that implement this are
in elfxx-sparc.c:_bfd_sparc_elf_relocate_section(), specifically
this block of code:

	case R_SPARC_GOT10:
	case R_SPARC_GOT13:
	case R_SPARC_GOT22:
 ...
	  if (h != NULL)
	    {
 ...
	    }
	  else
	    {
	      BFD_ASSERT (local_got_offsets != NULL
			  && local_got_offsets[r_symndx] != (bfd_vma) -1);

	      off = local_got_offsets[r_symndx];

	      /* The offset must always be a multiple of 8 on 64-bit and
		 4 on 32-bit.  We use the least significant bit to record
		 whether we have already processed this entry.  */
	      if ((off & 1) != 0)
		off &= ~1;
	      else
		{

		  if (info->shared)
		    {
		      asection *s;
		      Elf_Internal_Rela outrel;

		      /* We need to generate a R_SPARC_RELATIVE reloc
			 for the dynamic linker.  */
		      s = htab->srelgot;
		      BFD_ASSERT (s != NULL);

		      outrel.r_offset = (htab->sgot->output_section->vma
					 + htab->sgot->output_offset
					 + off);
		      outrel.r_info = SPARC_ELF_R_INFO (htab, NULL,
							0, R_SPARC_RELATIVE);
		      outrel.r_addend = relocation;
		      relocation = 0;
		      sparc_elf_append_rela (output_bfd, s, &outrel);
		    }

		  SPARC_ELF_PUT_WORD (htab, output_bfd, relocation,
				      htab->sgot->contents + off);
		  local_got_offsets[r_symndx] |= 1;
		}
	    }
	  relocation = htab->sgot->output_offset + off - got_base;

I can't see any easy way to implement this using the
current gold target infrastructure and interfaces.

If there is a nice way, please show me! :-)

Otherwise, my initial suggestion is that perhaps we should add a way
to point GOT entries at relocations, or parts of a relocation, and add
a new GOT type for that and assosciated ->write() methods.

Then I could register the GOT entry with ->add_local_with_rela()
or similar, and tell it "and BTW, put there gsym->value() in
this relocation addend over here instead of the GOT slot."

Alternatively, we could have a target fixup pass that can walk over
the dynamic relocs, and for this case the sparc target would
transfer the GOT slot values into the associated R_SPARC_RELATIVE
reloc addends, and clear the GOT slot.

Any better ideas?



More information about the Binutils mailing list