This is the mail archive of the binutils@sourceware.org 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]
Other format: [Raw text]

[patch, committed] Nios II large-GOT support


The published Nios II ABI restricts the GOT to 64K maximum because it uses 16-bit relocations for GOT-relative addressing. There's a note saying that new relocations might be added in the future to remove that restriction... and here they are. :-) This project was undertaken in cooperation with Altera and they have agreed to document the new relocations in future versions of the ABI specification.

The new relocations are similar to the existing lo/hiadj pairs used to represent 32-bit constants in other contexts. Referring to the code examples in the existing ABI documentation, the large-GOT equivalent of

addi r3, r22, %got(x)       # R_NIOS2_GOT16

is

movhi r3, %got_hiadj(x)     # R_NIOS2_GOT_HA
addi r3, r3, %got_lo(x)     # R_NIOS2_GOT_LO
add r3, r3, r22

and

ldw r3, %call(fun)(r22)     # R_NIOS2_CALL16 fun
callr r3

becomes

movhi r3, %call_hiadj(x)     # R_NIOS2_CALL_HA
addi r3, r3, %call_lo(x)     # R_NIOS2_CALL_LO
add r3, r3, r22
ldw r3, 0(r3)
callr r3

This patch doesn't include any testcases for the new relocations; we tested it in conjunction with a GCC patch that makes it emit the large-GOT code sequences with -fPIC. We'll be posting the GCC part in due course.

-Sandra

2014-02-03  Sandra Loosemore  <sandra@codesourcery.com>

	include/elf/
	* nios2.h (R_NIOS2_GOT_LO, R_NIOS2_GOT_HA): New.
	(R_NIOS2_CALL_LO, R_NIOS2_CALL_HA): New.
	(R_NIOS2_ILLEGAL): Adjust.

	gas/
	* config/tc-nios2.c (md_apply_fix): Test for new relocs.
	(nios2_special_reloc): Add %call_lo, %call_hiadj, %got_lo,
	%got_hiadj relocation operators.  Sort table and add comment
	to explain ordering.
	(nios2_fix_adjustable): Test for new relocs.
	* doc/c-nios2.texi (Nios II Relocations): Document new relocation
	operators.

	bfd/
	* reloc.c (BFD_RELOC_NIOS2_GOT_LO, BFD_RELOC_NIOS2_GOT_HA): New.
	(BFD_RELOC_NIOS2_CALL_LO, BFD_RELOC_NIOS2_CALL_HA): New.
	* libbfd.h: Regenerated.
	* bfd-in2.h: Regenerated.
	* elf32-nios2.c (elf_nios2_howto_table_rel): Add new relocations.
	(nios2_reloc_map): Likewise.
	(GOT_USED, CALL_USED): Renamed from GOT16_USED and CALL16_USED.
	Fixed all references.
	(nios2_elf32_relocate_section): Add new relocations.
	(nios2_elf32_check_relocs): Likewise.
	(nios2_elf32_gc_sweep_hook): Likewise.

diff --git a/include/elf/nios2.h b/include/elf/nios2.h
index 7686350..47afc0f 100644
--- a/include/elf/nios2.h
+++ b/include/elf/nios2.h
@@ -76,7 +76,11 @@ START_RELOC_NUMBERS (elf_nios2_reloc_type)
   RELOC_NUMBER (R_NIOS2_RELATIVE, 39)
   RELOC_NUMBER (R_NIOS2_GOTOFF, 40)
   RELOC_NUMBER (R_NIOS2_CALL26_NOAT,  41)
-  RELOC_NUMBER (R_NIOS2_ILLEGAL, 42)
+  RELOC_NUMBER (R_NIOS2_GOT_LO, 42)
+  RELOC_NUMBER (R_NIOS2_GOT_HA, 43)
+  RELOC_NUMBER (R_NIOS2_CALL_LO, 44)
+  RELOC_NUMBER (R_NIOS2_CALL_HA, 45)
+  RELOC_NUMBER (R_NIOS2_ILLEGAL, 46)
 END_RELOC_NUMBERS (R_NIOS2_maxext)
 
 /* Processor-specific section flags.  */
