public inbox for elfutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] RISC-V: Add initial return value location support.
@ 2018-12-27 23:26 Jim Wilson
  2019-01-10 12:26 ` Mark Wielaard
  0 siblings, 1 reply; 5+ messages in thread
From: Jim Wilson @ 2018-12-27 23:26 UTC (permalink / raw)
  To: elfutils-devel; +Cc: Jim Wilson

Started with the aarch64 support and modified it for RISC-V.  The flattened
structure support hasn't been written yet, but the rest of it should be
correct for the LP64D ABI.  We have potentially 6 different ABIs to support,
so this requires checking elf header flags in riscv_init when setting the hook.

Signed-off-by: Jim Wilson <jimw@sifive.com>
---
 backends/ChangeLog      |   8 ++
 backends/Makefile.am    |   2 +-
 backends/riscv_init.c   |  10 +-
 backends/riscv_retval.c | 251 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 269 insertions(+), 2 deletions(-)
 create mode 100644 backends/riscv_retval.c

diff --git a/backends/ChangeLog b/backends/ChangeLog
index c8234072..637aa8c2 100644
--- a/backends/ChangeLog
+++ b/backends/ChangeLog
@@ -1,5 +1,13 @@
 2018-12-27  Jim Wilson  <jimw@sifive.com>
 
+	* Makefile.am (riscv_SRCS): Add riscv_retval.c.
+	* riscv_init.c: Include libelfP.h.
+	(riscv_return_value_location_lp64d): Declare.
+	(riscv_init): Delete unused attribute from elf parameter.  Register
+	riscv_return_value_location_lp64d hook if 64-bit ELF and 64-bit FP
+	registers.
+	* riscv_retval.c: New file.
+
 	* riscv_corenote.c (prstatus_regs): Change offset from 1 to 8.
 	(PRSTATUS_REGSET_ITEMS): New.
 
diff --git a/backends/Makefile.am b/backends/Makefile.am
index 9d340425..fedeb93a 100644
--- a/backends/Makefile.am
+++ b/backends/Makefile.am
@@ -132,7 +132,7 @@ libebl_bpf_pic_a_SOURCES = $(bpf_SRCS)
 am_libebl_bpf_pic_a_OBJECTS = $(bpf_SRCS:.c=.os)
 
 riscv_SRCS = riscv_init.c riscv_symbol.c riscv_cfi.c riscv_regs.c \
-	     riscv_initreg.c riscv_corenote.c
+	     riscv_initreg.c riscv_corenote.c riscv_retval.c
 libebl_riscv_pic_a_SOURCES = $(riscv_SRCS)
 am_libebl_riscv_pic_a_OBJECTS = $(riscv_SRCS:.c=.os)
 
diff --git a/backends/riscv_init.c b/backends/riscv_init.c
index 8b7ce8b5..ecee2910 100644
--- a/backends/riscv_init.c
+++ b/backends/riscv_init.c
@@ -33,12 +33,16 @@
 #define RELOC_PREFIX	R_RISCV_
 #include "libebl_CPU.h"
 
+#include "libelfP.h"
+
 /* This defines the common reloc hooks based on riscv_reloc.def.  */
 #include "common-reloc.c"
 
+extern __typeof (EBLHOOK (return_value_location))
+  riscv_return_value_location_lp64d attribute_hidden;
 
 const char *
-riscv_init (Elf *elf __attribute__ ((unused)),
+riscv_init (Elf *elf,
 	    GElf_Half machine __attribute__ ((unused)),
 	    Ebl *eh,
 	    size_t ehlen)
@@ -59,6 +63,10 @@ riscv_init (Elf *elf __attribute__ ((unused)),
   HOOK (eh, machine_flag_check);
   HOOK (eh, set_initial_registers_tid);
   HOOK (eh, core_note);
+  if (eh->class == ELFCLASS64
+      && ((elf->state.elf64.ehdr->e_flags & EF_RISCV_FLOAT_ABI)
+	  == EF_RISCV_FLOAT_ABI_DOUBLE))
+    eh->return_value_location = riscv_return_value_location_lp64d;
 
   return MODVERSION;
 }
diff --git a/backends/riscv_retval.c b/backends/riscv_retval.c
new file mode 100644
index 00000000..35b6010b
--- /dev/null
+++ b/backends/riscv_retval.c
@@ -0,0 +1,251 @@
+/* Function return value location for Linux/RISC-V ABI.
+   Copyright (C) 2018 Sifive, Inc.
+   Copyright (C) 2013 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <inttypes.h>
+
+#include <assert.h>
+#include <dwarf.h>
+
+#define BACKEND riscv_
+#include "libebl_CPU.h"
+
+static int
+dwarf_bytesize_aux (Dwarf_Die *die, Dwarf_Word *sizep)
+{
+  int bits;
+  if (((bits = 8 * dwarf_bytesize (die)) < 0
+       && (bits = dwarf_bitsize (die)) < 0)
+      || bits % 8 != 0)
+    return -1;
+
+  *sizep = bits / 8;
+  return 0;
+}
+
+static int
+pass_in_gpr_lp64 (const Dwarf_Op **locp, Dwarf_Word size)
+{
+  static const Dwarf_Op loc[] =
+    {
+      { .atom = DW_OP_reg10 }, { .atom = DW_OP_piece, .number = 8 },
+      { .atom = DW_OP_reg11 }, { .atom = DW_OP_piece, .number = 8 }
+    };
+
+  *locp = loc;
+  return size <= 8 ? 1 : 4;
+}
+
+static int
+pass_by_ref (const Dwarf_Op **locp)
+{
+  static const Dwarf_Op loc[] = { { .atom = DW_OP_breg10 } };
+
+  *locp = loc;
+  return 1;
+}
+
+static int
+pass_in_fpr_lp64f (const Dwarf_Op **locp, Dwarf_Word size)
+{
+  static const Dwarf_Op loc[] =
+    {
+      { .atom = DW_OP_regx, .number = 42 },
+      { .atom = DW_OP_piece, .number = 4 },
+      { .atom = DW_OP_regx, .number = 43 },
+      { .atom = DW_OP_piece, .number = 4 }
+    };
+
+  *locp = loc;
+  return size <= 4 ? 1 : 4;
+}
+
+static int
+pass_in_fpr_lp64d (const Dwarf_Op **locp, Dwarf_Word size)
+{
+  static const Dwarf_Op loc[] =
+    {
+      { .atom = DW_OP_regx, .number = 42 },
+      { .atom = DW_OP_piece, .number = 8 },
+      { .atom = DW_OP_regx, .number = 43 },
+      { .atom = DW_OP_piece, .number = 8 }
+    };
+
+  *locp = loc;
+  return size <= 8 ? 1 : 4;
+}
+
+static int
+flatten_aggregate_arg (Dwarf_Die *typedie __attribute__ ((unused)),
+		       Dwarf_Die *arg0 __attribute__ ((unused)),
+		       Dwarf_Die *arg1 __attribute__ ((unused)))
+{
+  /* ??? */
+  return 1;
+}
+
+static int
+pass_by_flattened_arg (const Dwarf_Op **locp __attribute__ ((unused)),
+		       Dwarf_Word size __attribute__ ((unused)),
+		       Dwarf_Die *arg0 __attribute__ ((unused)),
+		       Dwarf_Die *arg1 __attribute__ ((unused)))
+{
+  /* ??? */
+  return -2;
+}
+
+int
+riscv_return_value_location_lp64d (Dwarf_Die *functypedie,
+				   const Dwarf_Op **locp)
+{
+  /* Start with the function's type, and get the DW_AT_type attribute,
+     which is the type of the return value.  */
+  Dwarf_Die typedie;
+  int tag = dwarf_peeled_die_type (functypedie, &typedie);
+  if (tag <= 0)
+    return tag;
+
+  Dwarf_Word size = (Dwarf_Word)-1;
+
+  /* If the argument type is a Composite Type that is larger than 16
+     bytes, then the argument is copied to memory allocated by the
+     caller and the argument is replaced by a pointer to the copy.  */
+  if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type
+      || tag == DW_TAG_class_type || tag == DW_TAG_array_type)
+    {
+      Dwarf_Die arg0, arg1;
+
+      if (dwarf_aggregate_size (&typedie, &size) < 0)
+	return -1;
+      /* A struct containing just one floating-point real is passed as though
+	 it were a standalone floating-point real.  A struct containing two
+	 floating-point reals is passed in two floating-point registers, if
+	 neither is more than FLEN bits wide.  A struct containing just one
+	 complex floating-point number is passed as though it were a struct
+	 containing two floating-point reals.  A struct containing one
+	 floating-point real and one integer (or bitfield), in either order,
+	 is passed in a floating-point register and an integer register,
+	 provided the floating-point real is no more than FLEN bits wide and
+	 the integer is no more than XLEN bits wide.  */
+      if (tag == DW_TAG_structure_type
+	  && flatten_aggregate_arg (&typedie, &arg0, &arg1))
+	return pass_by_flattened_arg (locp, size, &arg0, &arg1);
+      /* Aggregates larger than 2*XLEN bits are passed by reference.  */
+      else if (size > 16)
+	return pass_by_ref (locp);
+      /* Aggregates whose total size is no more than XLEN bits are passed in
+	 a register.  Aggregates whose total size is no more than 2*XLEN bits
+	 are passed in a pair of registers.  */
+      else
+	return pass_in_gpr_lp64 (locp, size);
+    }
+
+  if (tag == DW_TAG_base_type
+      || tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
+    {
+      if (dwarf_bytesize_aux (&typedie, &size) < 0)
+	{
+	  if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
+	    size = 8;
+	  else
+	    return -1;
+	}
+
+      Dwarf_Attribute attr_mem;
+      if (tag == DW_TAG_base_type)
+	{
+	  Dwarf_Word encoding;
+	  if (dwarf_formudata (dwarf_attr_integrate (&typedie, DW_AT_encoding,
+						     &attr_mem),
+			       &encoding) != 0)
+	    return -1;
+
+	  switch (encoding)
+	    {
+	    case DW_ATE_boolean:
+	    case DW_ATE_signed:
+	    case DW_ATE_unsigned:
+	    case DW_ATE_unsigned_char:
+	    case DW_ATE_signed_char:
+	      /* Scalars that are at most XLEN bits wide are passed in a single
+		 argument register.  Scalars that are 2*XLEN bits wide are
+		 passed in a pair of argument registers.  Scalars wider than
+		 2*XLEN are passed by reference; there are none for LP64D.  */
+	      return pass_in_gpr_lp64 (locp, size);
+
+	    case DW_ATE_float:
+	      /* A real floating-point argument is passed in a floating-point
+		 argument register if it is no more than FLEN bits wide,
+		 otherwise it is passed according to the integer calling
+		 convention.  */
+	      switch (size)
+		{
+		case 4: /* single */
+		case 8: /* double */
+		  return pass_in_fpr_lp64d (locp, size);
+
+		case 16: /* quad */
+		  return pass_in_gpr_lp64 (locp, size);
+
+		default:
+		  return -2;
+		}
+
+	    case DW_ATE_complex_float:
+	      /* A complex floating-point number is passed as though it were a
+		 struct containing two floating-point reals.  */
+	      switch (size)
+		{
+		case 8: /* float _Complex */
+		  return pass_in_fpr_lp64f (locp, size);
+
+		case 16: /* double _Complex */
+		  return pass_in_fpr_lp64d (locp, size);
+
+		case 32: /* long double _Complex */
+		  return pass_by_ref (locp);
+
+		default:
+		  return -2;
+		}
+	    }
+
+	  return -2;
+	}
+      else
+	return pass_in_gpr_lp64 (locp, size);
+    }
+
+  *locp = NULL;
+  return 0;
+}
-- 
2.19.2

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] RISC-V: Add initial return value location support.
  2018-12-27 23:26 [PATCH] RISC-V: Add initial return value location support Jim Wilson
@ 2019-01-10 12:26 ` Mark Wielaard
  2019-01-10 18:56   ` Jim Wilson
                     ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Mark Wielaard @ 2019-01-10 12:26 UTC (permalink / raw)
  To: Jim Wilson, elfutils-devel

On Thu, 2018-12-27 at 15:26 -0800, Jim Wilson wrote:
> Started with the aarch64 support and modified it for RISC-V.  The
> flattened
> structure support hasn't been written yet, but the rest of it should
> be
> correct for the LP64D ABI.  We have potentially 6 different ABIs to
> support,
> so this requires checking elf header flags in riscv_init when setting
> the hook.

nitpick. Please keep the commit message lines < 76 chars if possible.
Looks good and it resolves the run-native-test.sh (on risc-v).

We really should add a non-native test, so it is easier to test on
other arches. But currently only aarch64 has one (run-funcretval.sh).
I'll see if I can extend that to other arches. Then we can also see if
we can get the aggregates correct.

The comments explain things well, but it would be good to have official
references to the calling convention and DWARF register mappings.
The calling convention is explained in:

https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#procedure-calling-convention
But I couldn't find an official DWARF register mapping.
If you have references I like to add them to the code.

Pushed as is.

Thanks,

Mark

BTW. Just for other reviewers.

> +static int
> +pass_in_gpr_lp64 (const Dwarf_Op **locp, Dwarf_Word size)
> +{
> +  static const Dwarf_Op loc[] =
> +    {
> +      { .atom = DW_OP_reg10 }, { .atom = DW_OP_piece, .number = 8 },
> +      { .atom = DW_OP_reg11 }, { .atom = DW_OP_piece, .number = 8 }
> +    };
> +
> +  *locp = loc;
> +  return size <= 8 ? 1 : 4;
> +}

Other backends also do this, but it might not be immediately clear (at
least I had to double check). When the size fits into a register we
pretend that the returned loc description is simply of size 1
(DW_OP_reg10), otherwise it is split across the two registers (size 4,
two pieces).

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] RISC-V: Add initial return value location support.
  2019-01-10 12:26 ` Mark Wielaard
