158 lines
4.5 KiB
Diff
158 lines
4.5 KiB
Diff
|
|
Signed-off-by: malachite <malachiten@outlook.com>
|
||
|
|
diff --git a/backends/riscv_retval.c b/backends/riscv_retval.c
|
||
|
|
index 0a1e02f..50c451a 100644
|
||
|
|
--- a/backends/riscv_retval.c
|
||
|
|
+++ b/backends/riscv_retval.c
|
||
|
|
@@ -1,6 +1,7 @@
|
||
|
|
/* Function return value location for Linux/RISC-V ABI.
|
||
|
|
Copyright (C) 2018 Sifive, Inc.
|
||
|
|
Copyright (C) 2013 Red Hat, Inc.
|
||
|
|
+ Copyright (C) 2024 Mark J. Wielaard <mark@klomp.org>
|
||
|
|
This file is part of elfutils.
|
||
|
|
|
||
|
|
This file is free software; you can redistribute it and/or modify
|
||
|
|
@@ -105,23 +106,123 @@ pass_in_fpr_lp64d (const Dwarf_Op **locp, Dwarf_Word size)
|
||
|
|
return size <= 8 ? 1 : 4;
|
||
|
|
}
|
||
|
|
|
||
|
|
+/* Checks if we can "flatten" the given type, Only handles the simple
|
||
|
|
+ cases where we have a struct with one or two the same base type
|
||
|
|
+ elements. */
|
||
|
|
static int
|
||
|
|
-flatten_aggregate_arg (Dwarf_Die *typedie __attribute__ ((unused)),
|
||
|
|
- Dwarf_Die *arg0 __attribute__ ((unused)),
|
||
|
|
- Dwarf_Die *arg1 __attribute__ ((unused)))
|
||
|
|
+flatten_aggregate_arg (Dwarf_Die *typedie,
|
||
|
|
+ Dwarf_Word size,
|
||
|
|
+ Dwarf_Die *arg0,
|
||
|
|
+ Dwarf_Die *arg1)
|
||
|
|
{
|
||
|
|
- /* ??? */
|
||
|
|
+ int tag0, tag1;
|
||
|
|
+ Dwarf_Die member;
|
||
|
|
+ Dwarf_Word encoding0, encoding1;
|
||
|
|
+ Dwarf_Attribute attr;
|
||
|
|
+ Dwarf_Word size0, size1;
|
||
|
|
+
|
||
|
|
+ if (size < 8 || size > 16)
|
||
|
|
+ return 0;
|
||
|
|
+
|
||
|
|
+ if (dwarf_child (typedie, arg0) != 0)
|
||
|
|
+ return 0;
|
||
|
|
+
|
||
|
|
+ tag0 = dwarf_tag (arg0);
|
||
|
|
+ while (tag0 != -1 && tag0 != DW_TAG_member)
|
||
|
|
+ {
|
||
|
|
+ if (dwarf_siblingof (arg0, arg0) != 0)
|
||
|
|
+ return 0;
|
||
|
|
+ tag0 = dwarf_tag (arg0);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (tag0 != DW_TAG_member)
|
||
|
|
+ return 0;
|
||
|
|
+
|
||
|
|
+ /* Remember where we are. */
|
||
|
|
+ member = *arg0;
|
||
|
|
+
|
||
|
|
+ tag0 = dwarf_peeled_die_type (arg0, arg0);
|
||
|
|
+ if (tag0 != DW_TAG_base_type)
|
||
|
|
+ return 0;
|
||
|
|
+
|
||
|
|
+ if (dwarf_attr_integrate (arg0, DW_AT_encoding, &attr) == NULL
|
||
|
|
+ || dwarf_formudata (&attr, &encoding0) != 0)
|
||
|
|
+ return 0;
|
||
|
|
+
|
||
|
|
+ if (dwarf_bytesize_aux (arg0, &size0) != 0)
|
||
|
|
+ return 0;
|
||
|
|
+
|
||
|
|
+ if (size == size0)
|
||
|
|
+ return 1; /* This one member is the whole size. */
|
||
|
|
+
|
||
|
|
+ if (size != 2 * size0)
|
||
|
|
+ return 0; /* We only handle two of the same. */
|
||
|
|
+
|
||
|
|
+ /* Look for another member with the same encoding. */
|
||
|
|
+ if (dwarf_siblingof (&member, arg1) != 0)
|
||
|
|
+ return 0;
|
||
|
|
+
|
||
|
|
+ tag1 = dwarf_tag (arg1);
|
||
|
|
+ while (tag1 != -1 && tag1 != DW_TAG_member)
|
||
|
|
+ {
|
||
|
|
+ if (dwarf_siblingof (arg1, arg1) != 0)
|
||
|
|
+ return 0;
|
||
|
|
+ tag1 = dwarf_tag (arg1);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (tag1 != DW_TAG_member)
|
||
|
|
+ return 0;
|
||
|
|
+
|
||
|
|
+ tag1 = dwarf_peeled_die_type (arg1, arg1);
|
||
|
|
+ if (tag1 != DW_TAG_base_type)
|
||
|
|
+ return 0; /* We can only handle two equal base types for now. */
|
||
|
|
+
|
||
|
|
+ if (dwarf_attr_integrate (arg1, DW_AT_encoding, &attr) == NULL
|
||
|
|
+ || dwarf_formudata (&attr, &encoding1) != 0
|
||
|
|
+ || encoding0 != encoding1)
|
||
|
|
+ return 0; /* We can only handle two of the same for now. */
|
||
|
|
+
|
||
|
|
+ if (dwarf_bytesize_aux (arg1, &size1) != 0)
|
||
|
|
+ return 0;
|
||
|
|
+
|
||
|
|
+ if (size0 != size1)
|
||
|
|
+ return 0; /* We can only handle two of the same for now. */
|
||
|
|
+
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
+/* arg0 and arg1 should be the peeled die types found by
|
||
|
|
+ flatten_aggregate_arg. */
|
||
|
|
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)))
|
||
|
|
+pass_by_flattened_arg (const Dwarf_Op **locp,
|
||
|
|
+ Dwarf_Word size,
|
||
|
|
+ Dwarf_Die *arg0,
|
||
|
|
+ Dwarf_Die *arg1 __attribute__((unused)))
|
||
|
|
{
|
||
|
|
- /* ??? */
|
||
|
|
- return -2;
|
||
|
|
+ /* For now we just assume arg0 and arg1 are the same type and
|
||
|
|
+ encoding. */
|
||
|
|
+ Dwarf_Word encoding;
|
||
|
|
+ Dwarf_Attribute attr;
|
||
|
|
+
|
||
|
|
+ if (dwarf_attr_integrate (arg0, DW_AT_encoding, &attr) == NULL
|
||
|
|
+ || dwarf_formudata (&attr, &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:
|
||
|
|
+ return pass_in_gpr_lp64 (locp, size);
|
||
|
|
+
|
||
|
|
+ case DW_ATE_float:
|
||
|
|
+ return pass_in_fpr_lp64d (locp, size);
|
||
|
|
+
|
||
|
|
+ default:
|
||
|
|
+ return -1;
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
|
||
|
|
int
|
||
|
|
@@ -158,7 +259,7 @@ riscv_return_value_location_lp64ifd (int fp, Dwarf_Die *functypedie,
|
||
|
|
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))
|
||
|
|
+ && flatten_aggregate_arg (&typedie, size, &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)
|
||
|
|
|