From 0385e82a5e543b98343b84c2f641e33a5e267eab Mon Sep 17 00:00:00 2001 From: Jozef Lawrynowicz Date: Fri, 16 Aug 2019 14:16:58 +0100 Subject: [PATCH] MSP430: Add new Data Region GNU object attribute --- bfd/elf32-msp430.c | 82 ++++++---- binutils/readelf.c | 32 +++- gas/config/tc-msp430.c | 140 +++++++++++++++++- gas/doc/as.texi | 17 +++ gas/doc/c-msp430.texi | 12 ++ gas/testsuite/gas/msp430/attr-430-small-bad.d | 4 + gas/testsuite/gas/msp430/attr-430-small-bad.l | 4 + .../gas/msp430/attr-430-small-good.d | 6 + gas/testsuite/gas/msp430/attr-430-small.s | 3 + .../gas/msp430/attr-430x-large-any-bad.d | 4 + .../gas/msp430/attr-430x-large-any-bad.l | 4 + .../gas/msp430/attr-430x-large-any-good.d | 6 + .../gas/msp430/attr-430x-large-any.s | 4 + .../gas/msp430/attr-430x-large-lower-bad.d | 4 + .../gas/msp430/attr-430x-large-lower-bad.l | 3 + .../gas/msp430/attr-430x-large-lower-good.d | 6 + .../gas/msp430/attr-430x-large-lower.s | 4 + gas/testsuite/gas/msp430/msp430.exp | 6 + include/elf/msp430.h | 42 ++++++ ld/testsuite/ld-msp430-elf/attr-gnu-main.s | 8 + ld/testsuite/ld-msp430-elf/attr-gnu-obj.s | 2 + .../attr-gnu-region-lower-upper.d | 6 + .../ld-msp430-elf/attr-gnu-region-lower.d | 12 ++ .../ld-msp430-elf/attr-gnu-region-upper.d | 13 ++ ld/testsuite/ld-msp430-elf/msp430-elf.exp | 12 +- 25 files changed, 402 insertions(+), 34 deletions(-) create mode 100644 gas/testsuite/gas/msp430/attr-430-small-bad.d create mode 100644 gas/testsuite/gas/msp430/attr-430-small-bad.l create mode 100644 gas/testsuite/gas/msp430/attr-430-small-good.d create mode 100644 gas/testsuite/gas/msp430/attr-430-small.s create mode 100644 gas/testsuite/gas/msp430/attr-430x-large-any-bad.d create mode 100644 gas/testsuite/gas/msp430/attr-430x-large-any-bad.l create mode 100644 gas/testsuite/gas/msp430/attr-430x-large-any-good.d create mode 100644 gas/testsuite/gas/msp430/attr-430x-large-any.s create mode 100644 gas/testsuite/gas/msp430/attr-430x-large-lower-bad.d create mode 100644 gas/testsuite/gas/msp430/attr-430x-large-lower-bad.l create mode 100644 gas/testsuite/gas/msp430/attr-430x-large-lower-good.d create mode 100644 gas/testsuite/gas/msp430/attr-430x-large-lower.s create mode 100644 ld/testsuite/ld-msp430-elf/attr-gnu-main.s create mode 100644 ld/testsuite/ld-msp430-elf/attr-gnu-obj.s create mode 100644 ld/testsuite/ld-msp430-elf/attr-gnu-region-lower-upper.d create mode 100644 ld/testsuite/ld-msp430-elf/attr-gnu-region-lower.d create mode 100644 ld/testsuite/ld-msp430-elf/attr-gnu-region-upper.d diff --git a/bfd/elf32-msp430.c b/bfd/elf32-msp430.c index fe5fd8ff8c..35cb71e3f1 100644 --- a/bfd/elf32-msp430.c +++ b/bfd/elf32-msp430.c @@ -2408,15 +2408,15 @@ data_model (int model) } } -/* Merge MSPABI object attributes from IBFD into OBFD. +/* Merge MSPABI and GNU object attributes from IBFD into OBFD. Raise an error if there are conflicting attributes. */ static bfd_boolean -elf32_msp430_merge_mspabi_attributes (bfd *ibfd, struct bfd_link_info *info) +elf32_msp430_merge_msp430_attributes (bfd *ibfd, struct bfd_link_info *info) { bfd *obfd = info->output_bfd; - obj_attribute *in_attr; - obj_attribute *out_attr; + obj_attribute *in_msp_attr, *in_gnu_attr; + obj_attribute *out_msp_attr, *out_gnu_attr; bfd_boolean result = TRUE; static bfd * first_input_bfd = NULL; @@ -2435,45 +2435,47 @@ elf32_msp430_merge_mspabi_attributes (bfd *ibfd, struct bfd_link_info *info) { _bfd_elf_copy_obj_attributes (ibfd, obfd); - out_attr = elf_known_obj_attributes_proc (obfd); + out_msp_attr = elf_known_obj_attributes_proc (obfd); /* Use the Tag_null value to indicate that the attributes have been initialized. */ - out_attr[0].i = 1; + out_msp_attr[0].i = 1; first_input_bfd = ibfd; return TRUE; } - in_attr = elf_known_obj_attributes_proc (ibfd); - out_attr = elf_known_obj_attributes_proc (obfd); + in_msp_attr = elf_known_obj_attributes_proc (ibfd); + out_msp_attr = elf_known_obj_attributes_proc (obfd); + in_gnu_attr = elf_known_obj_attributes (ibfd) [OBJ_ATTR_GNU]; + out_gnu_attr = elf_known_obj_attributes (obfd) [OBJ_ATTR_GNU]; /* The ISAs must be the same. */ - if (in_attr[OFBA_MSPABI_Tag_ISA].i != out_attr[OFBA_MSPABI_Tag_ISA].i) + if (in_msp_attr[OFBA_MSPABI_Tag_ISA].i != out_msp_attr[OFBA_MSPABI_Tag_ISA].i) { _bfd_error_handler /* xgettext:c-format */ (_("error: %pB uses %s instructions but %pB uses %s"), - ibfd, isa_type (in_attr[OFBA_MSPABI_Tag_ISA].i), - first_input_bfd, isa_type (out_attr[OFBA_MSPABI_Tag_ISA].i)); + ibfd, isa_type (in_msp_attr[OFBA_MSPABI_Tag_ISA].i), + first_input_bfd, isa_type (out_msp_attr[OFBA_MSPABI_Tag_ISA].i)); result = FALSE; } /* The code models must be the same. */ - if (in_attr[OFBA_MSPABI_Tag_Code_Model].i != - out_attr[OFBA_MSPABI_Tag_Code_Model].i) + if (in_msp_attr[OFBA_MSPABI_Tag_Code_Model].i != + out_msp_attr[OFBA_MSPABI_Tag_Code_Model].i) { _bfd_error_handler /* xgettext:c-format */ (_("error: %pB uses the %s code model whereas %pB uses the %s code model"), - ibfd, code_model (in_attr[OFBA_MSPABI_Tag_Code_Model].i), - first_input_bfd, code_model (out_attr[OFBA_MSPABI_Tag_Code_Model].i)); + ibfd, code_model (in_msp_attr[OFBA_MSPABI_Tag_Code_Model].i), + first_input_bfd, code_model (out_msp_attr[OFBA_MSPABI_Tag_Code_Model].i)); result = FALSE; } /* The large code model is only supported by the MSP430X. */ - if (in_attr[OFBA_MSPABI_Tag_Code_Model].i == 2 - && out_attr[OFBA_MSPABI_Tag_ISA].i != 2) + if (in_msp_attr[OFBA_MSPABI_Tag_Code_Model].i == 2 + && out_msp_attr[OFBA_MSPABI_Tag_ISA].i != 2) { _bfd_error_handler /* xgettext:c-format */ @@ -2483,41 +2485,65 @@ elf32_msp430_merge_mspabi_attributes (bfd *ibfd, struct bfd_link_info *info) } /* The data models must be the same. */ - if (in_attr[OFBA_MSPABI_Tag_Data_Model].i != - out_attr[OFBA_MSPABI_Tag_Data_Model].i) + if (in_msp_attr[OFBA_MSPABI_Tag_Data_Model].i != + out_msp_attr[OFBA_MSPABI_Tag_Data_Model].i) { _bfd_error_handler /* xgettext:c-format */ (_("error: %pB uses the %s data model whereas %pB uses the %s data model"), - ibfd, data_model (in_attr[OFBA_MSPABI_Tag_Data_Model].i), - first_input_bfd, data_model (out_attr[OFBA_MSPABI_Tag_Data_Model].i)); + ibfd, data_model (in_msp_attr[OFBA_MSPABI_Tag_Data_Model].i), + first_input_bfd, data_model (out_msp_attr[OFBA_MSPABI_Tag_Data_Model].i)); result = FALSE; } /* The small code model requires the use of the small data model. */ - if (in_attr[OFBA_MSPABI_Tag_Code_Model].i == 1 - && out_attr[OFBA_MSPABI_Tag_Data_Model].i != 1) + if (in_msp_attr[OFBA_MSPABI_Tag_Code_Model].i == 1 + && out_msp_attr[OFBA_MSPABI_Tag_Data_Model].i != 1) { _bfd_error_handler /* xgettext:c-format */ (_("error: %pB uses the small code model but %pB uses the %s data model"), ibfd, first_input_bfd, - data_model (out_attr[OFBA_MSPABI_Tag_Data_Model].i)); + data_model (out_msp_attr[OFBA_MSPABI_Tag_Data_Model].i)); result = FALSE; } /* The large data models are only supported by the MSP430X. */ - if (in_attr[OFBA_MSPABI_Tag_Data_Model].i > 1 - && out_attr[OFBA_MSPABI_Tag_ISA].i != 2) + if (in_msp_attr[OFBA_MSPABI_Tag_Data_Model].i > 1 + && out_msp_attr[OFBA_MSPABI_Tag_ISA].i != 2) { _bfd_error_handler /* xgettext:c-format */ (_("error: %pB uses the %s data model but %pB only uses MSP430 instructions"), - ibfd, data_model (in_attr[OFBA_MSPABI_Tag_Data_Model].i), + ibfd, data_model (in_msp_attr[OFBA_MSPABI_Tag_Data_Model].i), first_input_bfd); result = FALSE; } + /* Just ignore the data region unless the large memory model is in use. + We have already checked that ibfd and obfd use the same memory model. */ + if ((in_msp_attr[OFBA_MSPABI_Tag_Code_Model].i + == OFBA_MSPABI_Val_Code_Model_LARGE) + && (in_msp_attr[OFBA_MSPABI_Tag_Data_Model].i + == OFBA_MSPABI_Val_Data_Model_LARGE)) + { + /* We cannot allow "lower region only" to be linked with any other + values (i.e. ANY or NONE). + Before this attribute existed, "ANY" region was the default. */ + bfd_boolean ibfd_lower_region_used + = (in_gnu_attr[Tag_GNU_MSP430_Data_Region].i == Val_GNU_MSP430_Data_Region_Lower); + bfd_boolean obfd_lower_region_used + = (out_gnu_attr[Tag_GNU_MSP430_Data_Region].i == Val_GNU_MSP430_Data_Region_Lower); + if (ibfd_lower_region_used != obfd_lower_region_used) + { + _bfd_error_handler + (_("error: %pB can use the upper region for data, but %pB assumes data is exclusively in lower memory"), + ibfd_lower_region_used ? obfd : ibfd, + ibfd_lower_region_used ? ibfd : obfd); + result = FALSE; + } + } + return result; } @@ -2536,7 +2562,7 @@ elf32_msp430_merge_private_bfd_data (bfd *ibfd, struct bfd_link_info *info) max (bfd_get_mach (ibfd), bfd_get_mach (obfd))); #undef max - return elf32_msp430_merge_mspabi_attributes (ibfd, info); + return elf32_msp430_merge_msp430_attributes (ibfd, info); } static bfd_boolean diff --git a/binutils/readelf.c b/binutils/readelf.c index cc168163b2..f890d56a13 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -15731,6 +15731,36 @@ display_msp430x_attribute (unsigned char * p, return p; } +static unsigned char * +display_msp430_gnu_attribute (unsigned char * p, + unsigned int tag, + const unsigned char * const end) +{ + if (tag == Tag_GNU_MSP430_Data_Region) + { + unsigned int len; + int val; + + val = read_uleb128 (p, &len, end); + p += len; + printf (" Tag_GNU_MSP430_Data_Region: "); + + switch (val) + { + case Val_GNU_MSP430_Data_Region_Any: + printf (_("Any Region\n")); + break; + case Val_GNU_MSP430_Data_Region_Lower: + printf (_("Lower Region Only\n")); + break; + default: + printf ("??? (%d)\n", val); + } + return p; + } + return display_tag_value (tag & 1, p, end); +} + struct riscv_attr_tag_t { const char *name; int tag; @@ -19555,7 +19585,7 @@ process_arch_specific (Filedata * filedata) case EM_MSP430: return process_attributes (filedata, "mspabi", SHT_MSP430_ATTRIBUTES, display_msp430x_attribute, - display_generic_attribute); + display_msp430_gnu_attribute); case EM_RISCV: return process_attributes (filedata, "riscv", SHT_RISCV_ATTRIBUTES, diff --git a/gas/config/tc-msp430.c b/gas/config/tc-msp430.c index 5821b1c811..73e740a365 100644 --- a/gas/config/tc-msp430.c +++ b/gas/config/tc-msp430.c @@ -689,6 +689,8 @@ static bfd_boolean do_unknown_interrupt_nops = TRUE; static bfd_boolean move_data = FALSE; #define OPTION_DATA_REGION 'r' static bfd_boolean upper_data_region_in_use = FALSE; +/* The default is to use the lower region only. */ +static bfd_boolean lower_data_region_only = TRUE; enum { @@ -1473,6 +1475,13 @@ md_parse_option (int c, const char * arg) if (strcmp (arg, "upper") == 0 || strcmp (arg, "either") == 0) upper_data_region_in_use = TRUE; + if (strcmp (arg, "upper") == 0 + || strcmp (arg, "either") == 0 + /* With data-region=none, the compiler has generated code assuming data + could be in the upper region, but nothing has been explicitly placed + there. */ + || strcmp (arg, "none") == 0) + lower_data_region_only = FALSE; return 1; } @@ -1598,6 +1607,114 @@ msp430_refsym (int arg ATTRIBUTE_UNUSED) (void) symbol_find_or_make (sym_name); } +/* Handle a .mspabi_attribute or .gnu_attribute directive. + attr_type is 0 for .mspabi_attribute or 1 for .gnu_attribute. + This is only used for validating the attributes in the assembly file against + the options gas has been invoked with. If the attributes and options are + compatible then we add the attributes to the assembly file in + msp430_md_end. */ +static void +msp430_object_attribute (int attr_type) +{ + char tag_name_s[32]; + char tag_value_s[32]; + int tag_name, tag_value; + /* First operand is the tag name, second is the tag value e.g. + ".mspabi_attribute 4, 2". */ + input_line_pointer = extract_operand (input_line_pointer, tag_name_s, 32); + input_line_pointer = extract_operand (input_line_pointer, tag_value_s, 32); + tag_name = atoi (tag_name_s); + tag_value = atoi (tag_value_s); + /* If the attribute directive is present, the tag_value should never be set + to 0. */ + if (tag_name == 0 || tag_value == 0) + as_bad (_("bad arguments \"%s\" and/or \"%s\" in %s directive"), + tag_name_s, tag_value_s, (attr_type ? ".gnu_attribute" + : ".mspabi_attribute")); + else if (attr_type == 0) + /* Handle .mspabi_attribute. */ + switch (tag_name) + { + case OFBA_MSPABI_Tag_ISA: + switch (tag_value) + { + case OFBA_MSPABI_Val_ISA_MSP430: + if (target_is_430x ()) + as_bad (_("file was compiled for the 430 ISA but the %s ISA is selected"), + (target_is_430xv2 () ? "430X" : "430Xv2")); + break; + case OFBA_MSPABI_Val_ISA_MSP430X: + if (!target_is_430x ()) + as_bad (_("file was compiled for the 430X ISA but the 430 ISA is selected")); + break; + default: + as_bad (_("unknown MSPABI build attribute value '%d' for OFBA_MSPABI_Tag_ISA(%d) " + "in .mspabi_attribute directive"), tag_value, OFBA_MSPABI_Tag_ISA); + break; + } + break; + case OFBA_MSPABI_Tag_Code_Model: + /* Fall through. */ + case OFBA_MSPABI_Tag_Data_Model: + /* FIXME: Might we want to set the memory model to large if the assembly + file has the large model attribute, but -ml has not been passed? */ + switch (tag_value) + { + case OFBA_MSPABI_Val_Code_Model_SMALL: + if (large_model) + as_bad (_("file was compiled for the small memory model, but the large memory " + "model is selected")); + break; + case OFBA_MSPABI_Val_Code_Model_LARGE: + if (!large_model) + as_bad (_("file was compiled for the large memory model, but the small memory " + "model is selected")); + break; + default: + as_bad (_("unknown MSPABI build attribute value '%d' for %s(%d) " + "in .mspabi_attribute directive"), tag_value, + (tag_name == OFBA_MSPABI_Tag_Code_Model + ? "OFBA_MSPABI_Tag_Code_Model" + : "OFBA_MSPABI_Tag_Data_Model"), + (tag_name == OFBA_MSPABI_Tag_Code_Model + ? OFBA_MSPABI_Tag_Code_Model + : OFBA_MSPABI_Tag_Data_Model)); + break; + } + break; + default: + as_bad (_("unknown MSPABI build attribute tag '%d' in .mspabi_attribute directive"), tag_name); + break; + } + else if (attr_type == 1) + /* Handle .gnu_attribute. */ + switch (tag_name) + { + case Tag_GNU_MSP430_Data_Region: + /* This attribute is only applicable in the large memory model. */ + if (!large_model) + break; + switch (tag_value) + { + case Val_GNU_MSP430_Data_Region_Lower: + if (!lower_data_region_only) + as_bad (_("file was compiled assuming all data will be in the lower memory region, " + "but the upper region is in use")); + break; + case Val_GNU_MSP430_Data_Region_Any: + if (lower_data_region_only) + as_bad (_("file was compiled assuming data could be in the upper memory region, " + "but the lower data region is exclusively in use")); + break; + default: + as_bad (_("unknown GNU build attribute value '%d' for Tag_GNU_MSP430_Data_Region(%d) " + "in .gnu_attribute directive"), tag_value, Tag_GNU_MSP430_Data_Region); + } + } + else + as_bad (_("internal: unexpected argument '%d' to msp430_object_attribute"), attr_type); +} + const pseudo_typeS md_pseudo_table[] = { {"arch", msp430_set_arch, OPTION_MMCU}, @@ -1611,6 +1728,8 @@ const pseudo_typeS md_pseudo_table[] = {"refsym", msp430_refsym, 0}, {"comm", msp430_comm, 0}, {"lcomm", msp430_lcomm, 0}, + {"mspabi_attribute", msp430_object_attribute, 0}, + {"gnu_attribute", msp430_object_attribute, 1}, {NULL, NULL, 0} }; @@ -4919,7 +5038,7 @@ msp430_fix_adjustable (struct fix *fixp ATTRIBUTE_UNUSED) return FALSE; } -/* Set the contents of the .MSP430.attributes section. */ +/* Set the contents of the .MSP430.attributes and .GNU.attributes sections. */ void msp430_md_end (void) @@ -4936,14 +5055,27 @@ msp430_md_end (void) as_warn (_(WARN_NOP_AT_EOF)); } + /* We have already emitted an error if any of the following attributes + disagree with the attributes in the input assembly file. See + msp430_object_attribute. */ bfd_elf_add_proc_attr_int (stdoutput, OFBA_MSPABI_Tag_ISA, - target_is_430x () ? 2 : 1); + target_is_430x () ? OFBA_MSPABI_Val_ISA_MSP430X + : OFBA_MSPABI_Val_ISA_MSP430); bfd_elf_add_proc_attr_int (stdoutput, OFBA_MSPABI_Tag_Code_Model, - large_model ? 2 : 1); + large_model ? OFBA_MSPABI_Val_Code_Model_LARGE + : OFBA_MSPABI_Val_Code_Model_SMALL); bfd_elf_add_proc_attr_int (stdoutput, OFBA_MSPABI_Tag_Data_Model, - large_model ? 2 : 1); + large_model ? OFBA_MSPABI_Val_Code_Model_LARGE + : OFBA_MSPABI_Val_Code_Model_SMALL); + + /* The data region GNU attribute is ignored for the small memory model. */ + if (large_model) + bfd_elf_add_obj_attr_int (stdoutput, OBJ_ATTR_GNU, Tag_GNU_MSP430_Data_Region, + lower_data_region_only + ? Val_GNU_MSP430_Data_Region_Lower + : Val_GNU_MSP430_Data_Region_Any ); } /* Returns FALSE if there is a msp430 specific reason why the diff --git a/gas/doc/as.texi b/gas/doc/as.texi index b4598e86dc..93e80f9a43 100644 --- a/gas/doc/as.texi +++ b/gas/doc/as.texi @@ -7585,6 +7585,23 @@ The vector ABI used by this object file. The value will be: @end itemize @end table +@subsection MSP430 Attributes + +@table @r +@item Tag_GNU_MSP430_Data_Region (4) +The data region used by this object file. The value will be: + +@itemize @bullet +@item +0 for files not using the large memory model. +@item +1 for files which have been compiled with the condition that all +data is in the lower memory region, i.e. below address 0x10000. +@item +2 for files which allow data to be placed in the full 20-bit memory range. +@end itemize +@end table + @node Defining New Object Attributes @section Defining New Object Attributes diff --git a/gas/doc/c-msp430.texi b/gas/doc/c-msp430.texi index dfa435a461..bc7007b2a4 100644 --- a/gas/doc/c-msp430.texi +++ b/gas/doc/c-msp430.texi @@ -322,6 +322,18 @@ exist purely for pulling in object files from archives. Note that this reloc is not sufficient to prevent garbage collection; use a KEEP() directive in the linker file to preserve such objects. +@cindex @code{mspabi_attribute} directive, MSP430 +@item .mspabi_attribute +This directive tells the assembler what the MSPABI build attributes for this +file are. This is used for validating the command line options passed to +the assembler against the options the original source file was compiled with. +The expected format is: +@samp{.mspabi_attribute tag_name, tag_value} +For example, to set the tag @code{OFBA_MSPABI_Tag_ISA} to @code{MSP430X}: +@samp{.mspabi_attribute 4, 2} + +See the @cite{MSP430 EABI, document slaa534} for the details on tag names and +values. @end table @node MSP430 Opcodes diff --git a/gas/testsuite/gas/msp430/attr-430-small-bad.d b/gas/testsuite/gas/msp430/attr-430-small-bad.d new file mode 100644 index 0000000000..302ba57070 --- /dev/null +++ b/gas/testsuite/gas/msp430/attr-430-small-bad.d @@ -0,0 +1,4 @@ +#name: Error when 430 ISA and small memory model object attributes conflict with options +#source: attr-430-small.s +#as: -mdata-region=none -ml +#error_output: attr-430-small-bad.l diff --git a/gas/testsuite/gas/msp430/attr-430-small-bad.l b/gas/testsuite/gas/msp430/attr-430-small-bad.l new file mode 100644 index 0000000000..c339ecfa35 --- /dev/null +++ b/gas/testsuite/gas/msp430/attr-430-small-bad.l @@ -0,0 +1,4 @@ +[^:]*: Assembler messages: +[^:]*:1: Error: file was compiled for the 430 ISA but the 430X ISA is selected +[^:]*:2: Error: file was compiled for the small memory model, but the large memory model is selected +[^:]*:3: Error: file was compiled for the small memory model, but the large memory model is selected diff --git a/gas/testsuite/gas/msp430/attr-430-small-good.d b/gas/testsuite/gas/msp430/attr-430-small-good.d new file mode 100644 index 0000000000..5f3137f947 --- /dev/null +++ b/gas/testsuite/gas/msp430/attr-430-small-good.d @@ -0,0 +1,6 @@ +#name: 430 ISA and small memory model object attributes +#source: attr-430-small.s +#as: -mcpu=msp430 +#objdump: -t + +#pass diff --git a/gas/testsuite/gas/msp430/attr-430-small.s b/gas/testsuite/gas/msp430/attr-430-small.s new file mode 100644 index 0000000000..2bdb1dbf83 --- /dev/null +++ b/gas/testsuite/gas/msp430/attr-430-small.s @@ -0,0 +1,3 @@ +.mspabi_attribute 4, 1 ; OFBA_MSPABI_Tag_ISA == 430 +.mspabi_attribute 6, 1 ; OFBA_MSPABI_Tag_Code_Model == Small +.mspabi_attribute 8, 1 ; OFBA_MSPABI_Tag_Data_Model == Small diff --git a/gas/testsuite/gas/msp430/attr-430x-large-any-bad.d b/gas/testsuite/gas/msp430/attr-430x-large-any-bad.d new file mode 100644 index 0000000000..6793f7cb1c --- /dev/null +++ b/gas/testsuite/gas/msp430/attr-430x-large-any-bad.d @@ -0,0 +1,4 @@ +#name: Error when 430X ISA, large memory model and any data region object attributes conflict with options +#source: attr-430x-large-any.s +#as: -mcpu=msp430 -ml +#error_output: attr-430x-large-any-bad.l diff --git a/gas/testsuite/gas/msp430/attr-430x-large-any-bad.l b/gas/testsuite/gas/msp430/attr-430x-large-any-bad.l new file mode 100644 index 0000000000..3c049a23f8 --- /dev/null +++ b/gas/testsuite/gas/msp430/attr-430x-large-any-bad.l @@ -0,0 +1,4 @@ +[^:]*: Assembler messages: +[^:]*:1: Error: file was compiled for the 430X ISA but the 430 ISA is selected +[^:]*:4: Error: file was compiled assuming data could be in the upper memory region, but the lower data region is exclusively in use + diff --git a/gas/testsuite/gas/msp430/attr-430x-large-any-good.d b/gas/testsuite/gas/msp430/attr-430x-large-any-good.d new file mode 100644 index 0000000000..603aab11b5 --- /dev/null +++ b/gas/testsuite/gas/msp430/attr-430x-large-any-good.d @@ -0,0 +1,6 @@ +#name: 430X ISA, large memory model and any data region object attributes +#source: attr-430x-large-any.s +#as: -ml -mdata-region=none +#objdump: -t + +#pass diff --git a/gas/testsuite/gas/msp430/attr-430x-large-any.s b/gas/testsuite/gas/msp430/attr-430x-large-any.s new file mode 100644 index 0000000000..593c1710a1 --- /dev/null +++ b/gas/testsuite/gas/msp430/attr-430x-large-any.s @@ -0,0 +1,4 @@ +.mspabi_attribute 4, 2 ; OFBA_MSPABI_Tag_ISA == 430x +.mspabi_attribute 6, 2 ; OFBA_MSPABI_Tag_Code_Model == Large +.mspabi_attribute 8, 2 ; OFBA_MSPABI_Tag_Data_Model == Large +.gnu_attribute 4, 2 ; Tag_GNU_MSP430_Data_Region == Any diff --git a/gas/testsuite/gas/msp430/attr-430x-large-lower-bad.d b/gas/testsuite/gas/msp430/attr-430x-large-lower-bad.d new file mode 100644 index 0000000000..fb7e5cad7d --- /dev/null +++ b/gas/testsuite/gas/msp430/attr-430x-large-lower-bad.d @@ -0,0 +1,4 @@ +#name: Error when 430X ISA, large memory model and lower data region object attributes conflict with options +#source: attr-430x-large-lower.s +#as: -mdata-region=none -mcpu=msp430 -ml +#error_output: attr-430x-large-lower-bad.l diff --git a/gas/testsuite/gas/msp430/attr-430x-large-lower-bad.l b/gas/testsuite/gas/msp430/attr-430x-large-lower-bad.l new file mode 100644 index 0000000000..a21b640915 --- /dev/null +++ b/gas/testsuite/gas/msp430/attr-430x-large-lower-bad.l @@ -0,0 +1,3 @@ +[^:]*: Assembler messages: +[^:]*:1: Error: file was compiled for the 430X ISA but the 430 ISA is selected +[^:]*:4: Error: file was compiled assuming all data will be in the lower memory region, but the upper region is in use diff --git a/gas/testsuite/gas/msp430/attr-430x-large-lower-good.d b/gas/testsuite/gas/msp430/attr-430x-large-lower-good.d new file mode 100644 index 0000000000..c4a395cd80 --- /dev/null +++ b/gas/testsuite/gas/msp430/attr-430x-large-lower-good.d @@ -0,0 +1,6 @@ +#name: 430X ISA, large memory model and lower data region object attributes +#source: attr-430x-large-lower.s +#as: -ml +#objdump: -t + +#pass diff --git a/gas/testsuite/gas/msp430/attr-430x-large-lower.s b/gas/testsuite/gas/msp430/attr-430x-large-lower.s new file mode 100644 index 0000000000..4ab0b5d13a --- /dev/null +++ b/gas/testsuite/gas/msp430/attr-430x-large-lower.s @@ -0,0 +1,4 @@ +.mspabi_attribute 4, 2 ; OFBA_MSPABI_Tag_ISA == 430x +.mspabi_attribute 6, 2 ; OFBA_MSPABI_Tag_Code_Model == Large +.mspabi_attribute 8, 2 ; OFBA_MSPABI_Tag_Data_Model == Large +.gnu_attribute 4, 1 ; Tag_GNU_MSP430_Data_Region == Lower diff --git a/gas/testsuite/gas/msp430/msp430.exp b/gas/testsuite/gas/msp430/msp430.exp index 9c7a1975f9..ef3164da2b 100644 --- a/gas/testsuite/gas/msp430/msp430.exp +++ b/gas/testsuite/gas/msp430/msp430.exp @@ -46,4 +46,10 @@ if [expr [istarget "msp430-*-*"]] then { run_dump_test "preinit-array" run_dump_test "init-array" run_dump_test "fini-array" + run_dump_test "attr-430-small-bad" + run_dump_test "attr-430-small-good" + run_dump_test "attr-430x-large-lower-bad" + run_dump_test "attr-430x-large-lower-good" + run_dump_test "attr-430x-large-any-bad" + run_dump_test "attr-430x-large-any-good" } diff --git a/include/elf/msp430.h b/include/elf/msp430.h index e060804b66..3319b961d8 100644 --- a/include/elf/msp430.h +++ b/include/elf/msp430.h @@ -58,6 +58,48 @@ #define OFBA_MSPABI_Tag_ISA 4 #define OFBA_MSPABI_Tag_Code_Model 6 #define OFBA_MSPABI_Tag_Data_Model 8 +#define OFBA_MSPABI_Tag_enum_size 10 /* Unused by GNU. */ + +/* GNU Object attribute tags. */ +enum +{ + /* 0-3 are generic. */ + + /* Define a GNU attribute for keeping track of whether the compiler has + generated code assuming that the upper region could be in use. + Added by the assembler based on the -mdata-region option. + FIXME: GCC should be generating the attribute. + This tag is ignored unless the large memory model is in use. */ + Tag_GNU_MSP430_Data_Region = 4, +}; + +/* Object attribute values. */ +enum +{ + /* Values defined for OFBA_MSPABI_Tag_ISA. */ + OFBA_MSPABI_Val_ISA_NONE = 0, + OFBA_MSPABI_Val_ISA_MSP430 = 1, + OFBA_MSPABI_Val_ISA_MSP430X = 2, + + /* Values defined for OFBA_MSPABI_Tag_Code_Model. */ + OFBA_MSPABI_Val_Code_Model_NONE = 0, + OFBA_MSPABI_Val_Code_Model_SMALL = 1, + OFBA_MSPABI_Val_Code_Model_LARGE = 2, + + /* Values defined for OFBA_MSPABI_Tag_Data_Model. */ + OFBA_MSPABI_Val_Data_Model_NONE = 0, + OFBA_MSPABI_Val_Data_Model_SMALL = 1, + OFBA_MSPABI_Val_Data_Model_LARGE = 2, + OFBA_MSPABI_Val_Data_Model_RESTRICTED = 3, /* Unused by GNU. */ + + /* Values defined for Tag_GNU_MSP430_Data_Region. */ + Val_GNU_MSP430_Data_Region_NONE = 0, + /* The default data region. Assumes all data is below address 0x10000. */ + Val_GNU_MSP430_Data_Region_Lower = 1, + /* Set if -mdata-region={none,upper,either}. Assumes + data could be placed at or above address 0x10000. */ + Val_GNU_MSP430_Data_Region_Any = 2, +}; /* Relocations. */ START_RELOC_NUMBERS (elf_msp430_reloc_type) diff --git a/ld/testsuite/ld-msp430-elf/attr-gnu-main.s b/ld/testsuite/ld-msp430-elf/attr-gnu-main.s new file mode 100644 index 0000000000..e07a58ca70 --- /dev/null +++ b/ld/testsuite/ld-msp430-elf/attr-gnu-main.s @@ -0,0 +1,8 @@ +.text + .balign 2 + .global main + .type main, @function +main: +.L2: + BRA #.L2 + .size main, .-main diff --git a/ld/testsuite/ld-msp430-elf/attr-gnu-obj.s b/ld/testsuite/ld-msp430-elf/attr-gnu-obj.s new file mode 100644 index 0000000000..d256e409c2 --- /dev/null +++ b/ld/testsuite/ld-msp430-elf/attr-gnu-obj.s @@ -0,0 +1,2 @@ +.text + .comm a,2,2 diff --git a/ld/testsuite/ld-msp430-elf/attr-gnu-region-lower-upper.d b/ld/testsuite/ld-msp430-elf/attr-gnu-region-lower-upper.d new file mode 100644 index 0000000000..70f8e35004 --- /dev/null +++ b/ld/testsuite/ld-msp430-elf/attr-gnu-region-lower-upper.d @@ -0,0 +1,6 @@ +#name: prevent merging of lower and upper attributes +#source: attr-gnu-main.s -ml -mdata-region=lower +#source: attr-gnu-obj.s -ml -mdata-region=upper +#ld: +#error: .*can use the upper region for data, but.*assumes data is exclusively in lower memory.* +#error: .*failed to merge target specific data of file.* diff --git a/ld/testsuite/ld-msp430-elf/attr-gnu-region-lower.d b/ld/testsuite/ld-msp430-elf/attr-gnu-region-lower.d new file mode 100644 index 0000000000..57345aadeb --- /dev/null +++ b/ld/testsuite/ld-msp430-elf/attr-gnu-region-lower.d @@ -0,0 +1,12 @@ +#source: attr-gnu-main.s -ml -mdata-region=lower +#source: attr-gnu-obj.s -ml +#readelf: -A + +Attribute Section: mspabi +File Attributes + Tag_ISA: MSP430X + Tag_Code_Model: Large + Tag_Data_Model: Large +Attribute Section: gnu +File Attributes + Tag_GNU_MSP430_Data_Region: Lower Region Only diff --git a/ld/testsuite/ld-msp430-elf/attr-gnu-region-upper.d b/ld/testsuite/ld-msp430-elf/attr-gnu-region-upper.d new file mode 100644 index 0000000000..225968dc44 --- /dev/null +++ b/ld/testsuite/ld-msp430-elf/attr-gnu-region-upper.d @@ -0,0 +1,13 @@ +#source: attr-gnu-main.s -ml -mdata-region=upper +#source: attr-gnu-obj.s -ml -mdata-region=none +#ld: --data-region=either +#readelf: -A + +Attribute Section: mspabi +File Attributes + Tag_ISA: MSP430X + Tag_Code_Model: Large + Tag_Data_Model: Large +Attribute Section: gnu +File Attributes + Tag_GNU_MSP430_Data_Region: Any Region diff --git a/ld/testsuite/ld-msp430-elf/msp430-elf.exp b/ld/testsuite/ld-msp430-elf/msp430-elf.exp index b6f3151c80..08620b57ff 100644 --- a/ld/testsuite/ld-msp430-elf/msp430-elf.exp +++ b/ld/testsuite/ld-msp430-elf/msp430-elf.exp @@ -46,6 +46,7 @@ if { ![istarget "msp430*elf*"] } { # treated as a sign of an error and FAILs the test. # # + set msp430regionprefixtests { {"Move main() to .upper.text" "-T msp430.ld --code-region=upper" "" "" {main-with-text-rodata.s} {{objdump -d main-text-upper.d}} "main-upper"} @@ -162,7 +163,7 @@ set msp430warntests { {{ld warn-no-lower-data.r}} "warn-no-lower-data"} } -# Don't run section shuffle tests when msp430 ISA is selected +# Don't run further tests when msp430 ISA is selected if {[string match "*-mcpu=msp430 *" [board_info [target_info name] multilib_flags]] || [string match "*-mcpu=msp430" [board_info [target_info name] multilib_flags]]} { return @@ -173,3 +174,12 @@ run_ld_link_tests $msp430eithershuffletests run_ld_link_tests $msp430warntests run_dump_test valid-map + +# Don't run data region tests if a data region is specified +if {[string match "*-mdata-region*" [board_info [target_info name] multilib_flags]]} { + return +} +# GNU object attribute dump tests +run_dump_test attr-gnu-region-lower +run_dump_test attr-gnu-region-upper +run_dump_test attr-gnu-region-lower-upper -- 2.17.1