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]

[1/4, committed] Add Nios II arch flags and compatibility tests


This patch adds ELF flags to distinguish Nios II R1 and R2 objects,
BFD support to propagate them through the linker and prevent mixing R1
and R2 objects, and a -march command-line option to the assembler to
tell it how to tag the output.  (Subsequent patches in the series will
make the assembler use different encodings for R2 output.)

The value of EF_NIOS2_ARCH_R1 was chosen to be zero so that all
existing object files, which don't set the field, will properly be
recognized as R1.  In BFD, bfd_mach_nios2 is only used to indicate an
unknown or uninitialized arch variant now -- the correct mach setting
is taken from the first input bfd.

The assembler defaults to producing R1 output, as before.  Note that
there are no assembler command-line flags or ELF attributes to
identify use of the various optional R2 extensions.  There aren't any
compatibility issues between code that uses or doesn't use those
extensions, and users are expected to be smart enough not to run code
containing those instructions on hardware that doesn't support them.

Adding the new BFD mach variants requires a small tweak to GDB as
well, which I'll post separately to the gdb-patches list.

-Sandra

2015-07-01  Sandra Loosemore  <sandra@codesourcery.com>
	    Cesar Philippidis  <cesar@codesourcery.com>

	bfd/
	* archures.c (bfd_mach_nios2r1, bfd_mach_nios2r2): New.
	* bfd-in2.h: Regenerated.
	* cpu-nios2.c (nios2_compatible): New.
	(N): Use nios2_compatible instead of bfd_default_compatible.
	(NIOS2R1_NEXT, NIOS2R2_NEXT): Define.
	(arch_info_struct): New.
	(bfd_nios2_arch): Chain to NIOS2R1_NEXT.
	* elf32-nios2.c (is_nios2_elf): New.
	(nios2_elf32_merge_private_bfd_data): New.
	(nios2_elf32_object_p): New.
	(bfd_elf32_bfd_merge_private_bfd_data): Define.
	(elf_backend_object_p): Define.

	gas/
	* config/tc-nios2.c: Adjust includes.
	(OPTION_MARCH): Define.
	(md_longopts): Add -march option.
	(nios2_architecture): New.
	(nios2_use_arch): New.
	(md_parse_option): Handle OPTION_MARCH.
	(md_show_usage): Document -march.
	(md_begin): Set arch in BFD.
	(nios2_elf_final_processing): New.
	* config/tc-nios2.h (elf_tc_final_processing): Define.
	(nios2_elf_final_processing): New.
	* doc/c-nios2.texi (-march): Add documentation.

	include/elf/
	* nios2.h (EF_NIOS2_ARCH_R1, EF_NIOS2_ARCH_R2): Define.

	ld/testsuite/
	* ld-nios2/mixed1a.d: New.
	* ld-nios2/mixed1a.s: New.
	* ld-nios2/mixed1b.d: New.
	* ld-nios2/mixed1b.s: New.
	* ld-nios2/nios2.exp: Build the new compatibility tests.
diff --git a/bfd/archures.c b/bfd/archures.c
index 677c470..95433f8 100644
--- a/bfd/archures.c
+++ b/bfd/archures.c
@@ -501,8 +501,10 @@ DESCRIPTION
 .  bfd_arch_aarch64,   {* AArch64  *}
 .#define bfd_mach_aarch64 0
 .#define bfd_mach_aarch64_ilp32	32
-.  bfd_arch_nios2,
-.#define bfd_mach_nios2	0
+.  bfd_arch_nios2,	{* Nios II *}
+.#define bfd_mach_nios2		0
+.#define bfd_mach_nios2r1	1
+.#define bfd_mach_nios2r2	2
 .  bfd_arch_visium,	{* Visium *}
 .#define bfd_mach_visium	1
 .  bfd_arch_last
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 2d32c74..fb3b770 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -2295,8 +2295,10 @@ enum bfd_architecture
   bfd_arch_aarch64,   /* AArch64  */
 #define bfd_mach_aarch64 0
 #define bfd_mach_aarch64_ilp32 32
-  bfd_arch_nios2,
-#define bfd_mach_nios2 0
+  bfd_arch_nios2,      /* Nios II */
+#define bfd_mach_nios2         0
+#define bfd_mach_nios2r1       1
+#define bfd_mach_nios2r2       2
   bfd_arch_visium,     /* Visium */
 #define bfd_mach_visium        1
   bfd_arch_last