diff --git a/gas/config/tc-nios2.c b/gas/config/tc-nios2.c
index eb81b35..3d52048 100644
--- a/gas/config/tc-nios2.c
+++ b/gas/config/tc-nios2.c
@@ -1139,7 +1139,6 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 		  || fixP->fx_r_type == BFD_RELOC_NIOS2_U16
 		  || fixP->fx_r_type == BFD_RELOC_16_PCREL
 		  || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL26
-		  || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL26_NOAT
 		  || fixP->fx_r_type == BFD_RELOC_NIOS2_IMM5
 		  || fixP->fx_r_type == BFD_RELOC_NIOS2_CACHE_OPX
 		  || fixP->fx_r_type == BFD_RELOC_NIOS2_IMM6
@@ -1165,6 +1164,11 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED)
 		  || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_LE16
 		  || fixP->fx_r_type == BFD_RELOC_NIOS2_GOTOFF
 		  || fixP->fx_r_type == BFD_RELOC_NIOS2_TLS_DTPREL
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL26_NOAT
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_GOT_LO
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_GOT_HA
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL_LO
+		  || fixP->fx_r_type == BFD_RELOC_NIOS2_CALL_HA
 		  /* Add other relocs here as we generate them.  */
 		  ));
 
@@ -1301,21 +1305,28 @@ struct nios2_special_relocS
   bfd_reloc_code_real_type reloc_type;
 };
 
+/* This table is sorted so that prefix strings are listed after the longer
+   strings that include them -- e.g., %got after %got_hiadj, etc.  */
+
 struct nios2_special_relocS nios2_special_reloc[] = {
   {"%hiadj", BFD_RELOC_NIOS2_HIADJ16},
   {"%hi", BFD_RELOC_NIOS2_HI16},
   {"%lo", BFD_RELOC_NIOS2_LO16},
   {"%gprel", BFD_RELOC_NIOS2_GPREL},
+  {"%call_lo", BFD_RELOC_NIOS2_CALL_LO},
+  {"%call_hiadj", BFD_RELOC_NIOS2_CALL_HA},
   {"%call", BFD_RELOC_NIOS2_CALL16},
   {"%gotoff_lo", BFD_RELOC_NIOS2_GOTOFF_LO},
   {"%gotoff_hiadj", BFD_RELOC_NIOS2_GOTOFF_HA},
+  {"%gotoff", BFD_RELOC_NIOS2_GOTOFF},
+  {"%got_hiadj", BFD_RELOC_NIOS2_GOT_HA},
+  {"%got_lo", BFD_RELOC_NIOS2_GOT_LO},
+  {"%got", BFD_RELOC_NIOS2_GOT16},
   {"%tls_gd", BFD_RELOC_NIOS2_TLS_GD16},
   {"%tls_ldm", BFD_RELOC_NIOS2_TLS_LDM16},
   {"%tls_ldo", BFD_RELOC_NIOS2_TLS_LDO16},
   {"%tls_ie", BFD_RELOC_NIOS2_TLS_IE16},
   {"%tls_le", BFD_RELOC_NIOS2_TLS_LE16},
-  {"%gotoff", BFD_RELOC_NIOS2_GOTOFF},
-  {"%got", BFD_RELOC_NIOS2_GOT16}
 };
 
 #define NIOS2_NUM_SPECIAL_RELOCS \
@@ -2824,7 +2835,12 @@ nios2_fix_adjustable (fixS *fixp)
       || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_DTPMOD
       || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_DTPREL
       || fixp->fx_r_type == BFD_RELOC_NIOS2_TLS_TPREL
-      || fixp->fx_r_type == BFD_RELOC_NIOS2_GOTOFF)
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_GOTOFF
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_GOT_LO
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_GOT_HA
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_CALL_LO
+      || fixp->fx_r_type == BFD_RELOC_NIOS2_CALL_HA
+      )
     return 0;
 
   return 1;
