[PATCH] m68k: tag floating-point ABI used

Pat Bernardi bernardi@adacore.com
Thu Jun 25 20:05:38 GMT 2020


This patch adds GNU attribute support to m68k and utilises it to tag the
floating-point calling convention used (hard-float or soft-float). It enables
the linker to ensure linked objects use a consistent floating-point ABI and
allows tools like GDB to infer the ABI used from the ELF file. It is based on
similar work done for PowerPC.

The patch has been tested for m68k-elf and x86-64/Linux.

If approved, I'll need a maintainer to commit on my behalf.

Thanks,

Pat Bernardi
AdaCore

---
bfd/ChangeLog:
2020-06-25  Pat Bernardi  <bernardi@adacore.com>

	* elf32-m68k.c (m68k_elf_merge_obj_attributes): New function.
	(elf32_m68k_merge_private_bfd_data): Merge GNU attributes.

binutils/ChangeLog:
2020-06-25  Pat Bernardi  <bernardi@adacore.com>

	* readelf.c (display_m68k_gnu_attribute): New function.
	(process_arch_specific): Call display_m68k_gnu_attribute for EM_68K.

gas/ChangeLog:
2020-06-25  Pat Bernardi  <bernardi@adacore.com>

	* config/tc-m68k.c (m68k_elf_gnu_attribute): New function.
	(md_pseudo_table): Handle "gnu_attribute".
	* doc/as.texi: Document GNU attribute for M68K.

include/ChangeLog:
2020-06-25  Pat Bernardi  <bernardi@adacore.com>

	* elf/m68k.h: Add enum for GNU object attribute with floating point
	tag name and values.

ld/ChangeLog:
2020-06-25  Pat Bernardi  <bernardi@adacore.com>

	* testsuite/ld-m68k/attr-gnu-4-0.s: New file.
	* testsuite/ld-m68k/attr-gnu-4-0.s: Likewise.
	* testsuite/ld-m68k/attr-gnu-4-01.d: Likewise.
	* testsuite/ld-m68k/attr-gnu-4-1.s: Likewise.
	* testsuite/ld-m68k/attr-gnu-4-02.d: Likewise.
	* testsuite/ld-m68k/attr-gnu-4-2.s: Likewise.
	* testsuite/ld-m68k/attr-gnu-4-10.d: Likewise.
	* testsuite/ld-m68k/attr-gnu-4-11.d: Likewise.
	* testsuite/ld-m68k/attr-gnu-4-12.d: Likewise.
	* testsuite/ld-m68k/attr-gnu-4-20.d: Likewise.
	* testsuite/ld-m68k/attr-gnu-4-21.d: Likewise.
	* testsuite/ld-m68k/attr-gnu-4-22.d: Likewise.
	* testsuite/ld-m68k/m68k.exp: Run the new tests.

diff --git a/bfd/elf32-m68k.c b/bfd/elf32-m68k.c
index 39c5e1c2cc..7ccdaabbb6 100644
--- a/bfd/elf32-m68k.c
+++ b/bfd/elf32-m68k.c
@@ -1122,6 +1122,65 @@ elf32_m68k_set_private_flags (bfd *abfd, flagword flags)
   return TRUE;
 }

+/* Merge object attributes from IBFD into OBFD.  Warn if
+   there are conflicting attributes. */
+static bfd_boolean
+m68k_elf_merge_obj_attributes (bfd *ibfd, struct bfd_link_info *info)
+{
+  bfd *obfd = info->output_bfd;
+  obj_attribute *in_attr, *in_attrs;
+  obj_attribute *out_attr, *out_attrs;
+  bfd_boolean ret = TRUE;
+
+  in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU];
+  out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU];
+
+  in_attr = &in_attrs[Tag_GNU_M68K_ABI_FP];
+  out_attr = &out_attrs[Tag_GNU_M68K_ABI_FP];
+
+  if (in_attr->i != out_attr->i)
+    {
+      int in_fp = in_attr->i & 3;
+      int out_fp = out_attr->i & 3;
+      static bfd *last_fp;
+
+      if (in_fp == 0)
+	;
+      else if (out_fp == 0)
+	{
+	  out_attr->type = ATTR_TYPE_FLAG_INT_VAL;
+	  out_attr->i ^= in_fp;
+	  last_fp = ibfd;
+	}
+      else if (out_fp == 1 && in_fp == 2)
+	{
+	  _bfd_error_handler
+	    /* xgettext:c-format */
+	    (_("%pB uses hard float, %pB uses soft float"),
+	     last_fp, ibfd);
+	  ret = FALSE;
+	}
+      else if (out_fp == 2 && in_fp == 1)
+	{
+	  _bfd_error_handler
+	    /* xgettext:c-format */
+	    (_("%pB uses hard float, %pB uses soft float"),
+	     ibfd, last_fp);
+	  ret = FALSE;
+	}
+    }
+
+  if (!ret)
+    {
+      out_attr->type = ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_ERROR;
+      bfd_set_error (bfd_error_bad_value);
+      return FALSE;
+    }
+
+  /* Merge Tag_compatibility attributes and any common GNU ones.  */
+  return _bfd_elf_merge_object_attributes (ibfd, info);
+}
+
 /* Merge backend specific data from an object file to the output
    object file when linking.  */
 static bfd_boolean