diff --git a/bfd/cpu-nios2.c b/bfd/cpu-nios2.c
index 57539db..1e8f521 100644
--- a/bfd/cpu-nios2.c
+++ b/bfd/cpu-nios2.c
@@ -24,6 +24,26 @@
 #include "bfd.h"
 #include "libbfd.h"
 
+static const bfd_arch_info_type *
+nios2_compatible (const bfd_arch_info_type *a,
+		  const bfd_arch_info_type *b)
+{
+  if (a->arch != b->arch)
+    return NULL;
+
+  if (a->bits_per_word != b->bits_per_word)
+    return NULL;
+
+  if (a->mach == bfd_mach_nios2)
+    return a;
+  else if (b->mach == bfd_mach_nios2)
+    return b;
+  else if (a->mach != b->mach)
+    return NULL;
+
+  return a;
+}
+
 #define N(BITS_WORD, BITS_ADDR, NUMBER, PRINT, DEFAULT, NEXT)		\
   {							\
     BITS_WORD, /*  bits in a word */			\
@@ -35,10 +55,20 @@
     PRINT,						\
     3,							\
     DEFAULT,						\
-    bfd_default_compatible,				\
+    nios2_compatible,					\
     bfd_default_scan,					\
     bfd_arch_default_fill,			       	\
     NEXT						\
   }
 
-const bfd_arch_info_type bfd_nios2_arch = N (32, 32, 0, "nios2", TRUE, NULL);
+#define NIOS2R1_NEXT &arch_info_struct[0]
+#define NIOS2R2_NEXT &arch_info_struct[1]
+
+static const bfd_arch_info_type arch_info_struct[] =
+{
+  N (32, 32, bfd_mach_nios2r1, "nios2:r1", FALSE, NIOS2R2_NEXT),
+  N (32, 32, bfd_mach_nios2r2, "nios2:r2", FALSE, NULL),
+};
+
+const bfd_arch_info_type bfd_nios2_arch = 
+  N (32, 32, 0, "nios2", TRUE, NIOS2R1_NEXT);
diff --git a/bfd/elf32-nios2.c b/bfd/elf32-nios2.c
index 4f992bf..6a1372b 100644
--- a/bfd/elf32-nios2.c
+++ b/bfd/elf32-nios2.c
@@ -2038,6 +2038,72 @@ nios2_elf32_build_stubs (struct bfd_link_info *info)
 }
 
 
