From patchwork Wed Sep 11 10:25:58 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jozef Lawrynowicz X-Patchwork-Id: 1160899 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-508829-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=mittosystems.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="w3YjOYjz"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=mittosystems.com header.i=@mittosystems.com header.b="jEbORtON"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46Syk42pXXz9s00 for ; Wed, 11 Sep 2019 20:26:34 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=lHxn8/lKAeRyn8YwdP8u/PWjPNLfmQ5Gx+KH6y0Eq5gjYSomaNIAR 0YXmv6w6+G8eDHhNFI3n/KrEuOZsXLni4JcjqdUrfrM/tvQaJzzx2AgyoMWCqKRX kKKjwZ7uq6vHcp6HIe/n8x5s4v5IiF6NmK2MPdzwLWIumKPKYoLZX8= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=UBvs2FaXZUUGm9582D2Cacg5ZGE=; b=w3YjOYjzAjcpJVx4jJGS 3/eWbphbP6r7VmuGQf444632vW258RlKliVln00YKx0kEx4uF/VDjM0J3OuNI9F5 bdUXhvHIPxg/UCvf3cNz8yYPJBMmAeicvPP05sQIuY0OSYpuf+RckHpEutPxCLFi 4QNQRq4g/ckvCvx+pIdN9Pg= Received: (qmail 8036 invoked by alias); 11 Sep 2019 10:26:20 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 8027 invoked by uid 89); 11 Sep 2019 10:26:19 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-25.4 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_STOCKGEN, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=bis, capability X-HELO: mail-wr1-f41.google.com Received: from mail-wr1-f41.google.com (HELO mail-wr1-f41.google.com) (209.85.221.41) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 11 Sep 2019 10:26:06 +0000 Received: by mail-wr1-f41.google.com with SMTP id d17so11115358wrq.13 for ; Wed, 11 Sep 2019 03:26:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mittosystems.com; s=google; h=date:from:to:subject:message-id:mime-version; bh=6y/PDrkwSATRSLLBElOzb+HWD+hgxguHba5NPjpJ1jQ=; b=jEbORtON1mmWCatLreq+YBYQsG8eO6vds8E7UzzH3q/PYZ7hedS7Aps/2b+4rBeyMp fbYOJxFwJbd0ATXbn5sGWOegvZz8DRw5wAcExOWe/GA+czKs0pQgAgWfytCYo4gzhpB3 rwCQ2kEBtrR6HWPDTlliYq+od/Bn+jEt+7xDyTci9zii57FXH15IyPLXFCG4xlOTAWDJ cyHTYFuzDU1GjwbKc03nJNrrHzgQEKUezfILOHkk8820E5Okj0IWeZJz0QMwff/eo5nU dYj0uXoVPrg1sjznH2KFKHDFpebrtN7eXRwLa1TzA4xqPXrWuT8VMISiFQZI3qrZ+tnP Cm1Q== Received: from jozef-kubuntu ([2a01:4b00:87fd:900:647e:5942:9794:a6ce]) by smtp.gmail.com with ESMTPSA id l1sm24926843wrb.1.2019.09.11.03.26.01 for (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 11 Sep 2019 03:26:02 -0700 (PDT) Date: Wed, 11 Sep 2019 11:25:58 +0100 From: Jozef Lawrynowicz To: "gcc-patches@gcc.gnu.org" Subject: [PATCH][MSP430] Don't generate 430X insns when handling data in the lower memory region Message-ID: <20190911112558.20a77395@jozef-kubuntu> MIME-Version: 1.0 X-IsSubscribed: yes The MSP430 target has a "430X" extension which increases the directly addressable memory range from 64KB (16-bit) to 1MB (20-bit). This 1MB memory range is split into a "lower" region (below address 0x10000) and "upper" region (at or above address 0x10000). When data in the upper region is addressed, 430 instructions cannot be used, as their 16-bit capability will be exceeded; 430X instructions must be used instead. Most 430X instructions require an additional word of op-code, and also require more cycles to execute compared to their 430 equivalent. Currently, when the large memory model is specified (-mlarge), 430X instructions will always be used when addressing a symbol_ref using the absolute addressing mode e.g. MOVX #1, &foo. The attached patch modifies code generation so that 430X instructions will only be used when the symbol being addressed will not be placed in the lower memory region. This is determined by checking if -mdata-region=lower (the new default) is passed, or if the "lower" attribute is set on the variable. Since code will be generated to assume all variables are in the lower memory region with -mdata-region=lower, object files built with this option cannot be linked with objects files built with other -mdata-region= values. To facilitate the checking of this, a patch for binutils (to be submitted after this is accepted) is also attached. The compiler will now generate assembler directives indicating the ISA, memory model and data region the source file was compiled with. The assembler will check these directives match the options it has been invoked with, and then add the attribute to the object file. Successfully regtested for msp430-elf in the small and large memory model, and with -mdata-region=upper. Testing with -mdata-region=upper should expose any cases where a 430X instruction is not used where it is required, since all data is forced into the upper region so a lack of 430X insn would cause a relocation overflow. In fact the attached patch fixes some relocation overflows by adding missing "%X" operand selectors to some insns. One relocation overflow remains (pr65077.c), but that is a separate binutils issue. Ok for trunk? 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