@@ -1149,6 +1208,9 @@ elf32_m68k_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info)

   bfd_set_arch_mach (obfd, bfd_arch_m68k, arch_info->mach);

+  if (!m68k_elf_merge_obj_attributes (ibfd, info))
+    return FALSE;
+
   in_flags = elf_elfheader (ibfd)->e_flags;
   if (!elf_flags_init (obfd))
     {
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 9e4fa3327b..25f0e2354c 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -15367,6 +15367,44 @@ display_gnu_attribute (unsigned char * p,
   return display_tag_value (tag, p, end);
 }

+static unsigned char *
+display_m68k_gnu_attribute (unsigned char * p,
+			    unsigned int tag,
+			    const unsigned char * const end)
+{
+  unsigned int val;
+
+  if (tag == Tag_GNU_M68K_ABI_FP)
+    {
+      printf ("  Tag_GNU_M68K_ABI_FP: ");
+      if (p == end)
+	{
+	  printf (_("<corrupt>\n"));
+	  return p;
+	}
+      READ_ULEB (val, p, end);
+
+      if (val > 3)
+	printf ("(%#x), ", val);
+
+      switch (val & 3)
+	{
+	case 0:
+	  printf (_("unspecified hard/soft float\n"));
+	  break;
+	case 1:
+	  printf (_("hard float\n"));
+	  break;
+	case 2:
+	  printf (_("soft float\n"));
+	  break;
+	}
+      return p;
+    }
+
+  return display_tag_value (tag & 1, p, end);
+}
+
 static unsigned char *
 display_power_gnu_attribute (unsigned char * p,
 			     unsigned int tag,
@@ -19928,6 +19966,10 @@ process_arch_specific (Filedata * filedata)
     case EM_NDS32:
       return process_nds32_specific (filedata);

+    case EM_68K:
+      return process_attributes (filedata, NULL, SHT_GNU_ATTRIBUTES, NULL,
+				 display_m68k_gnu_attribute);
+
     case EM_PPC:
     case EM_PPC64:
       return process_attributes (filedata, NULL, SHT_GNU_ATTRIBUTES, NULL,
diff --git a/gas/config/tc-m68k.c b/gas/config/tc-m68k.c
index cbb227a333..c2aec634b3 100644
--- a/gas/config/tc-m68k.c
+++ b/gas/config/tc-m68k.c
@@ -30,6 +30,7 @@
 #include "elf/m68k.h"

 static void m68k_elf_cons (int);
+static void m68k_elf_gnu_attribute (int);

 /* This string holds the chars that always start a comment.  If the
    pre-processor is disabled, these aren't very useful.  The macro
@@ -889,6 +890,7 @@ const pseudo_typeS md_pseudo_table[] =

   {"arch", s_m68k_arch, 0},
   {"cpu", s_m68k_cpu, 0},
+  {"gnu_attribute", m68k_elf_gnu_attribute, 0},

   /* The following pseudo-ops are supported for MRI compatibility.  */
   {"chip", s_chip, 0},
@@ -7951,6 +7953,24 @@ m68k_elf_cons (int nbytes /* 4=.long */)
   demand_empty_rest_of_line ();
 }

+/* Parse a .gnu_attribute directive.  */
+static void
+m68k_elf_gnu_attribute (int ignored ATTRIBUTE_UNUSED)
+{
+  int tag = obj_elf_vendor_attribute (OBJ_ATTR_GNU);
+
+  /* Check validity of defined m68k tags.  */
+  if (tag == Tag_GNU_M68K_ABI_FP)
+    {
+      unsigned int val;
+
+      val = bfd_elf_get_obj_attr_int (stdoutput, OBJ_ATTR_GNU, tag);
+
+      if ((tag == Tag_GNU_M68K_ABI_FP && val > 2))
+	as_warn (_("unknown .gnu_attribute value"));
+    }
+}
+
 int
 tc_m68k_regname_to_dw2regnum (const char *regname)
 {
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index f8d892eaa5..ac4a073eab 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -7583,6 +7583,22 @@ than 1, the file can only be processed by other toolchains under some private
 arrangement indicated by the flag value and the vendor name.
 @end table

+@subsection M680x0 Attributes
+
+@table @r
+@item Tag_GNU_M68K_ABI_FP (4)
+The floating-point ABI used by this object file.  The value will be:
+
+@itemize @bullet
+@item
+0 for files not affected by the floating-point ABI.
+@item
+1 for files using double-precision hardware floating-point ABI.
+@item
+2 for files using the software floating-point ABI.
+@end itemize
+@end table
+
 @subsection MIPS Attributes

 @table @r
diff --git a/include/elf/m68k.h b/include/elf/m68k.h
index 2d3c12e050..e5b0592042 100644
--- a/include/elf/m68k.h
+++ b/include/elf/m68k.h
@@ -97,5 +97,17 @@ END_RELOC_NUMBERS (R_68K_max)
 #define EF_M68K_CF_EMAC_B	0x30  /* EMAC_B */
 #define EF_M68K_CF_FLOAT	0x40  /* Has float insns */
 #define EF_M68K_CF_MASK		0xFF
-
+
+/* GNU object attribute tags.  */
+enum
+{
+  /* 0-3 are generic.  */
+
+  /* FP ABI, low 2 bits:
+     1 for double precision hard-float,
+     2 for soft-float,
+     0 for not tagged or not using any ABIs affected by the differences. */
+  Tag_GNU_M68K_ABI_FP = 4,
+};
+
 #endif
diff --git a/ld/testsuite/ld-m68k/attr-gnu-4-0.s b/ld/testsuite/ld-m68k/attr-gnu-4-0.s
new file mode 100644
index 0000000000..a1437461d0
--- /dev/null
+++ b/ld/testsuite/ld-m68k/attr-gnu-4-0.s
@@ -0,0 +1 @@
+.gnu_attribute 4,0
diff --git a/ld/testsuite/ld-m68k/attr-gnu-4-00.d b/ld/testsuite/ld-m68k/attr-gnu-4-00.d
new file mode 100644
index 0000000000..467ad603cf
--- /dev/null
+++ b/ld/testsuite/ld-m68k/attr-gnu-4-00.d
@@ -0,0 +1,4 @@
+#source: attr-gnu-4-0.s
+#source: attr-gnu-4-0.s
+#ld: -r
+#readelf: -A
diff --git a/ld/testsuite/ld-m68k/attr-gnu-4-01.d b/ld/testsuite/ld-m68k/attr-gnu-4-01.d
new file mode 100644
index 0000000000..1e7fef0741
--- /dev/null
+++ b/ld/testsuite/ld-m68k/attr-gnu-4-01.d
@@ -0,0 +1,8 @@
+#source: attr-gnu-4-0.s
+#source: attr-gnu-4-1.s
+#ld: -r
+#readelf: -A
+
+Attribute Section: gnu
+File Attributes
+  Tag_GNU_M68K_ABI_FP: hard float
diff --git a/ld/testsuite/ld-m68k/attr-gnu-4-02.d b/ld/testsuite/ld-m68k/attr-gnu-4-02.d
new file mode 100644
index 0000000000..cc3945a215
--- /dev/null
+++ b/ld/testsuite/ld-m68k/attr-gnu-4-02.d
@@ -0,0 +1,8 @@
+#source: attr-gnu-4-0.s
+#source: attr-gnu-4-2.s
+#ld: -r
+#readelf: -A
+
+Attribute Section: gnu
+File Attributes
+  Tag_GNU_M68K_ABI_FP: soft float
diff --git a/ld/testsuite/ld-m68k/attr-gnu-4-1.s b/ld/testsuite/ld-m68k/attr-gnu-4-1.s
new file mode 100644
index 0000000000..e985a56f6b
--- /dev/null
+++ b/ld/testsuite/ld-m68k/attr-gnu-4-1.s
@@ -0,0 +1 @@
+.gnu_attribute 4,1
diff --git a/ld/testsuite/ld-m68k/attr-gnu-4-10.d b/ld/testsuite/ld-m68k/attr-gnu-4-10.d
new file mode 100644
index 0000000000..a6a798b4a4
--- /dev/null
+++ b/ld/testsuite/ld-m68k/attr-gnu-4-10.d
@@ -0,0 +1,8 @@
+#source: attr-gnu-4-1.s
+#source: attr-gnu-4-0.s
+#ld: -r
+#readelf: -A
+
+Attribute Section: gnu
+File Attributes
+  Tag_GNU_M68K_ABI_FP: hard float
diff --git a/ld/testsuite/ld-m68k/attr-gnu-4-11.d b/ld/testsuite/ld-m68k/attr-gnu-4-11.d
new file mode 100644
index 0000000000..ecc66a4925
--- /dev/null
+++ b/ld/testsuite/ld-m68k/attr-gnu-4-11.d
@@ -0,0 +1,8 @@
+#source: attr-gnu-4-1.s
+#source: attr-gnu-4-1.s
+#ld: -r
+#readelf: -A
+
+Attribute Section: gnu
+File Attributes
+  Tag_GNU_M68K_ABI_FP: hard float
diff --git a/ld/testsuite/ld-m68k/attr-gnu-4-12.d b/ld/testsuite/ld-m68k/attr-gnu-4-12.d
new file mode 100644
index 0000000000..49526b1750
--- /dev/null
+++ b/ld/testsuite/ld-m68k/attr-gnu-4-12.d
@@ -0,0 +1,4 @@
+#source: attr-gnu-4-1.s
+#source: attr-gnu-4-2.s
+#ld: -r
+#error: .* uses hard float, .* uses soft float.*
diff --git a/ld/testsuite/ld-m68k/attr-gnu-4-2.s b/ld/testsuite/ld-m68k/attr-gnu-4-2.s
new file mode 100644
index 0000000000..54ebf4ed8d
--- /dev/null
+++ b/ld/testsuite/ld-m68k/attr-gnu-4-2.s
@@ -0,0 +1 @@
+.gnu_attribute 4,2
diff --git a/ld/testsuite/ld-m68k/attr-gnu-4-20.d b/ld/testsuite/ld-m68k/attr-gnu-4-20.d
new file mode 100644
index 0000000000..92b410a3df
--- /dev/null
+++ b/ld/testsuite/ld-m68k/attr-gnu-4-20.d
@@ -0,0 +1,8 @@
+#source: attr-gnu-4-2.s
+#source: attr-gnu-4-0.s
+#ld: -r
+#readelf: -A
+
+Attribute Section: gnu
+File Attributes
+  Tag_GNU_M68K_ABI_FP: soft float
diff --git a/ld/testsuite/ld-m68k/attr-gnu-4-21.d b/ld/testsuite/ld-m68k/attr-gnu-4-21.d
new file mode 100644
index 0000000000..390dada36c
--- /dev/null
+++ b/ld/testsuite/ld-m68k/attr-gnu-4-21.d
@@ -0,0 +1,4 @@
+#source: attr-gnu-4-2.s
+#source: attr-gnu-4-1.s
+#ld: -r
+#error: .* uses hard float, .* uses soft float.*
diff --git a/ld/testsuite/ld-m68k/attr-gnu-4-22.d b/ld/testsuite/ld-m68k/attr-gnu-4-22.d
new file mode 100644
index 0000000000..cfa9b35a99
--- /dev/null
+++ b/ld/testsuite/ld-m68k/attr-gnu-4-22.d
@@ -0,0 +1,8 @@
+#source: attr-gnu-4-2.s
+#source: attr-gnu-4-2.s
+#ld: -r
+#readelf: -A
+
+Attribute Section: gnu
+File Attributes
+  Tag_GNU_M68K_ABI_FP: soft float
diff --git a/ld/testsuite/ld-m68k/m68k.exp b/ld/testsuite/ld-m68k/m68k.exp
index df859ba1fe..b61098b1c3 100644
--- a/ld/testsuite/ld-m68k/m68k.exp
+++ b/ld/testsuite/ld-m68k/m68k.exp
@@ -92,3 +92,14 @@ if { [istarget m68k-*-linux*] } then {

     run_ld_link_tests $m68k_tls_tests
 }
+
+run_dump_test "attr-gnu-4-00"
+run_dump_test "attr-gnu-4-01"
+run_dump_test "attr-gnu-4-02"
+run_dump_test "attr-gnu-4-10"
+run_dump_test "attr-gnu-4-11"
+run_dump_test "attr-gnu-4-12"
+run_dump_test "attr-gnu-4-20"
+run_dump_test "attr-gnu-4-21"
+run_dump_test "attr-gnu-4-22"
+
--
2.24.3



More information about the Binutils mailing list