+#define is_nios2_elf(bfd) \
+  (bfd_get_flavour (bfd) == bfd_target_elf_flavour \
+   && elf_object_id (bfd) == NIOS2_ELF_DATA)
+
+/* Merge backend specific data from an object file to the output
+   object file when linking.  */
+
+static bfd_boolean
+nios2_elf32_merge_private_bfd_data (bfd *ibfd, bfd *obfd)
+{
+  flagword old_flags;
+  flagword new_flags;
+
+  if (!is_nios2_elf (ibfd) || !is_nios2_elf (obfd))
+    return TRUE;
+
+  /* Check if we have the same endianness.  */
+  if (! _bfd_generic_verify_endian_match (ibfd, obfd))
+    return FALSE;
+
+  new_flags = elf_elfheader (ibfd)->e_flags;
+  old_flags = elf_elfheader (obfd)->e_flags;
+  if (!elf_flags_init (obfd))
+    {
+      /* First call, no flags set.  */
+      elf_flags_init (obfd) = TRUE;
+      elf_elfheader (obfd)->e_flags = new_flags;
+
+      switch (new_flags)
+	{
+	default:
+	case EF_NIOS2_ARCH_R1:
+	  bfd_default_set_arch_mach (obfd, bfd_arch_nios2, bfd_mach_nios2r1);
+	  break;
+	case EF_NIOS2_ARCH_R2:
+	  if (bfd_big_endian (ibfd))
+	    {
+	      (*_bfd_error_handler)
+		(_("error: %B: Big-endian R2 is not supported."), ibfd);
+	      bfd_set_error (bfd_error_bad_value);
+	      return FALSE;
+	    }
+	  bfd_default_set_arch_mach (obfd, bfd_arch_nios2, bfd_mach_nios2r2);
+	  break;
+	}
+    }
+
+  /* Incompatible flags.  */
+  else if (new_flags != old_flags)
+    {
+      /* So far, the only incompatible flags denote incompatible
+	 architectures.  */
+      (*_bfd_error_handler)
+	(_("error: %B: Conflicting CPU architectures %d/%d"),
+	 ibfd, new_flags, old_flags);
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+
+  /* Merge Tag_compatibility attributes and any common GNU ones.  */
+  _bfd_elf_merge_object_attributes (ibfd, obfd);
+
+  return TRUE;
+}
+
+
 /* Implement bfd_elf32_bfd_reloc_type_lookup:
    Given a BFD reloc type, return a howto structure.  */
 static reloc_howto_type *
@@ -3707,6 +3773,29 @@ nios2_elf32_copy_indirect_symbol (struct bfd_link_info *info,
   _bfd_elf_link_hash_copy_indirect (info, dir, ind);
 }
 
+/* Set the right machine number for a NIOS2 ELF file.  */
+
+static bfd_boolean
+nios2_elf32_object_p (bfd *abfd)
+{
+  unsigned long mach;
+
+  mach = elf_elfheader (abfd)->e_flags;
+
+  switch (mach)
+    {
+    default:
+    case EF_NIOS2_ARCH_R1:
+      bfd_default_set_arch_mach (abfd, bfd_arch_nios2, bfd_mach_nios2r1);
+      break;
+    case EF_NIOS2_ARCH_R2:
+      bfd_default_set_arch_mach (abfd, bfd_arch_nios2, bfd_mach_nios2r2);
+      break;
+    }
+
+  return TRUE;
+}
+
 /* Implement elf_backend_check_relocs:
    Look through the relocs for a section during the first phase.  */
 static bfd_boolean
@@ -5256,6 +5345,9 @@ const struct bfd_elf_special_section elf32_nios2_special_sections[] =
 #define bfd_elf32_bfd_link_hash_table_create \
 					  nios2_elf32_link_hash_table_create
 
+#define bfd_elf32_bfd_merge_private_bfd_data \
+					  nios2_elf32_merge_private_bfd_data
+
 /* Relocation table lookup macros.  */
 
 #define bfd_elf32_bfd_reloc_type_lookup	  nios2_elf32_bfd_reloc_type_lookup
@@ -5292,6 +5384,7 @@ const struct bfd_elf_special_section elf32_nios2_special_sections[] =
 #define elf_backend_size_dynamic_sections nios2_elf32_size_dynamic_sections
 #define elf_backend_add_symbol_hook	  nios2_elf_add_symbol_hook
 #define elf_backend_copy_indirect_symbol  nios2_elf32_copy_indirect_symbol
+#define elf_backend_object_p		  nios2_elf32_object_p
 
 #define elf_backend_grok_prstatus	  nios2_grok_prstatus
 #define elf_backend_grok_psinfo		  nios2_grok_psinfo
diff --git a/gas/config/tc-nios2.c b/gas/config/tc-nios2.c
index 2fb26b8..549ca98 100644
--- a/gas/config/tc-nios2.c
+++ b/gas/config/tc-nios2.c
@@ -25,6 +25,7 @@
 #include "elf/nios2.h"
 #include "tc-nios2.h"
 #include "bfd.h"
+#include "libbfd.h"
 #include "dwarf2dbg.h"
 #include "subsegs.h"
 #include "safe-ctype.h"
@@ -80,7 +81,9 @@ struct option md_longopts[] = {
 #define OPTION_EB (OPTION_MD_BASE + 3)
   {"EB", no_argument, NULL, OPTION_EB},
 #define OPTION_EL (OPTION_MD_BASE + 4)
-  {"EL", no_argument, NULL, OPTION_EL}
+  {"EL", no_argument, NULL, OPTION_EL},
+#define OPTION_MARCH (OPTION_MD_BASE + 5)
+  {"march", required_argument, NULL, OPTION_MARCH}
 };
 
 size_t md_longopts_size = sizeof (md_longopts);
@@ -212,6 +215,9 @@ static symbolS *nios2_last_label;
 symbolS *GOT_symbol;
 #endif
 
+/* The processor architecture value, EF_NIOS2_ARCH_R1 by default.  */
+static int nios2_architecture = EF_NIOS2_ARCH_R1;
+
 
 /** Utility routines.  */
 /* Function md_chars_to_number takes the sequence of
@@ -2209,6 +2215,34 @@ output_movia (nios2_insn_infoS *insn)
 
 /** External interfaces.  */
 
+/* Update the selected architecture based on ARCH, giving an error if
+   ARCH is an invalid value.  */
+
+static void
+nios2_use_arch (const char *arch)
+{
+  if (strcmp (arch, "nios2") == 0 || strcmp (arch, "r1") == 0)
+    {
+      nios2_architecture |= EF_NIOS2_ARCH_R1;
+      nios2_opcodes = (struct nios2_opcode *) nios2_r1_opcodes;
+      nios2_num_opcodes = nios2_num_r1_opcodes;
+      nop32 = nop_r1;
+      nop16 = NULL;
+      return;
+    }
+  else if (strcmp (arch, "r2") == 0)
+    {
+      nios2_architecture |= EF_NIOS2_ARCH_R2;
+      nios2_opcodes = (struct nios2_opcode *) nios2_r2_opcodes;
+      nios2_num_opcodes = nios2_num_r2_opcodes;
+      nop32 = nop_r2;
+      nop16 = nop_r2_cdx;
+      return;
+    }
+
+  as_bad (_("unknown architecture '%s'"), arch);
+}
+
 /* The following functions are called by machine-independent parts of
    the assembler. */
 int
@@ -2235,6 +2269,9 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED)
     case OPTION_EL:
       target_big_endian = 0;
       break;