diff --git a/gas/doc/c-nios2.texi b/gas/doc/c-nios2.texi
index 1d45dd2..0ba6b9b 100644
--- a/gas/doc/c-nios2.texi
+++ b/gas/doc/c-nios2.texi
@@ -131,7 +131,11 @@ fastint:
 @end smallexample
 
 @cindex @code{call} directive, Nios II
+@cindex @code{call_lo} directive, Nios II
+@cindex @code{call_hiadj} directive, Nios II
 @cindex @code{got} directive, Nios II
+@cindex @code{got_lo} directive, Nios II
+@cindex @code{got_hiadj} directive, Nios II
 @cindex @code{gotoff} directive, Nios II
 @cindex @code{gotoff_lo} directive, Nios II
 @cindex @code{gotoff_hiadj} directive, Nios II
@@ -141,7 +145,11 @@ fastint:
 @cindex @code{tls_ldm} directive, Nios II
 @cindex @code{tls_ldo} directive, Nios II
 @item %call(@var{expression})
+@item %call_lo(@var{expression})
+@item %call_hiadj(@var{expression})
 @itemx %got(@var{expression})
+@itemx %got_lo(@var{expression})
+@itemx %got_hiadj(@var{expression})
 @itemx %gotoff(@var{expression})
 @itemx %gotoff_lo(@var{expression})
 @itemx %gotoff_hiadj(@var{expression})
diff --git a/bfd/reloc.c b/bfd/reloc.c
index 3d1256d..5cc6e0c 100644
--- a/bfd/reloc.c
+++ b/bfd/reloc.c
@@ -6067,6 +6067,14 @@ ENUMX
   BFD_RELOC_NIOS2_GOTOFF
 ENUMX
   BFD_RELOC_NIOS2_CALL26_NOAT
+ENUMX
+  BFD_RELOC_NIOS2_GOT_LO
+ENUMX
+  BFD_RELOC_NIOS2_GOT_HA
+ENUMX
+  BFD_RELOC_NIOS2_CALL_LO
+ENUMX
+  BFD_RELOC_NIOS2_CALL_HA
 ENUMDOC
   Relocations used by the Altera Nios II core.
 
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 73e2332..b30fb0d 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -5226,6 +5226,10 @@ a matching LO8XG part.  */
   BFD_RELOC_NIOS2_RELATIVE,
   BFD_RELOC_NIOS2_GOTOFF,
   BFD_RELOC_NIOS2_CALL26_NOAT,
+  BFD_RELOC_NIOS2_GOT_LO,
+  BFD_RELOC_NIOS2_GOT_HA,
+  BFD_RELOC_NIOS2_CALL_LO,
+  BFD_RELOC_NIOS2_CALL_HA,
 
 /* IQ2000 Relocations.  */
   BFD_RELOC_IQ2000_OFFSET_16,
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index 9711e17..bbca43f 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -2533,6 +2533,10 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_NIOS2_RELATIVE",
   "BFD_RELOC_NIOS2_GOTOFF",
   "BFD_RELOC_NIOS2_CALL26_NOAT",
+  "BFD_RELOC_NIOS2_GOT_LO",
+  "BFD_RELOC_NIOS2_GOT_HA",
+  "BFD_RELOC_NIOS2_CALL_LO",
+  "BFD_RELOC_NIOS2_CALL_HA",
   "BFD_RELOC_IQ2000_OFFSET_16",
   "BFD_RELOC_IQ2000_OFFSET_21",
   "BFD_RELOC_IQ2000_UHI16",
