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.
This commit is contained in:
Nelson Chu 2020-06-12 23:06:49 +08:00
parent cbd7581f34
commit 39ff0b8123
18 changed files with 257 additions and 100 deletions

View File

@ -1,3 +1,25 @@
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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);

View File

@ -1,3 +1,9 @@
2020-06-22 Nelson Chu <nelson.chu@sifive.com>
* 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.
2020-06-20 Alan Modra <amodra@gmail.com>
* configure.tgt: Set bfd_gas for all SH targets.

View File

@ -126,8 +126,6 @@ riscv_set_default_priv_spec (const char *s)
enum riscv_priv_spec_class class;
unsigned major, minor, revision;
obj_attribute *attr;
size_t buf_size;
char *buf;
/* Find the corresponding priv spec class. */
if (riscv_get_priv_spec_class (s, &class))
@ -149,40 +147,24 @@ riscv_set_default_priv_spec (const char *s)
minor = (unsigned) attr[Tag_RISCV_priv_spec_minor].i;
revision = (unsigned) attr[Tag_RISCV_priv_spec_revision].i;
/* The priv attributes setting 0.0.0 is meaningless. We should have set
the default_priv_spec by md_parse_option and riscv_after_parse_args,
so just skip the following setting. */
if (major == 0 && minor == 0 && revision == 0)
return 1;
if (riscv_get_priv_spec_class_from_numbers (major,
minor,
revision,
&class))
{
/* The priv attributes setting 0.0.0 is meaningless. We should have set
the default_priv_spec by md_parse_option and riscv_after_parse_args,
so just skip the following setting. */
if (class == PRIV_SPEC_CLASS_NONE)
return 1;
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);
}
if (riscv_get_priv_spec_class (buf, &class))
{
default_priv_spec = class;
free (buf);
return 1;
}
/* Still can not find the priv spec class. */
as_bad (_("Unknown default privilege spec `%d.%d.%d' set by "
"privilege attributes"), major, minor, revision);
free (buf);
return 0;
}

View File

@ -1,3 +1,9 @@
2020-06-22 Nelson Chu <nelson.chu@sifive.com>
* opcode/riscv.h (riscv_get_priv_spec_class): Move the function
forward declarations to bfd/elfxx-riscv.h.
(riscv_get_priv_spec_name): Likewise.
2020-06-15 Max Filippov <jcmvbkbc@gmail.com>
* elf/xtensa.h (xtensa_abi_choice): New declaration.

View File

@ -490,9 +490,5 @@ extern const struct riscv_ext_version riscv_ext_version_table[];
extern int
riscv_get_isa_spec_class (const char *, enum riscv_isa_spec_class *);
extern int
riscv_get_priv_spec_class (const char *, enum riscv_priv_spec_class *);
extern const char *
riscv_get_priv_spec_name (enum riscv_priv_spec_class);
#endif /* _RISCV_H_ */

View File

@ -1,3 +1,12 @@
2020-06-22 Nelson Chu <nelson.chu@sifive.com>
* 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.
2020-06-21 Alan Modra <amodra@gmail.com>
* ldfile.c: Replace uses of ENABLE_PLUGINS with BFD_SUPPORTS_PLUGINS.

View File