+    case OPTION_MARCH:
+      nios2_use_arch (arg);
+      break;
     default:
       return 0;
       break;
@@ -2262,9 +2299,11 @@ md_show_usage (FILE *stream)
 	   "branches with jmp sequences (default)\n"
 	   "  -no-relax		    do not replace any branches or calls\n"
 	   "  -EB		    force big-endian byte ordering\n"
-	   "  -EL		    force little-endian byte ordering\n");
+	   "  -EL		    force little-endian byte ordering\n"
+	   "  -march=ARCH	    enable instructions from architecture ARCH\n");
 }
 
+
 /* This function is called once, at assembler startup time.
    It should set up all the tables, etc. that the MD part of the
    assembler will need. */
@@ -2274,6 +2313,19 @@ md_begin (void)
   int i;
   const char *inserted;
 
+  switch (nios2_architecture)
+    {
+    default:
+    case EF_NIOS2_ARCH_R1:
+      bfd_default_set_arch_mach (stdoutput, bfd_arch_nios2, bfd_mach_nios2r1);
+      break;
+    case EF_NIOS2_ARCH_R2:
+      if (target_big_endian)
+	as_fatal (_("Big-endian R2 is not supported."));
+      bfd_default_set_arch_mach (stdoutput, bfd_arch_nios2, bfd_mach_nios2r2);
+      break;
+    }
+
   /* Create and fill a hashtable for the Nios II opcodes, registers and 
      arguments.  */
   nios2_opcode_hash = hash_new ();
@@ -2747,3 +2799,13 @@ nios2_frame_initial_instructions (void)
 {
   cfi_add_CFA_def_cfa (27, 0);
 }
+
+#ifdef OBJ_ELF
+/* Some special processing for a Nios II ELF file.  */
+
+void
+nios2_elf_final_processing (void)
+{
+  elf_elfheader (stdoutput)->e_flags = nios2_architecture;
+}
+#endif
diff --git a/gas/config/tc-nios2.h b/gas/config/tc-nios2.h
index 2e69caf..8b9a7d8 100644
--- a/gas/config/tc-nios2.h
+++ b/gas/config/tc-nios2.h
@@ -118,4 +118,7 @@ extern int nios2_regname_to_dw2regnum (char *regname);
 #define tc_cfi_frame_initial_instructions  nios2_frame_initial_instructions
 extern void nios2_frame_initial_instructions (void);
 
+#define elf_tc_final_processing nios2_elf_final_processing
+extern void nios2_elf_final_processing (void);
+
 #endif /* TC_NIOS2 */
diff --git a/gas/doc/c-nios2.texi b/gas/doc/c-nios2.texi
index 1fb29f2..880346d 100644
--- a/gas/doc/c-nios2.texi
+++ b/gas/doc/c-nios2.texi
@@ -58,6 +58,16 @@ Generate big-endian output.
 @item -EL
 Generate little-endian output.  This is the default.
 
