aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorNelson Chu <nelson.chu@sifive.com>2020-06-12 23:06:49 +0800
committerNelson Chu <nelson.chu@sifive.com>2020-06-22 10:01:14 +0800
commit39ff0b812324f4b050bb0b367b269db6d4d0cb8b (patch)
treed26141dff4583849bf6a8e99c6ea7458b9dcd0a8 /bfd
parentcbd7581f343d85b4216db2eefdf601f6d988062d (diff)
downloadgdb-39ff0b812324f4b050bb0b367b269db6d4d0cb8b.zip
gdb-39ff0b812324f4b050bb0b367b269db6d4d0cb8b.tar.gz
gdb-39ff0b812324f4b050bb0b367b269db6d4d0cb8b.tar.bz2
RISC-V: Report warning when linking the objects with different priv specs.
We do know some conflicts among different privileged specs. For linker, the safest approach is that don't allow the object linked with others which may cause conflicts. But this may cause inconvenience since not all objects with conflicting priv specs are linked will cause problems. But it is hard to know the detailed conflict cases for linker, so we probably need a option to tell linker that we do know there are no conflicts, or we are willing to take risks to link the objects with conflicted priv specs. But the option is still under discussion. Therefore, we can report warnings rather than errors when linking the objects with conflicted priv specs. This not only makes the linker more flexible, but also warns people that the conflicts may happen. We also need to update the output priv spec version once the input priv spec is newer. bfd/ * elfxx-riscv.c (struct priv_spec_t priv_specs[]): Move them from opcodes/riscv-opc.c to bfd/elfxx-riscv.c, since we need it in linker. (riscv_get_priv_spec_class): Likewise. (riscv_get_priv_spec_name): Likewise. (riscv_get_priv_spec_class_from_numbers): New function, convert the version numbers into string, then call riscv_get_priv_spec_class to get the priv spec class. * elfxx-riscv.h (riscv_get_priv_spec_class): Move forward declaration from include/opcode/riscv.h to bfd/elfxx-riscv.h. (riscv_get_priv_spec_name): Likewise. (riscv_get_priv_spec_class_from_numbers): New forward declaration. (opcode/riscv.h): Include it in the header rather than elfxx-riscv.c. * elfnn-riscv.c (riscv_merge_attributes): Get the priv spec classes of input and output objects form their priv spec attributes by riscv_get_priv_spec_class_from_numbers. Report warning rather than errors when linking objects with differnet priv spec versions. We do know v1.9.1 may have conflicts to other versions, so report the warning, too. After that, update the output priv spec version to the newest one so far. gas/ * config/tc-riscv.c (buf_size, buf): Remove the unused variables. (riscv_set_default_priv_spec): Get the priv spec version from the priv spec attributes by riscv_get_priv_spec_class_from_numbers. include/ * opcode/riscv.h (riscv_get_priv_spec_class): Move the function forward declarations to bfd/elfxx-riscv.h. (riscv_get_priv_spec_name): Likewise. opcodes/ * riscv-opc.c: Move the structures and functions to bfd/elfxx-riscv.c. * riscv-dis.c: Include elfxx-riscv.h. ld/ * testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-01.d: Updated. * testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-02.d: Updated. * testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-03.d: Updated. * testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-04.d: Updated. * testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-05.d: Updated. * testsuite/ld-riscv-elf/attr-merge-priv-spec-failed-06.d: Updated.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/ChangeLog22
-rw-r--r--bfd/elfnn-riscv.c47
-rw-r--r--bfd/elfxx-riscv.c96
-rw-r--r--bfd/elfxx-riscv.h13
4 files changed, 166 insertions, 12 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index d9b66b5..6ac3c0f 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,5 +1,27 @@
2020-06-22 Nelson Chu <nelson.chu@sifive.com>
+ * elfxx-riscv.c (struct priv_spec_t priv_specs[]): Move them from
+ opcodes/riscv-opc.c to bfd/elfxx-riscv.c, since we need it in linker.
+ (riscv_get_priv_spec_class): Likewise.
+ (riscv_get_priv_spec_name): Likewise.
+ (riscv_get_priv_spec_class_from_numbers): New function, convert
+ the version numbers into string, then call riscv_get_priv_spec_class
+ to get the priv spec class.
+ * elfxx-riscv.h (riscv_get_priv_spec_class): Move forward declaration
+ from include/opcode/riscv.h to bfd/elfxx-riscv.h.
+ (riscv_get_priv_spec_name): Likewise.
+ (riscv_get_priv_spec_class_from_numbers): New forward declaration.
+ (opcode/riscv.h): Include it in the header rather than elfxx-riscv.c.
+ * elfnn-riscv.c (riscv_merge_attributes): Get the priv spec classes
+ of input and output objects form their priv spec attributes by
+ riscv_get_priv_spec_class_from_numbers. Report warning rather than
+ errors when linking objects with differnet priv spec versions. We do
+ know v1.9.1 may have conflicts to other versions, so report the
+ warning, too. After that, update the output priv spec version to the
+ newest one so far.
+
+2020-06-22 Nelson Chu <nelson.chu@sifive.com>
+
* elfnn-riscv.c (riscv_merge_attributes): Once we meet one of the
priv attributes, we will check the conflicts for all of them (major,
minor and revision), and then set the priv_attrs_merged to TRUE to
diff --git a/bfd/elfnn-riscv.c b/bfd/elfnn-riscv.c
index 2804459..00553f7 100644
--- a/bfd/elfnn-riscv.c
+++ b/bfd/elfnn-riscv.c
@@ -3052,25 +3052,31 @@ riscv_merge_attributes (bfd *ibfd, struct bfd_link_info *info)
unsigned int Tag_a = Tag_RISCV_priv_spec;
unsigned int Tag_b = Tag_RISCV_priv_spec_minor;
unsigned int Tag_c = Tag_RISCV_priv_spec_revision;
+ enum riscv_priv_spec_class in_priv_spec;
+ enum riscv_priv_spec_class out_priv_spec;
+
+ /* Get the priv spec class from elf attribute numbers. */
+ riscv_get_priv_spec_class_from_numbers (in_attr[Tag_a].i,
+ in_attr[Tag_b].i,
+ in_attr[Tag_c].i,
+ &in_priv_spec);
+ riscv_get_priv_spec_class_from_numbers (out_attr[Tag_a].i,
+ out_attr[Tag_b].i,
+ out_attr[Tag_c].i,
+ &out_priv_spec);
/* Allow to link the object without the priv specs. */
- if (out_attr[Tag_a].i == 0
- && out_attr[Tag_b].i == 0
- && out_attr[Tag_c].i == 0)
+ if (out_priv_spec == PRIV_SPEC_CLASS_NONE)
{
out_attr[Tag_a].i = in_attr[Tag_a].i;
out_attr[Tag_b].i = in_attr[Tag_b].i;
out_attr[Tag_c].i = in_attr[Tag_c].i;
}
- else if ((in_attr[Tag_a].i != 0
- || in_attr[Tag_b].i != 0
- || in_attr[Tag_c].i != 0)
- && (out_attr[Tag_a].i != in_attr[Tag_a].i
- || out_attr[Tag_b].i != in_attr[Tag_b].i
- || out_attr[Tag_c].i != in_attr[Tag_c].i))
+ else if (in_priv_spec != PRIV_SPEC_CLASS_NONE
+ && in_priv_spec != out_priv_spec)
{
_bfd_error_handler
- (_("error: %pB use privilege spec version %u.%u.%u but "
+ (_("warning: %pB use privilege spec version %u.%u.%u but "
"the output use version %u.%u.%u."),
ibfd,
in_attr[Tag_a].i,
@@ -3079,7 +3085,26 @@ riscv_merge_attributes (bfd *ibfd, struct bfd_link_info *info)
out_attr[Tag_a].i,
out_attr[Tag_b].i,
out_attr[Tag_c].i);
- result = FALSE;
+
+ /* The priv spec v1.9.1 can be linked with other spec
+ versions since the conflicts. We plan to drop the
+ v1.9.1 in a year or two, so this confict should be
+ removed in the future. */
+ if (in_priv_spec == PRIV_SPEC_CLASS_1P9P1
+ || out_priv_spec == PRIV_SPEC_CLASS_1P9P1)
+ {
+ _bfd_error_handler
+ (_("warning: privilege spec version 1.9.1 can not be "
+ "linked with other spec versions."));
+ }
+
+ /* Update the output priv attributes to the newest. */
+ if (in_priv_spec > out_priv_spec)
+ {
+ out_attr[Tag_a].i = in_attr[Tag_a].i;
+ out_attr[Tag_b].i = in_attr[Tag_b].i;
+ out_attr[Tag_c].i = in_attr[Tag_c].i;
+ }
}
priv_attrs_merged = TRUE;
}
diff --git a/bfd/elfxx-riscv.c b/bfd/elfxx-riscv.c
index 5dd36ab..fa46b06 100644
--- a/bfd/elfxx-riscv.c
+++ b/bfd/elfxx-riscv.c
@@ -25,7 +25,6 @@
#include "libbfd.h"
#include "elf-bfd.h"
#include "elf/riscv.h"
-#include "opcode/riscv.h"
#include "libiberty.h"
#include "elfxx-riscv.h"
#include "safe-ctype.h"
@@ -1750,3 +1749,98 @@ riscv_arch_str (unsigned xlen, const riscv_subset_list_t *subset)
return attr_str;
}
+
+/* Record the priv spec version string and the corresponding class. */
+
+struct priv_spec_t
+{
+ const char *name;
+ enum riscv_priv_spec_class class;
+};
+
+/* List for all supported privilege versions. */
+
+static const struct priv_spec_t priv_specs[] =
+{
+ {"1.9.1", PRIV_SPEC_CLASS_1P9P1},
+ {"1.10", PRIV_SPEC_CLASS_1P10},
+ {"1.11", PRIV_SPEC_CLASS_1P11},
+
+/* Terminate the list. */
+ {NULL, 0}
+};
+
+/* Get the corresponding CSR version class by giving a privilege
+ version string. */
+
+int
+riscv_get_priv_spec_class (const char *s,
+ enum riscv_priv_spec_class *class)
+{
+ const struct priv_spec_t *version;
+
+ if (s == NULL)
+ return 0;
+
+ for (version = &priv_specs[0]; version->name != NULL; ++version)
+ if (strcmp (version->name, s) == 0)
+ {
+ *class = version->class;
+ return 1;
+ }
+
+ /* Can not find the supported privilege version. */
+ return 0;
+}
+
+/* Get the corresponding CSR version class by giving privilege
+ version numbers. It is usually used to convert the priv
+ attribute numbers into the corresponding class. */
+
+int
+riscv_get_priv_spec_class_from_numbers (unsigned int major,
+ unsigned int minor,
+ unsigned int revision,
+ enum riscv_priv_spec_class *class)
+{
+ size_t buf_size;
+ char *buf;
+ int result = 1;
+
+ if (major == 0 && minor == 0 && revision == 0)
+ {
+ *class = PRIV_SPEC_CLASS_NONE;
+ return result;
+ }
+
+ buf_size = riscv_estimate_digit (major)
+ + 1 /* '.' */
+ + riscv_estimate_digit (minor)
+ + 1; /* string terminator */
+ if (revision != 0)
+ {
+ buf_size += 1 /* '.' */
+ + riscv_estimate_digit (revision);
+ buf = xmalloc (buf_size);
+ snprintf (buf, buf_size, "%d.%d.%d", major, minor, revision);
+ }
+ else
+ {
+ buf = xmalloc (buf_size);
+ snprintf (buf, buf_size, "%d.%d", major, minor);
+ }
+
+ result = riscv_get_priv_spec_class (buf, class);
+ free (buf);
+ return result;
+}
+
+/* Get the corresponding privilege version string by giving a CSR
+ version class. */
+
+const char *
+riscv_get_priv_spec_name (enum riscv_priv_spec_class class)
+{
+ /* The first enum is PRIV_SPEC_CLASS_NONE. */
+ return priv_specs[class - 1].name;
+}
diff --git a/bfd/elfxx-riscv.h b/bfd/elfxx-riscv.h
index 7b8f09b..c91b169 100644
--- a/bfd/elfxx-riscv.h
+++ b/bfd/elfxx-riscv.h
@@ -22,6 +22,7 @@
#include "elf/common.h"
#include "elf/internal.h"
+#include "opcode/riscv.h"
extern reloc_howto_type *
riscv_reloc_name_lookup (bfd *, const char *);
@@ -109,3 +110,15 @@ typedef enum riscv_isa_ext_class
riscv_isa_ext_class_t
riscv_get_prefix_class (const char *);
+
+extern int
+riscv_get_priv_spec_class (const char *, enum riscv_priv_spec_class *);
+
+extern int
+riscv_get_priv_spec_class_from_numbers (unsigned int,
+ unsigned int,
+ unsigned int,
+ enum riscv_priv_spec_class *);
+
+extern const char *
+riscv_get_priv_spec_name (enum riscv_priv_spec_class);