@ -2,4 +2,12 @@
#source: attr-merge-priv-spec-c.s
#as:
#ld: -r
#error: .*use privilege spec version 1.11.0 but the output use version 1.9.1.
#warning: .*warning: .*use privilege spec version 1.11.0 but the output use version 1.9.1.
#warning: .*warning: .*privilege spec version 1.9.1 can not be linked with other spec versions.
#readelf: -A
Attribute Section: riscv
File Attributes
Tag_RISCV_arch: [a-zA-Z0-9_\"].*
Tag_RISCV_priv_spec: 1
Tag_RISCV_priv_spec_minor: 11

View File

@ -2,4 +2,12 @@
#source: attr-merge-priv-spec-a.s
#as:
#ld: -r
#error: .*use privilege spec version 1.9.1 but the output use version 1.11.0.
#warning: .*warning: .*use privilege spec version 1.9.1 but the output use version 1.11.0.
#warning: .*warning: .*privilege spec version 1.9.1 can not be linked with other spec versions.
#readelf: -A
Attribute Section: riscv
File Attributes
Tag_RISCV_arch: [a-zA-Z0-9_\"].*
Tag_RISCV_priv_spec: 1
Tag_RISCV_priv_spec_minor: 11

View File

@ -3,4 +3,12 @@
#source: attr-merge-priv-spec-c.s
#as:
#ld: -r
#error: .*use privilege spec version 1.11.0 but the output use version 1.9.1.
#warning: .*warning: .*use privilege spec version 1.11.0 but the output use version 1.9.1.
#warning: .*warning: .*privilege spec version 1.9.1 can not be linked with other spec versions.
#readelf: -A
Attribute Section: riscv
File Attributes
Tag_RISCV_arch: [a-zA-Z0-9_\"].*
Tag_RISCV_priv_spec: 1
Tag_RISCV_priv_spec_minor: 11

View File

@ -3,4 +3,12 @@
#source: attr-merge-priv-spec-c.s
#as:
#ld: -r
#error: .*use privilege spec version 1.11.0 but the output use version 1.9.1.
#warning: .*warning: .*use privilege spec version 1.11.0 but the output use version 1.9.1.
#warning: .*warning: .*privilege spec version 1.9.1 can not be linked with other spec versions.
#readelf: -A
Attribute Section: riscv
File Attributes
Tag_RISCV_arch: [a-zA-Z0-9_\"].*
Tag_RISCV_priv_spec: 1
Tag_RISCV_priv_spec_minor: 11

View File

@ -3,4 +3,12 @@
#source: attr-merge-priv-spec-a.s
#as:
#ld: -r
#error: .*use privilege spec version 1.9.1 but the output use version 1.11.0.
#warning: .*warning: .*use privilege spec version 1.9.1 but the output use version 1.11.0.
#warning: .*warning: .*privilege spec version 1.9.1 can not be linked with other spec versions.
#readelf: -A
Attribute Section: riscv
File Attributes
Tag_RISCV_arch: [a-zA-Z0-9_\"].*
Tag_RISCV_priv_spec: 1
Tag_RISCV_priv_spec_minor: 11

View File

@ -3,4 +3,12 @@
#source: attr-merge-priv-spec-a.s
#as:
#ld: -r
#error: .*use privilege spec version 1.9.1 but the output use version 1.11.0.
#warning: .*warning: .*use privilege spec version 1.9.1 but the output use version 1.11.0.
#warning: .*warning: .*privilege spec version 1.9.1 can not be linked with other spec versions.
#readelf: -A
Attribute Section: riscv
File Attributes
Tag_RISCV_arch: [a-zA-Z0-9_\"].*
Tag_RISCV_priv_spec: 1
Tag_RISCV_priv_spec_minor: 11

View File

@ -1,3 +1,8 @@
2020-06-22 Nelson Chu <nelson.chu@sifive.com>
* riscv-opc.c: Move the structures and functions to bfd/elfxx-riscv.c.
* riscv-dis.c: Include elfxx-riscv.h.
2020-06-18 H.J. Lu <hongjiu.lu@intel.com>
* i386-dis.c (prefix_table): Revert the last vmgexit change.

View File

@ -27,6 +27,7 @@
#include "opintl.h"
#include "elf-bfd.h"
#include "elf/riscv.h"
#include "elfxx-riscv.h"
#include "bfd_stdint.h"
#include <ctype.h>

View File

@ -977,53 +977,3 @@ riscv_get_isa_spec_class (const char *s,
/* Can not find the supported ISA spec. */
return 0;
}
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 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;
}