diff options
Diffstat (limited to 'gas/config/tc-msp430.c')
-rw-r--r-- | gas/config/tc-msp430.c | 146 |
1 files changed, 142 insertions, 4 deletions
diff --git a/gas/config/tc-msp430.c b/gas/config/tc-msp430.c index 56d2024..41413f0 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,120 @@ 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 +1734,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 +5044,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 +5061,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 |