diff --git a/bfd/elf32-nios2.c b/bfd/elf32-nios2.c
index dbe5289..b6a60ff 100644
--- a/bfd/elf32-nios2.c
+++ b/bfd/elf32-nios2.c
@@ -670,6 +670,62 @@ static reloc_howto_type elf_nios2_howto_table_rel[] = {
 	 0xffffffc0,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
+  HOWTO (R_NIOS2_GOT_LO,
+	 0,
+	 2,
+	 16,
+	 FALSE,
+	 6,
+	 complain_overflow_dont,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_GOT_LO",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_GOT_HA,
+	 0,
+	 2,
+	 16,
+	 FALSE,
+	 6,
+	 complain_overflow_dont,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_GOT_HA",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_CALL_LO,
+	 0,
+	 2,
+	 16,
+	 FALSE,
+	 6,
+	 complain_overflow_dont,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_CALL_LO",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
+  HOWTO (R_NIOS2_CALL_HA,
+	 0,
+	 2,
+	 16,
+	 FALSE,
+	 6,
+	 complain_overflow_dont,
+	 bfd_elf_generic_reloc,
+	 "R_NIOS2_CALL_HA",
+	 FALSE,
+	 0x003fffc0,
+	 0x003fffc0,
+	 FALSE),
+
 /* Add other relocations here.  */
 };
 
@@ -749,6 +805,10 @@ static const struct elf_reloc_map nios2_reloc_map[] = {
   {BFD_RELOC_NIOS2_RELATIVE, R_NIOS2_RELATIVE},
   {BFD_RELOC_NIOS2_GOTOFF, R_NIOS2_GOTOFF},
   {BFD_RELOC_NIOS2_CALL26_NOAT, R_NIOS2_CALL26_NOAT},
+  {BFD_RELOC_NIOS2_GOT_LO, R_NIOS2_GOT_LO},
+  {BFD_RELOC_NIOS2_GOT_HA, R_NIOS2_GOT_HA},
+  {BFD_RELOC_NIOS2_CALL_LO, R_NIOS2_CALL_LO},
+  {BFD_RELOC_NIOS2_CALL_HA, R_NIOS2_CALL_HA},
 };
 
 enum elf32_nios2_stub_type
@@ -839,10 +899,11 @@ struct elf32_nios2_link_hash_entry
      a dynamic GOT reloc in shared objects, only a dynamic PLT reloc.  Lazy
      linking will not work if the dynamic GOT reloc exists.
      To check for this condition efficiently, we compare got_types_used against
-     CALL16_USED, meaning
-     (got_types_used & (GOT16_USED | CALL16_USED)) == CALL16_USED.  */
-#define GOT16_USED	1
-#define CALL16_USED	2
+     CALL_USED, meaning
+     (got_types_used & (GOT_USED | CALL_USED)) == CALL_USED.
+  */
+#define GOT_USED	1
+#define CALL_USED	2
   unsigned char got_types_used;
 };
 
