[x86-64] Large model relocation

Michael Matz matz@suse.de
Mon Mar 20 18:36:00 GMT 2006


Hi,

this patch adds the necessary support for the five new relocations for the
large model.  I've tested it on i386 and x86-64; it builds and doesn't
cause breakage in the testsuite for both.  Additionally we use this patch
(or better a slightly adjusted version) since quite some time internally,
so I know that it also builds several 1000 packages.

Full large model support also would need a change in elf.sc moving the
.plt after .text (so that .plt and .got have a chance to be nearer than
2GB).  This is because I didn't bother to actually implement the new .plt
layout which would be necessary for more than an abysmal number of
exported symbols (102261124 to be exact).  So the .plt code can't reach 
more than 2GB away, and as long as .text is between it and .got it can't 
be larger than the 2GB, which is the whole point of the large model.  I'll 
post that as follow up after the heat about this one (should it rise up) 
colds down :-)

Daniel: I would like to see this in 2.17 if possible, so that GCC could 
make use of it simply by version number.


Ciao,
Michael.

bfd/ChangeLog:
	* reloc.c: Add BFD_RELOC_X86_64_GOT64, BFD_RELOC_X86_64_GOTPCREL64,
	BFD_RELOC_X86_64_GOTPC64, BFD_RELOC_X86_64_GOTPLT64,
	BFD_RELOC_X86_64_PLTOFF64.
	* bfd-in2.h: Regenerated.
	* libbfd.h: Regenerated.
	* elf64-x86-64.c (x86_64_elf_howto_table): Correct comment.
	Add howtos for above relocs.
	(x86_64_reloc_map): Add mappings for new relocs.
	(elf64_x86_64_check_relocs): R_X86_64_GOT64, R_X86_64_GOTPCREL64,
	R_X86_64_GOTPLT64 need a got entry.  R_X86_64_GOTPLT64 also a PLT
	entry.  R_X86_64_GOTPC64 needs a .got section.  R_X86_64_PLTOFF64
	needs a PLT entry.
	(elf64_x86_64_gc_sweep_hook): Reflect changes from
	elf64_x86_64_check_relocs for the new relocs.
	(elf64_x86_64_relocate_section): Handle new relocs.

gas/ChangeLog:
	* config/tc-i386.c (type_names): Correct placement of 'static'.
	(reloc): Map some more relocs to their 64 bit counterpart when
	size is 8.
	(output_insn): Work around breakage if DEBUG386 is defined.
	(output_disp): A BFD_RELOC_64 with GOT_symbol as operand also
	needs to be mapped to BFD_RELOC_X86_64_GOTPC64 or
	BFD_RELOC_X86_64_GOTPC32.  Also x86-64 handles pcrel addressing
	different from i386.
	(output_imm): Ditto.
	(lex_got): Recognize @PLTOFF and @GOTPLT.  Make @GOT accept also
	Imm64.
	(md_convert_frag): Jumps can now be larger than 2GB away, error
	out in that case.
	(tc_gen_reloc): New relocs are passed through.  BFD_RELOC_64
	and BFD_RELOC_64_PCREL are mapped to BFD_RELOC_X86_64_GOTPC64.

gas/testsuite/ChangeLog:
	* gas/i386/reloc64.s: Accept 64-bit forms.
	* gas/i386/reloc64.d: Adjust.
	* gas/i386/reloc64.l: Adjust.

include/ChangeLog:
	* elf/x86-64.h: Add the new relocations with their official
	numbers.

Index: bfd/bfd-in2.h
===================================================================
RCS file: /cvs/src/src/bfd/bfd-in2.h,v
retrieving revision 1.384
diff -u -p -r1.384 bfd-in2.h
--- bfd/bfd-in2.h	16 Mar 2006 12:20:16 -0000	1.384
+++ bfd/bfd-in2.h	20 Mar 2006 17:04:03 -0000
@@ -2702,6 +2702,11 @@ in the instruction.  */
   BFD_RELOC_X86_64_TPOFF32,
   BFD_RELOC_X86_64_GOTOFF64,
   BFD_RELOC_X86_64_GOTPC32,
+  BFD_RELOC_X86_64_GOT64,
+  BFD_RELOC_X86_64_GOTPCREL64,
+  BFD_RELOC_X86_64_GOTPC64,
+  BFD_RELOC_X86_64_GOTPLT64,
+  BFD_RELOC_X86_64_PLTOFF64,
   BFD_RELOC_X86_64_GOTPC32_TLSDESC,
   BFD_RELOC_X86_64_TLSDESC_CALL,
   BFD_RELOC_X86_64_TLSDESC,