@ 2019-01-10 18:56   ` Jim Wilson
  2019-01-10 18:58   ` Jim Wilson
  2019-01-18 21:23   ` Jim Wilson
  2 siblings, 0 replies; 5+ messages in thread
From: Jim Wilson @ 2019-01-10 18:56 UTC (permalink / raw)
  To: Mark Wielaard; +Cc: elfutils-devel

On Thu, Jan 10, 2019 at 4:26 AM Mark Wielaard <mark@klomp.org> wrote:
> The comments explain things well, but it would be good to have official
> references to the calling convention and DWARF register mappings.
> The calling convention is explained in:
>
> https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#procedure-calling-convention
> But I couldn't find an official DWARF register mapping.
> If you have references I like to add them to the code.

There is an issue asking us to add DWARF register mappings.  This was
filed before gdb was upstream and so some the comments are out of
date, but most of the info is still correct.
https://github.com/riscv/riscv-elf-psabi-doc/issues/70
I guess I should put that on my to do list to finish this now.

Jim

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] RISC-V: Add initial return value location support.
  2019-01-10 12:26 ` Mark Wielaard
  2019-01-10 18:56   ` Jim Wilson
@ 2019-01-10 18:58   ` Jim Wilson
  2019-01-18 21:23   ` Jim Wilson
  2 siblings, 0 replies; 5+ messages in thread
From: Jim Wilson @ 2019-01-10 18:58 UTC (permalink / raw)
  To: Mark Wielaard; +Cc: elfutils-devel

On Thu, Jan 10, 2019 at 4:26 AM Mark Wielaard <mark@klomp.org> wrote:
> We really should add a non-native test, so it is easier to test on
> other arches. But currently only aarch64 has one (run-funcretval.sh).
> I'll see if I can extend that to other arches. Then we can also see if
> we can get the aggregates correct.

RISC-V will require additional types for full coverage.  I've been
adding extra types to my local copy of the testcase .c file as I
implement them, but I still have a ways to go before this is finished,
and a few too many things on my to do list.

Jim

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] RISC-V: Add initial return value location support.
  2019-01-10 12:26 ` Mark Wielaard
  2019-01-10 18:56   ` Jim Wilson
  2019-01-10 18:58   ` Jim Wilson
@ 2019-01-18 21:23   ` Jim Wilson
  2 siblings, 0 replies; 5+ messages in thread
From: Jim Wilson @ 2019-01-18 21:23 UTC (permalink / raw)
  To: Mark Wielaard; +Cc: elfutils-devel

On Thu, Jan 10, 2019 at 4:26 AM Mark Wielaard <mark@klomp.org> wrote:
> https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#procedure-calling-convention
> But I couldn't find an official DWARF register mapping.
> If you have references I like to add them to the code.

This document now has a chapter for DWARF info, with just one table to
specify the DWARF register mapping.
https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md#dwarf-register-numbers

Jim

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2019-01-18 21:23 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-27 23:26 [PATCH] RISC-V: Add initial return value location support Jim Wilson
2019-01-10 12:26 ` Mark Wielaard
2019-01-10 18:56   ` Jim Wilson
2019-01-10 18:58   ` Jim Wilson
2019-01-18 21:23   ` Jim Wilson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).