@@ -2942,6 +3003,10 @@ nios2_elf32_relocate_section (bfd *output_bfd,
 
 	    case R_NIOS2_GOT16:
 	    case R_NIOS2_CALL16:
+	    case R_NIOS2_GOT_LO:
+	    case R_NIOS2_GOT_HA:
+	    case R_NIOS2_CALL_LO:
+	    case R_NIOS2_CALL_HA:
 	      /* Relocation is to the entry for this symbol in the
 		 global offset table.  */
 	      if (sgot == NULL)
@@ -2957,7 +3022,7 @@ nios2_elf32_relocate_section (bfd *output_bfd,
 		  bfd_boolean dyn;
 
 		  eh = (struct elf32_nios2_link_hash_entry *)h;
-		  use_plt = (eh->got_types_used == CALL16_USED
+		  use_plt = (eh->got_types_used == CALL_USED
 			     && h->plt.offset != (bfd_vma) -1);
 
 		  off = h->got.offset;
@@ -3044,9 +3109,30 @@ nios2_elf32_relocate_section (bfd *output_bfd,
 	      /* This relocation does not use the addend.  */
 	      rel->r_addend = 0;
 
-	      r = _bfd_final_link_relocate (howto, input_bfd, input_section,
-					    contents, rel->r_offset,
-					    relocation, rel->r_addend);
+	      switch (howto->type)
+		{
+		case R_NIOS2_GOT_LO:
+		case R_NIOS2_CALL_LO:
+		  r = nios2_elf32_do_lo16_relocate (input_bfd, howto,
+						    input_section, contents,
+						    rel->r_offset, relocation,
+						    rel->r_addend);
+		  break;
+		case R_NIOS2_GOT_HA:
+		case R_NIOS2_CALL_HA:
+		  r = nios2_elf32_do_hiadj16_relocate (input_bfd, howto,
+						       input_section, contents,
+						       rel->r_offset,
+						       relocation,
+						       rel->r_addend);
+		  break;
+		default:
+		  r = _bfd_final_link_relocate (howto, input_bfd,
+						input_section, contents,
+						rel->r_offset, relocation,
+						rel->r_addend);
+		  break;
+		}
 	      break;
 
 	    case R_NIOS2_GOTOFF_LO:
@@ -3671,7 +3757,11 @@ nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info,
       switch (r_type)
 	{
 	case R_NIOS2_GOT16:
+	case R_NIOS2_GOT_LO:
+	case R_NIOS2_GOT_HA:
 	case R_NIOS2_CALL16:
+	case R_NIOS2_CALL_LO:
+	case R_NIOS2_CALL_HA:
 	case R_NIOS2_TLS_GD16:
 	case R_NIOS2_TLS_IE16:
 	  /* This symbol requires a global offset table entry.  */
@@ -3682,7 +3772,11 @@ nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info,
 	      {
 	      default:
 	      case R_NIOS2_GOT16:
+	      case R_NIOS2_GOT_LO:
+	      case R_NIOS2_GOT_HA:
 	      case R_NIOS2_CALL16:
+	      case R_NIOS2_CALL_LO:
+	      case R_NIOS2_CALL_HA:
 		tls_type = GOT_NORMAL;
 		break;
 	      case R_NIOS2_TLS_GD16:
@@ -3719,7 +3813,9 @@ nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info,
 		  = (struct elf32_nios2_link_hash_entry *)h;
 		h->got.refcount++;
 		old_tls_type = elf32_nios2_hash_entry(h)->tls_type;
-		if (r_type == R_NIOS2_CALL16)
+		if (r_type == R_NIOS2_CALL16
+		    || r_type == R_NIOS2_CALL_LO
+		    || r_type == R_NIOS2_CALL_HA)
 		  {
 		    /* Make sure a plt entry is created for this symbol if
 		       it turns out to be a function defined by a dynamic
@@ -3727,10 +3823,10 @@ nios2_elf32_check_relocs (bfd *abfd, struct bfd_link_info *info,
 		    h->plt.refcount++;
 		    h->needs_plt = 1;
 		    h->type = STT_FUNC;
-		    eh->got_types_used |= CALL16_USED;
+		    eh->got_types_used |= CALL_USED;
 		  }
 		else
-		  eh->got_types_used |= GOT16_USED;
+		  eh->got_types_used |= GOT_USED;
 	      }
 	    else
 	      {
@@ -3964,7 +4060,11 @@ nios2_elf32_gc_sweep_hook (bfd *abfd,
       switch (r_type)
 	{
 	case R_NIOS2_GOT16:
+	case R_NIOS2_GOT_LO:
+	case R_NIOS2_GOT_HA:
 	case R_NIOS2_CALL16:
+	case R_NIOS2_CALL_LO:
+	case R_NIOS2_CALL_HA:
 	  if (h != NULL)
 	    {
 	      if (h->got.refcount > 0)
@@ -4114,7 +4214,7 @@ nios2_elf32_finish_dynamic_symbol (bfd *output_bfd,
 	}
     }
 
-  use_plt = (eh->got_types_used == CALL16_USED
+  use_plt = (eh->got_types_used == CALL_USED
 	     && h->plt.offset != (bfd_vma) -1);
 
   if (!use_plt && h->got.offset != (bfd_vma) -1
@@ -4587,7 +4687,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
     }
 
   eh = (struct elf32_nios2_link_hash_entry *) h;
-  use_plt = (eh->got_types_used == CALL16_USED
+  use_plt = (eh->got_types_used == CALL_USED
 	     && h->plt.offset != (bfd_vma) -1);
 
   if (h->got.refcount > 0)

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