Index: bfd/elf64-x86-64.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-x86-64.c,v
retrieving revision 1.112
diff -u -p -r1.112 elf64-x86-64.c
--- bfd/elf64-x86-64.c	16 Mar 2006 12:20:15 -0000	1.112
+++ bfd/elf64-x86-64.c	20 Mar 2006 17:04:03 -0000
@@ -31,8 +31,8 @@
 #define MINUS_ONE (~ (bfd_vma) 0)
 
 /* The relocation "howto" table.  Order of fields:
-   type, size, bitsize, pc_relative, complain_on_overflow,
-   special_function, name, partial_inplace, src_mask, dst_pack, pcrel_offset.  */
+   type, rightshift, size, bitsize, pc_relative, bitpos, complain_on_overflow,
+   special_function, name, partial_inplace, src_mask, dst_mask, pcrel_offset.  */
 static reloc_howto_type x86_64_elf_howto_table[] =
 {
   HOWTO(R_X86_64_NONE, 0, 0, 0, FALSE, 0, complain_overflow_dont,
@@ -112,11 +112,21 @@ static reloc_howto_type x86_64_elf_howto
   HOWTO(R_X86_64_GOTPC32, 0, 2, 32, TRUE, 0, complain_overflow_signed,
 	bfd_elf_generic_reloc, "R_X86_64_GOTPC32",
 	FALSE, 0xffffffff, 0xffffffff, TRUE),
-  EMPTY_HOWTO (27),
-  EMPTY_HOWTO (28),
-  EMPTY_HOWTO (29),
-  EMPTY_HOWTO (30),
-  EMPTY_HOWTO (31),
+  HOWTO(R_X86_64_GOT64, 0, 4, 64, FALSE, 0, complain_overflow_signed,
+	bfd_elf_generic_reloc, "R_X86_64_GOT64", FALSE, MINUS_ONE, MINUS_ONE,
+	FALSE),
+  HOWTO(R_X86_64_GOTPCREL64, 0, 4, 64, TRUE, 0, complain_overflow_signed,
+	bfd_elf_generic_reloc, "R_X86_64_GOTPCREL64", FALSE, MINUS_ONE,
+	MINUS_ONE, TRUE),
+  HOWTO(R_X86_64_GOTPC64, 0, 4, 64, TRUE, 0, complain_overflow_signed,
+	bfd_elf_generic_reloc, "R_X86_64_GOTPC64",
+	FALSE, MINUS_ONE, MINUS_ONE, TRUE),
+  HOWTO(R_X86_64_GOTPLT64, 0, 4, 64, FALSE, 0, complain_overflow_signed,
+	bfd_elf_generic_reloc, "R_X86_64_GOTPLT64", FALSE, MINUS_ONE,
+	MINUS_ONE, FALSE),
+  HOWTO(R_X86_64_PLTOFF64, 0, 4, 64, FALSE, 0, complain_overflow_signed,
+	bfd_elf_generic_reloc, "R_X86_64_PLTOFF64", FALSE, MINUS_ONE,
+	MINUS_ONE, FALSE),
   EMPTY_HOWTO (32),
   EMPTY_HOWTO (33),
   HOWTO(R_X86_64_GOTPC32_TLSDESC, 0, 2, 32, TRUE, 0,
@@ -185,6 +195,11 @@ static const struct elf_reloc_map x86_64
   { BFD_RELOC_64_PCREL,		R_X86_64_PC64, },
   { BFD_RELOC_X86_64_GOTOFF64,	R_X86_64_GOTOFF64, },
   { BFD_RELOC_X86_64_GOTPC32,	R_X86_64_GOTPC32, },
+  { BFD_RELOC_X86_64_GOT64,	R_X86_64_GOT64, },
+  { BFD_RELOC_X86_64_GOTPCREL64,R_X86_64_GOTPCREL64, },
+  { BFD_RELOC_X86_64_GOTPC64,	R_X86_64_GOTPC64, },
+  { BFD_RELOC_X86_64_GOTPLT64,	R_X86_64_GOTPLT64, },
+  { BFD_RELOC_X86_64_PLTOFF64,	R_X86_64_PLTOFF64, },
   { BFD_RELOC_X86_64_GOTPC32_TLSDESC, R_X86_64_GOTPC32_TLSDESC, },
   { BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, },
   { BFD_RELOC_X86_64_TLSDESC,	R_X86_64_TLSDESC, },
@@ -777,6 +792,9 @@ elf64_x86_64_check_relocs (bfd *abfd, st
 	case R_X86_64_GOT32:
 	case R_X86_64_GOTPCREL:
 	case R_X86_64_TLSGD:
+	case R_X86_64_GOT64:
+	case R_X86_64_GOTPCREL64:
+	case R_X86_64_GOTPLT64:
 	case R_X86_64_GOTPC32_TLSDESC:
 	case R_X86_64_TLSDESC_CALL:
 	  /* This symbol requires a global offset table entry.	*/
@@ -795,6 +813,14 @@ elf64_x86_64_check_relocs (bfd *abfd, st
 
 	    if (h != NULL)
 	      {
+		if (r_type == R_X86_64_GOTPLT64)
+		  {
+		    /* This relocation indicates that we also need
+		       a PLT entry, as this is a function.  We don't need
+		       a PLT entry for local symbols.  */
+		    h->needs_plt = 1;
+		    h->plt.refcount += 1;
+		  }
 		h->got.refcount += 1;
 		old_tls_type = elf64_x86_64_hash_entry (h)->tls_type;
 	      }
@@ -858,6 +884,7 @@ elf64_x86_64_check_relocs (bfd *abfd, st
 
 	case R_X86_64_GOTOFF64:
 	case R_X86_64_GOTPC32:
+	case R_X86_64_GOTPC64:
 	create_got:
 	  if (htab->sgot == NULL)
 	    {
@@ -885,6 +912,16 @@ elf64_x86_64_check_relocs (bfd *abfd, st
 	  h->plt.refcount += 1;
 	  break;
 
+	case R_X86_64_PLTOFF64:
+	  /* This tries to form the 'address' of a function relative
+	     to GOT.  For global symbols we need a PLT entry.  */
+	  if (h != NULL)
+	    {
+	      h->needs_plt = 1;
+	      h->plt.refcount += 1;
+	    }
+	  goto create_got;
+
 	case R_X86_64_8:
 	case R_X86_64_16:
 	case R_X86_64_32:
@@ -1189,8 +1226,13 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, s
 	case R_X86_64_GOTTPOFF:
 	case R_X86_64_GOT32:
 	case R_X86_64_GOTPCREL:
+	case R_X86_64_GOT64:
+	case R_X86_64_GOTPCREL64:
+	case R_X86_64_GOTPLT64:
 	  if (h != NULL)
 	    {
+	      if (r_type == R_X86_64_GOTPLT64 && h->plt.refcount > 0)
+	        h->plt.refcount -= 1;
 	      if (h->got.refcount > 0)
 		h->got.refcount -= 1;
 	    }
@@ -1215,6 +1257,7 @@ elf64_x86_64_gc_sweep_hook (bfd *abfd, s
 	  /* Fall thru */
 
 	case R_X86_64_PLT32:
+	case R_X86_64_PLTOFF64:
 	  if (h != NULL)
 	    {
 	      if (h->plt.refcount > 0)
@@ -2096,11 +2139,23 @@ elf64_x86_64_relocate_section (bfd *outp
 	 copied into the output file to be resolved at run time.  */
       switch (r_type)
 	{
+	asection *base_got;
 	case R_X86_64_GOT32:
+	case R_X86_64_GOT64:
 	  /* Relocation is to the entry for this symbol in the global
 	     offset table.  */
 	case R_X86_64_GOTPCREL:
-	  /* Use global offset table as symbol value.  */
+	case R_X86_64_GOTPCREL64:
+	  /* Use global offset table entry as symbol value.  */
+	case R_X86_64_GOTPLT64:
+	  /* This is the same as GOT64 for relocation purposes, but
+	     indicates the existence of a PLT entry.  The difficulty is,
+	     that we must calculate the GOT slot offset from the PLT
+	     offset, if this symbol got a PLT entry (it was global).
+	     Additionally if it's computed from the PLT entry, then that
+	     GOT offset is relative to .got.plt, not to .got.  */
+	  base_got = htab->sgot;
+
 	  if (htab->sgot == NULL)
 	    abort ();
 
@@ -2109,6 +2164,19 @@ elf64_x86_64_relocate_section (bfd *outp
 	      bfd_boolean dyn;
 
 	      off = h->got.offset;
+	      if (h->needs_plt
+	          && h->plt.offset != (bfd_vma)-1
+		  && off == (bfd_vma)-1)
+		{
+		  /* We can't use h->got.offset here to save
+		     state, or even just remember the offset, as
+		     finish_dynamic_symbol would use that as offset into
+		     .got.  */
+		  bfd_vma plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1;
+		  off = (plt_index + 3) * GOT_ENTRY_SIZE;
+		  base_got = htab->sgotplt;
+		}
+
 	      dyn = htab->elf.dynamic_sections_created;
 
 	      if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
@@ -2133,7 +2201,9 @@ elf64_x86_64_relocate_section (bfd *outp
 		  else
 		    {
 		      bfd_put_64 (output_bfd, relocation,
-				  htab->sgot->contents + off);
+				  base_got->contents + off);
+		      /* Note that this is harmless for the GOTPLT64 case,
+		         as -1 | 1 still is -1.  */
 		      h->got.offset |= 1;
 		    }
 		}
@@ -2155,7 +2225,7 @@ elf64_x86_64_relocate_section (bfd *outp
 	      else
 		{
 		  bfd_put_64 (output_bfd, relocation,
-			      htab->sgot->contents + off);
+			      base_got->contents + off);
 
 		  if (info->shared)
 		    {
@@ -2169,8 +2239,8 @@ elf64_x86_64_relocate_section (bfd *outp
 		      if (s == NULL)
 			abort ();
 
-		      outrel.r_offset = (htab->sgot->output_section->vma
-					 + htab->sgot->output_offset
+		      outrel.r_offset = (base_got->output_section->vma
+					 + base_got->output_offset
 					 + off);
 		      outrel.r_info = ELF64_R_INFO (0, R_X86_64_RELATIVE);
 		      outrel.r_addend = relocation;
@@ -2186,9 +2256,9 @@ elf64_x86_64_relocate_section (bfd *outp
 	  if (off >= (bfd_vma) -2)
 	    abort ();
 
-	  relocation = htab->sgot->output_section->vma
-		       + htab->sgot->output_offset + off;
-	  if (r_type != R_X86_64_GOTPCREL)
+	  relocation = base_got->output_section->vma
+		       + base_got->output_offset + off;
+	  if (r_type != R_X86_64_GOTPCREL && r_type != R_X86_64_GOTPCREL64)
 	    relocation -= htab->sgotplt->output_section->vma
 			  - htab->sgotplt->output_offset;
 
@@ -2224,12 +2294,31 @@ elf64_x86_64_relocate_section (bfd *outp
 	  break;
 
 	case R_X86_64_GOTPC32:
+	case R_X86_64_GOTPC64:
 	  /* Use global offset table as symbol value.  */
 	  relocation = htab->sgotplt->output_section->vma
 		       + htab->sgotplt->output_offset;
 	  unresolved_reloc = FALSE;
 	  break;
 
+	case R_X86_64_PLTOFF64:
+	  /* Relocation is PLT entry relative to GOT.  For local
+	     symbols it's the symbol itself relative to GOT.  */
+          if (h != NULL
+	      /* See PLT32 handling.  */
+	      && h->plt.offset != (bfd_vma) -1
+	      && htab->splt != NULL)
+	    {
+	      relocation = (htab->splt->output_section->vma
+			    + htab->splt->output_offset
+			    + h->plt.offset);
+	      unresolved_reloc = FALSE;
+	    }
+
+	  relocation -= htab->sgotplt->output_section->vma
+			+ htab->sgotplt->output_offset;
+	  break;
+
 	case R_X86_64_PLT32:
 	  /* Relocation is to the entry for this symbol in the
 	     procedure linkage table.  */
Index: bfd/libbfd.h
===================================================================
RCS file: /cvs/src/src/bfd/libbfd.h,v
retrieving revision 1.175
diff -u -p -r1.175 libbfd.h
--- bfd/libbfd.h	16 Mar 2006 12:20:16 -0000	1.175
+++ bfd/libbfd.h	20 Mar 2006 17:04:03 -0000
@@ -7,7 +7,7 @@
    (This include file is not for users of the library.)
 
    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003, 2004, 2005
+   1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
 
    Written by Cygnus Support.
@@ -1062,6 +1062,11 @@ static const char *const bfd_reloc_code_
   "BFD_RELOC_X86_64_TPOFF32",
   "BFD_RELOC_X86_64_GOTOFF64",
   "BFD_RELOC_X86_64_GOTPC32",
+  "BFD_RELOC_X86_64_GOT64",
+  "BFD_RELOC_X86_64_GOTPCREL64",
+  "BFD_RELOC_X86_64_GOTPC64",
+  "BFD_RELOC_X86_64_GOTPLT64",
+  "BFD_RELOC_X86_64_PLTOFF64",
   "BFD_RELOC_X86_64_GOTPC32_TLSDESC",
   "BFD_RELOC_X86_64_TLSDESC_CALL",
   "BFD_RELOC_X86_64_TLSDESC",
Index: bfd/libcoff.h
===================================================================
RCS file: /cvs/src/src/bfd/libcoff.h,v
retrieving revision 1.43
diff -u -p -r1.43 libcoff.h
--- bfd/libcoff.h	16 Mar 2006 12:20:16 -0000	1.43
+++ bfd/libcoff.h	20 Mar 2006 17:04:03 -0000
@@ -4,7 +4,7 @@
 
 /* BFD COFF object file private structure.
    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005
+   2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
    Written by Cygnus Support.
 
Index: bfd/reloc.c
===================================================================
RCS file: /cvs/src/src/bfd/reloc.c,v
retrieving revision 1.149
diff -u -p -r1.149 reloc.c
--- bfd/reloc.c	3 Mar 2006 15:25:29 -0000	1.149
+++ bfd/reloc.c	20 Mar 2006 17:04:03 -0000
@@ -2344,6 +2344,16 @@ ENUMX
 ENUMX
   BFD_RELOC_X86_64_GOTPC32
 ENUMX
+  BFD_RELOC_X86_64_GOT64
+ENUMX
+  BFD_RELOC_X86_64_GOTPCREL64
+ENUMX
+  BFD_RELOC_X86_64_GOTPC64
+ENUMX
+  BFD_RELOC_X86_64_GOTPLT64
+ENUMX
+  BFD_RELOC_X86_64_PLTOFF64
+ENUMX
   BFD_RELOC_X86_64_GOTPC32_TLSDESC
 ENUMX
   BFD_RELOC_X86_64_TLSDESC_CALL
Index: gas/config/tc-i386.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-i386.c,v
retrieving revision 1.207
diff -u -p -r1.207 tc-i386.c
--- gas/config/tc-i386.c	27 Feb 2006 15:35:37 -0000	1.207
+++ gas/config/tc-i386.c	20 Mar 2006 17:04:03 -0000
@@ -1169,13 +1169,12 @@ ps (s)
 	   segment_name (S_GET_SEGMENT (s)));
 }
 
-struct type_name
+static struct type_name
   {
     unsigned int mask;
     char *tname;
   }
-
-static const type_names[] =
+const type_names[] =
 {
   { Reg8, "r8" },
   { Reg16, "r16" },
@@ -1238,6 +1237,18 @@ reloc (unsigned int size,
       if (size == 8)
 	switch (other)
 	  {
+	    case BFD_RELOC_X86_64_GOT32:
+	      return BFD_RELOC_X86_64_GOT64;
+	      break;
+	    case BFD_RELOC_X86_64_PLTOFF64:
+	      return BFD_RELOC_X86_64_PLTOFF64;
+	      break;
+	    case BFD_RELOC_X86_64_GOTPC32:
+	      other = BFD_RELOC_X86_64_GOTPC64;
+	      break;
+	    case BFD_RELOC_X86_64_GOTPCREL:
+	      other = BFD_RELOC_X86_64_GOTPCREL64;
+	      break;
 	    case BFD_RELOC_X86_64_TPOFF32:
 	      other = BFD_RELOC_X86_64_TPOFF64;
 	      break;
@@ -3569,7 +3580,7 @@ check_prefix:
 #ifdef DEBUG386
   if (flag_debug)
     {
-      pi (line, &i);
+      pi ("" /*line*/, &i);
     }
 #endif /* DEBUG386  */
 }
@@ -3654,7 +3665,9 @@ output_disp (insn_start_frag, insn_start
 	      if (GOT_symbol
 		  && GOT_symbol == i.op[n].disps->X_add_symbol
 		  && (((reloc_type == BFD_RELOC_32
-			|| reloc_type == BFD_RELOC_X86_64_32S)
+			|| reloc_type == BFD_RELOC_X86_64_32S
+			|| (reloc_type == BFD_RELOC_64
+			    && object_64bit))
 		       && (i.op[n].disps->X_op == O_symbol
 			   || (i.op[n].disps->X_op == O_add
 			       && ((symbol_get_value_expression
@@ -3678,10 +3691,17 @@ output_disp (insn_start_frag, insn_start
 		    }
 
 		  if (!object_64bit)
-		    reloc_type = BFD_RELOC_386_GOTPC;
+		    {
+		      reloc_type = BFD_RELOC_386_GOTPC;
+		      i.op[n].imms->X_add_number += add;
+		    }
+		  else if (reloc_type == BFD_RELOC_64)
+		    reloc_type = BFD_RELOC_X86_64_GOTPC64;
 		  else
+		    /* Don't do the adjustment for x86-64, as there
+		       the pcrel addressing is relative to the _next_
+		       insn, and that is taken care of in other code.  */
 		    reloc_type = BFD_RELOC_X86_64_GOTPC32;
-		  i.op[n].disps->X_add_number += add;
 		}
 	      fix_new_exp (frag_now, p - frag_now->fr_literal, size,
 			   i.op[n].disps, pcrel, reloc_type);
@@ -3790,7 +3810,8 @@ output_imm (insn_start_frag, insn_start_
 	       * confusing to do it this way.  */
 
 	      if ((reloc_type == BFD_RELOC_32
-		   || reloc_type == BFD_RELOC_X86_64_32S)
+		   || reloc_type == BFD_RELOC_X86_64_32S
+		   || reloc_type == BFD_RELOC_64)
 		  && GOT_symbol
 		  && GOT_symbol == i.op[n].imms->X_add_symbol
 		  && (i.op[n].imms->X_op == O_symbol
@@ -3816,8 +3837,10 @@ output_imm (insn_start_frag, insn_start_
 
 		  if (!object_64bit)
 		    reloc_type = BFD_RELOC_386_GOTPC;
-		  else
+		  else if (size == 4)
 		    reloc_type = BFD_RELOC_X86_64_GOTPC32;
+		  else if (size == 8)
+		    reloc_type = BFD_RELOC_X86_64_GOTPC64;
 		  i.op[n].imms->X_add_number += add;
 		}
 	      fix_new_exp (frag_now, p - frag_now->fr_literal, size,
@@ -3870,12 +3893,19 @@ lex_got (enum bfd_reloc_code_real *reloc
      int *adjust,
      unsigned int *types)
 {
+  /* Some of the relocations depend on the size of what field is to
+     be relocated.  But in our callers i386_immediate and i386_displacement
+     we don't yet know the operand size (this will be set by insn
+     matching).  Hence we record the word32 relocation here,
+     and adjust the reloc according to the real size in reloc().  */
   static const struct {
     const char *str;
     const enum bfd_reloc_code_real rel[2];
     const unsigned int types64;
   } gotrel[] = {
+    { "PLTOFF",   { 0,                        BFD_RELOC_X86_64_PLTOFF64 }, Imm64 },
     { "PLT",      { BFD_RELOC_386_PLT32,      BFD_RELOC_X86_64_PLT32    }, Imm32|Imm32S|Disp32 },
+    { "GOTPLT",   { 0,                        BFD_RELOC_X86_64_GOTPLT64 }, Imm64|Disp64 },
     { "GOTOFF",   { BFD_RELOC_386_GOTOFF,     BFD_RELOC_X86_64_GOTOFF64 }, Imm64|Disp64 },
     { "GOTPCREL", { 0,                        BFD_RELOC_X86_64_GOTPCREL }, Imm32|Imm32S|Disp32 },
     { "TLSGD",    { BFD_RELOC_386_TLS_GD,     BFD_RELOC_X86_64_TLSGD    }, Imm32|Imm32S|Disp32 },
@@ -3887,7 +3917,7 @@ lex_got (enum bfd_reloc_code_real *reloc
     { "DTPOFF",   { BFD_RELOC_386_TLS_LDO_32, BFD_RELOC_X86_64_DTPOFF32 }, Imm32|Imm32S|Imm64|Disp32|Disp64 },
     { "GOTNTPOFF",{ BFD_RELOC_386_TLS_GOTIE,  0                         }, 0 },
     { "INDNTPOFF",{ BFD_RELOC_386_TLS_IE,     0                         }, 0 },
-    { "GOT",      { BFD_RELOC_386_GOT32,      BFD_RELOC_X86_64_GOT32    }, Imm32|Imm32S|Disp32 },
+    { "GOT",      { BFD_RELOC_386_GOT32,      BFD_RELOC_X86_64_GOT32    }, Imm32|Imm32S|Disp32|Imm64 },
     { "TLSDESC",  { BFD_RELOC_386_TLS_GOTDESC, BFD_RELOC_X86_64_GOTPC32_TLSDESC }, Imm32|Imm32S|Disp32 },
     { "TLSCALL",  { BFD_RELOC_386_TLS_DESC_CALL, BFD_RELOC_X86_64_TLSDESC_CALL }, Imm32|Imm32S|Disp32 }
   };
@@ -4947,6 +4977,20 @@ md_convert_frag (abfd, sec, fragP)
 	}
     }
 
+  /* If size if less then four we are sure that the operand fits,
+     but if it's 4, then it could be that the displacement is larger
+     then -/+ 2GB.  */
+  if (DISP_SIZE_FROM_RELAX_STATE (fragP->fr_subtype) == 4
+      && object_64bit
+      && ((addressT) (displacement_from_opcode_start - extension
+                      + ((addressT) 1 << 31))
+          > (((addressT) 2 << 31) - 1)))
+    {
+      as_bad_where (fragP->fr_file, fragP->fr_line,
+		    _("jump target out of range"));
+      /* Make us emit 0.  */
+      displacement_from_opcode_start = extension;
+    }
   /* Now put displacement after opcode.  */
   md_number_to_chars ((char *) where_to_put_displacement,
 		      (valueT) (displacement_from_opcode_start - extension),
@@ -5708,6 +5752,11 @@ tc_gen_reloc (section, fixp)
     case BFD_RELOC_X86_64_TPOFF64:
     case BFD_RELOC_X86_64_GOTOFF64:
     case BFD_RELOC_X86_64_GOTPC32:
+    case BFD_RELOC_X86_64_GOT64:
+    case BFD_RELOC_X86_64_GOTPCREL64:
+    case BFD_RELOC_X86_64_GOTPC64:
+    case BFD_RELOC_X86_64_GOTPLT64:
+    case BFD_RELOC_X86_64_PLTOFF64:
     case BFD_RELOC_X86_64_GOTPC32_TLSDESC:
     case BFD_RELOC_X86_64_TLSDESC_CALL:
     case BFD_RELOC_RVA:
@@ -5776,6 +5825,12 @@ tc_gen_reloc (section, fixp)
       else
 	code = BFD_RELOC_X86_64_GOTPC32;
     }
+  if ((code == BFD_RELOC_64 || code == BFD_RELOC_64_PCREL)
+      && GOT_symbol
+      && fixp->fx_addsy == GOT_symbol)
+    {
+      code = BFD_RELOC_X86_64_GOTPC64;
+    }
 
   rel = (arelent *) xmalloc (sizeof (arelent));
   rel->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *));
Index: gas/testsuite/gas/i386/reloc64.d
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/i386/reloc64.d,v
retrieving revision 1.2
diff -u -p -r1.2 reloc64.d
--- gas/testsuite/gas/i386/reloc64.d	28 Sep 2005 14:44:25 -0000	1.2
+++ gas/testsuite/gas/i386/reloc64.d	20 Mar 2006 17:04:03 -0000
@@ -19,6 +19,7 @@ Disassembly of section \.text:
 .*[ 	]+R_X86_64_PC32[ 	]+xtrn\+0xf+c
 .*[ 	]+R_X86_64_PC32[ 	]+xtrn\+0xf+c
 .*[ 	]+R_X86_64_PC8[ 	]+xtrn\+0xf+f
+.*[ 	]+R_X86_64_GOT64[ 	]+xtrn
 .*[ 	]+R_X86_64_GOT32[ 	]+xtrn
 .*[ 	]+R_X86_64_GOT32[ 	]+xtrn
 .*[ 	]+R_X86_64_GOTOFF64[ 	]+xtrn
@@ -26,7 +27,7 @@ Disassembly of section \.text:
 .*[ 	]+R_X86_64_GOTPCREL[ 	]+xtrn
 .*[ 	]+R_X86_64_GOTPCREL[ 	]+xtrn\+0xf+c
 .*[ 	]+R_X86_64_GOTPC32[ 	]+_GLOBAL_OFFSET_TABLE_\+0x0*2
-.*[ 	]+R_X86_64_GOTPC32[ 	]+_GLOBAL_OFFSET_TABLE_\+0xf+f
+.*[ 	]+R_X86_64_GOTPC32[ 	]+_GLOBAL_OFFSET_TABLE_\+0xf+c
 .*[ 	]+R_X86_64_GOTPC32[ 	]+_GLOBAL_OFFSET_TABLE_\+0x0*2
 .*[ 	]+R_X86_64_PLT32[ 	]+xtrn
 .*[ 	]+R_X86_64_PLT32[ 	]+xtrn
@@ -50,7 +51,9 @@ Disassembly of section \.data:
 #...
 .*[ 	]+R_X86_64_64[ 	]+xtrn
 .*[ 	]+R_X86_64_PC64[ 	]+xtrn
+.*[ 	]+R_X86_64_GOT64[ 	]+xtrn
 .*[ 	]+R_X86_64_GOTOFF64[ 	]+xtrn
+.*[ 	]+R_X86_64_GOTPCREL64[ 	]+xtrn
 .*[ 	]+R_X86_64_DTPOFF64[ 	]+xtrn
 .*[ 	]+R_X86_64_TPOFF64[ 	]+xtrn
 .*[ 	]+R_X86_64_32[ 	]+xtrn
Index: gas/testsuite/gas/i386/reloc64.l
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/i386/reloc64.l,v
retrieving revision 1.2
diff -u -p -r1.2 reloc64.l
--- gas/testsuite/gas/i386/reloc64.l	28 Sep 2005 14:44:25 -0000	1.2
+++ gas/testsuite/gas/i386/reloc64.l	20 Mar 2006 17:04:03 -0000
@@ -1,6 +1,5 @@
 .*: Assembler messages:
 .*:29: Error: .*
-.*:33: Error: .*
 .*:35: Error: .*
 .*:36: Error: .*
 .*:37: Error: .*
@@ -50,8 +49,6 @@
 .*:123: Error: .*
 .*:125: Error: .*
 .*:126: Error: .*
-.*:131: Error: .*
-.*:133: Error: .*
 .*:136: Error: .*
 .*:137: Error: .*
 .*:138: Error: .*
Index: gas/testsuite/gas/i386/reloc64.s
===================================================================
RCS file: /cvs/src/src/gas/testsuite/gas/i386/reloc64.s,v
retrieving revision 1.2
diff -u -p -r1.2 reloc64.s
--- gas/testsuite/gas/i386/reloc64.s	28 Sep 2005 14:44:25 -0000	1.2
+++ gas/testsuite/gas/i386/reloc64.s	20 Mar 2006 17:04:03 -0000
@@ -30,7 +30,7 @@ bad	mov	xtrn(%eip), %eax
 	call	xtrn
 	jrcxz	xtrn
 
-bad	movabs	$xtrn@got, %rax
+	movabs	$xtrn@got, %rax
 	add	$xtrn@got, %rax
 bad	mov	$xtrn@got, %eax
 bad	mov	$xtrn@got, %ax
@@ -128,9 +128,9 @@ bad	call	xtrn@tpoff
  .data
 	.quad	xtrn
 	.quad	xtrn - .
-bad	.quad	xtrn@got
+	.quad	xtrn@got
 	.quad	xtrn@gotoff
-bad	.quad	xtrn@gotpcrel
+	.quad	xtrn@gotpcrel
 ill	.quad	_GLOBAL_OFFSET_TABLE_
 ill	.quad	_GLOBAL_OFFSET_TABLE_ - .
 bad	.quad	xtrn@plt
Index: include/elf/x86-64.h
===================================================================
RCS file: /cvs/src/src/include/elf/x86-64.h,v
retrieving revision 1.9
diff -u -p -r1.9 x86-64.h
--- include/elf/x86-64.h	18 Jan 2006 21:07:47 -0000	1.9
+++ include/elf/x86-64.h	20 Mar 2006 17:04:04 -0000
@@ -54,7 +54,16 @@ START_RELOC_NUMBERS (elf_x86_64_reloc_ty
      RELOC_NUMBER (R_X86_64_GOTOFF64, 25)     /* 64 bit offset to GOT */
      RELOC_NUMBER (R_X86_64_GOTPC32,  26)     /* 32 bit signed pc relative
                                                  offset to GOT */
-     /* 27 .. 33 */
+     RELOC_NUMBER (R_X86_64_GOT64,    27)     /* 64 bit GOT entry offset */
+     RELOC_NUMBER (R_X86_64_GOTPCREL64, 28)   /* 64 bit signed pc relative
+     						 offset to GOT entry */
+     RELOC_NUMBER (R_X86_64_GOTPC64,  29)     /* 64 bit signed pc relative
+     						 offset to GOT */
+     RELOC_NUMBER (R_X86_64_GOTPLT64, 30)     /* like GOT64, but indicates
+     						 that PLT entry is needed */
+     RELOC_NUMBER (R_X86_64_PLTOFF64, 31)     /* 64 bit GOT relative offset
+     						 to PLT entry */
+     /* 32 .. 33 */
      RELOC_NUMBER (R_X86_64_GOTPC32_TLSDESC, 34)
 					      /* 32 bit signed pc relative
 						 offset to TLS descriptor



More information about the Binutils mailing list