+@cindex @code{march} command line option, Nios II
+@item -march=@var{architecture}
+This option specifies the target architecture.  The assembler issues
+an error message if an attempt is made to assemble an instruction which
+will not execute on the target architecture.  The following architecture
+names are recognized:
+@code{r1},
+@code{r2}.  
+The default is @code{r1}.
+
 @end table
 @c man end
 
diff --git a/include/elf/nios2.h b/include/elf/nios2.h
index 429b8ba..07f937f 100644
--- a/include/elf/nios2.h
+++ b/include/elf/nios2.h
@@ -93,4 +93,9 @@ END_RELOC_NUMBERS (R_NIOS2_maxext)
 /* Address of _gp.  */
 #define DT_NIOS2_GP 0x70000002
 
+/* Processor specific flags for the Elf header e_flags field.  */
+
+#define EF_NIOS2_ARCH_R1 0x00000000
+#define EF_NIOS2_ARCH_R2 0x00000001
+
 #endif /* _ELF_NIOS2_H */
diff --git a/ld/testsuite/ld-nios2/mixed1a.d b/ld/testsuite/ld-nios2/mixed1a.d
new file mode 100644
index 0000000..0c7d666
--- /dev/null
+++ b/ld/testsuite/ld-nios2/mixed1a.d
@@ -0,0 +1,9 @@
+#name: NIOS2 mixed1a
+#source: mixed1a.s
+#as: -march=r2
+#readelf: -h
+
+ELF Header:
+#...
+  Flags:                             0x1
+#...
diff --git a/ld/testsuite/ld-nios2/mixed1a.s b/ld/testsuite/ld-nios2/mixed1a.s
new file mode 100644
index 0000000..8742f1c
--- /dev/null
+++ b/ld/testsuite/ld-nios2/mixed1a.s
@@ -0,0 +1,9 @@
+# Test linking incompatible object file types. 
+
+.text
+.global	_start
+_start:
+	movhi	r2, %hiadj(foo)
+	addi	r2, r2, %lo(foo)
+	ldw	r2, 0(r2)
+	cmpeq	r2, r2, zero
diff --git a/ld/testsuite/ld-nios2/mixed1b.d b/ld/testsuite/ld-nios2/mixed1b.d
new file mode 100644
index 0000000..a702c5a
--- /dev/null
+++ b/ld/testsuite/ld-nios2/mixed1b.d
@@ -0,0 +1,9 @@
+#name: NIOS2 mixed1b
+#source: mixed1b.s
+#as: -march=r1
+#readelf: -h
+
+ELF Header:
+#...
+  Flags:                             0x0
+#...
diff --git a/ld/testsuite/ld-nios2/mixed1b.s b/ld/testsuite/ld-nios2/mixed1b.s
new file mode 100644
index 0000000..0d07590
--- /dev/null
+++ b/ld/testsuite/ld-nios2/mixed1b.s
@@ -0,0 +1,3 @@
+# Test linking incompatible object file types. 
+
+.comm	foo,4,4
diff --git a/ld/testsuite/ld-nios2/nios2.exp b/ld/testsuite/ld-nios2/nios2.exp
index 22080b4..b8ffd49 100644
--- a/ld/testsuite/ld-nios2/nios2.exp
+++ b/ld/testsuite/ld-nios2/nios2.exp
@@ -1,7 +1,31 @@
 if { ! [istarget nios2-*-*] } {
-    return
+    return 
 }
 
 foreach test [lsort [glob -nocomplain $srcdir/$subdir/*.d]] {
     run_dump_test [file rootname $test]
 }
+
+global link_output
+global ld
+
+set test_name "NIOS2 Mixed R1 and R2 objects"
+set test mixed1
+
+if ![ld_assemble $as "-march=r1 $srcdir/$subdir/${test}a.s" tmpdir/${test}a.o] {
+    unresolved "Build mixed1a.o"
+    return
+}
+
+if ![ld_assemble $as "-march=r2 $srcdir/$subdir/${test}b.s" tmpdir/${test}b.o] {
+    unresolved "Build mixed1b.o"
+    return
+}
+
+if { ![ld_simple_link $ld tmpdir/$test "tmpdir/${test}a.o tmpdir/${test}b.o"] } {
+    if [string match "*architecture * is incompatible*" $link_output] {
+	pass "$test_name"
+    } {
+	fail "$test_name"
+    }
+}

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