From patchwork Fri Jul 28 16:24:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Jose E. Marchesi" X-Patchwork-Id: 127730 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:918b:0:b0:3e4:2afc:c1 with SMTP id s11csp548961vqg; Fri, 28 Jul 2023 09:25:16 -0700 (PDT) X-Google-Smtp-Source: APBJJlFONaT+05fyx2pjbkLx82IlptJTYr3fxJsfEcO6emitd2ZqPMzCYhUFAud1zuX3Woj92BJA X-Received: by 2002:a05:6512:3495:b0:4fe:a2e:890c with SMTP id v21-20020a056512349500b004fe0a2e890cmr1889849lfr.49.1690561516393; Fri, 28 Jul 2023 09:25:16 -0700 (PDT) Received: from server2.sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id b14-20020aa7df8e000000b0052221fb7d74si3069885edy.77.2023.07.28.09.25.15 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Jul 2023 09:25:16 -0700 (PDT) Received-SPF: pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; dkim=pass header.i=@sourceware.org header.s=default header.b=RjpvHPRk; arc=fail (signature failed); spf=pass (google.com: domain of binutils-bounces+ouuuleilei=gmail.com@sourceware.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="binutils-bounces+ouuuleilei=gmail.com@sourceware.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 2A1583854C41 for ; Fri, 28 Jul 2023 16:25:10 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2A1583854C41 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1690561510; bh=lhQYZpLTyBV+TcquRQMtZ8tADZ7eUcmkQHBYyrEz/kQ=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=RjpvHPRkVAlp0nY+R5ObKejPuLSTpwgsA1J1jqdCvAD86/RG1ZpV0rTtYyD9POqnH 12dtk6ixDqyEdxhIK3mqLuxNKyZRP2FxzPY3B8HJMUy+6HV7zAspJJIqxjcr781n35 S2Ur9ImVuy2b/RJ8FVJQvi70BnZ7Z1yPUVx2nfQY= X-Original-To: binutils@sourceware.org Delivered-To: binutils@sourceware.org Received: from mx0a-00069f02.pphosted.com (mx0a-00069f02.pphosted.com [205.220.165.32]) by sourceware.org (Postfix) with ESMTPS id 30F153858CDA for ; Fri, 28 Jul 2023 16:24:55 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 30F153858CDA Received: from pps.filterd (m0246617.ppops.net [127.0.0.1]) by mx0b-00069f02.pphosted.com (8.17.1.19/8.17.1.19) with ESMTP id 36SF50kA029604 for ; Fri, 28 Jul 2023 16:24:53 GMT Received: from iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com (iadpaimrmta03.appoci.oracle.com [130.35.103.27]) by mx0b-00069f02.pphosted.com (PPS) with ESMTPS id 3s07nuv8j5-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Fri, 28 Jul 2023 16:24:51 +0000 Received: from pps.filterd (iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com [127.0.0.1]) by iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com (8.17.1.19/8.17.1.19) with ESMTP id 36SFK6jk011797 for ; Fri, 28 Jul 2023 16:24:50 GMT Received: from nam11-dm6-obe.outbound.protection.outlook.com (mail-dm6nam11lp2176.outbound.protection.outlook.com [104.47.57.176]) by iadpaimrmta03.imrmtpd1.prodappiadaev1.oraclevcn.com (PPS) with ESMTPS id 3s05j9h7y0-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) for ; Fri, 28 Jul 2023 16:24:50 +0000 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=aBHfhyn5UZfbhwWA4VKjC1jqXanIF+Eghr/0PtASoDSPScnWVuVsW2PmUUObhNjrn/or3eUmL0Io6wsWExUdfIqGtAPOj3rpVlOZrTBG1FmdcureqbHXSVkl8ToDwXMusa4b/1KAVtCRxCAxd82xZPuE9oZWmHAXhzTq8gOnxkG7jKWHl/EZqII/f/iwLCvPTskYEmkpyY2QAiW0VRYC3RgpgLJeI0ZleYqfcEFtjoktCY4WUMExBhHvLWkfQSRL+s+LAcdyzXS+i8q5nkfD6fUCU9WI97EYkPLyN4HfEz9zBe27royRhfFR8aw/F9CpOD7L4MWGA9TT/m6Omrw0Mg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=lhQYZpLTyBV+TcquRQMtZ8tADZ7eUcmkQHBYyrEz/kQ=; b=l9xDnspWKIhfNekmEI7oncOWUwouqm6+CZMVXUNkDpd3mZfI68eB/0zGc7Q3N5inW0Q9T8n+lZblDUhPdmIJdLwsLNfvgwBua9n3VBX95jZRNulgBTqKS7JdIANFxmC1Ge3z1dhnS3ry2KV4UDd3qj0EGhuNmNPqfEWIQbkbBiEFOERSRsC8YBCSZYEzWbvH16+Sbs/juTdvJMUO9A3zjv95F5suvIFGxF/RJHpG7f94AqNXLvewqi9vzrQRT7hdPGQVzjXCC9aKBOgcstw6kMyaUFwfQxyvTY5PtXGiXddMATCPY9YATdF+YDepBhbAzyHKEkc3VDByi+lB8yhRCg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=oracle.com; dmarc=pass action=none header.from=oracle.com; dkim=pass header.d=oracle.com; arc=none Received: from BYAPR10MB2888.namprd10.prod.outlook.com (2603:10b6:a03:88::32) by CH0PR10MB5225.namprd10.prod.outlook.com (2603:10b6:610:c5::15) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6631.29; Fri, 28 Jul 2023 16:24:47 +0000 Received: from BYAPR10MB2888.namprd10.prod.outlook.com ([fe80::d5ed:aedb:b99f:6f19]) by BYAPR10MB2888.namprd10.prod.outlook.com ([fe80::d5ed:aedb:b99f:6f19%3]) with mapi id 15.20.6631.026; Fri, 28 Jul 2023 16:24:47 +0000 To: binutils@sourceware.org Subject: [COMMITTED] bpf: gas: support relaxation of V4 jump instructions Date: Fri, 28 Jul 2023 18:24:40 +0200 Message-Id: <20230728162440.32565-1-jose.marchesi@oracle.com> X-Mailer: git-send-email 2.30.2 X-ClientProxiedBy: AS4P191CA0042.EURP191.PROD.OUTLOOK.COM (2603:10a6:20b:657::19) To BYAPR10MB2888.namprd10.prod.outlook.com (2603:10b6:a03:88::32) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: BYAPR10MB2888:EE_|CH0PR10MB5225:EE_ X-MS-Office365-Filtering-Correlation-Id: 6dc29b0e-de65-4e01-64cd-08db8f8728bf X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: 2ctFl8vsG1OEEghwNOe45vQO9hObEzrtKlRhXBc9JsI338/w8hF9c9YzI+9GtecfxrL89daSyqM4YN88HTfIPHtCdyGu6vSXPniQHre9ho+jiHih9w+tWhHfVHvwyj4e3GSM4G7lH6YrZjg+BxR09jYRNTBFcNxUsnoCDGeG8PQOEEUQ8wKT0gkL7hsTzZ0k9gS65FCT4/KCIP/h+Eau7sWcCXk8zYhABtZdX7S+REOObmblRa5q9vlYZ/a1FYDry35rNqzObfIFeaCydV/tEOdNgCThtG6FUucIrIrKAMK0OzfmbNTkL6kGD0Y9/7v/E/0TQ+5uTFXToNEhMzxkilq5DKNVmWZeas49IAfveafRvoISmEy4hvlFlf5gUyXGuCgb4ZLRFA9YJUsXzL5Kn9J/mhA+NBUjN2ETqjg9cL1TzDEl9J8NDVUDp1ctgg8/fDL1qM0SrL21l86LnjkCE6j0Zw8lna+NAGmSHJny0dxuQbLGL+nI6Ri7xoCONqBNx86o9lAExdcUXxClAw4j8qcXL7YmEF56Ug3wJ+tp+1nKivp3R6osuRM2KfGYpgPMQR0l7/vGmD8GvYTEIJSmEqJuUJQZyJCqtg1KtAk2gSc= X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:BYAPR10MB2888.namprd10.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230028)(376002)(396003)(366004)(39860400002)(136003)(346002)(451199021)(6486002)(6666004)(83380400001)(26005)(6506007)(6512007)(1076003)(478600001)(6916009)(66946007)(66476007)(66556008)(186003)(2616005)(38100700002)(2906002)(30864003)(8936002)(8676002)(5660300002)(316002)(41300700001)(86362001)(40140700001)(36756003)(21314003)(579004); DIR:OUT; SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: wy2UplXS+qaAQLgcJhGK8pQQNnjjvSsqIFfiK1GCP0Rc4TXfHIf+Au9WOSKXdJpTObquMTqpMXMqMTd2gD25Tshkx+/KhH65/zbE9i4FGoC7z5mXg0oiiWxFklgiDguUJym8sWc4TYdmELnawoBnLVmedKAuYsd+t3Y02pbOFegVDFU/ABWAapbdykYGmtp3I505BepGLQYL6SIa06JcqKGVYkBlRkyCwN4K3r7J9g4UdEuUPjqtHNnrT9jmA7ahlT3GRuBNJWqka11osi4J5wxnZc58KHCtSespVs0wU09Y1id07YG5MnOow0EXGQLi7qUSUL99pBVAPevzEyKIhM3JS8EPpc0f/9OitnS5NgTG/VVmfqlhnU6WWwDGGQ6qwD2QhW4KSWcivK4UgzNUadR0trj0925KOc94+N4SqWMZ898yXcVsjUZeW1La1Z2nG+MNQ94jYP6P/NnSKdcq+/i2fuCeVESnM7akiUQ1P9wk25jVtoxVHdyZUAA5RmXOZ/qXdxSgwLW9VoYBR+e0zVS/JiY/qjfQ934ifS6z5zyF2ecdiJJsh06JaU9sJJ21AsQ8425Y9rsHFl3LXoJmf+phDITIx4Tezi4bwtM2DTk+fEWuA4nJOasrOFjmiEqQ8Ie5foru27jqISngehJfFN4/lgQyKZMq7Y8vFVDr//QBBJTL3E9iPTwK/yj97r8H7R505kVht0OcTO3o+ofjnIgcpec0qAOgAt/qiIpYqDabkOWC4NDyqrvejxrzqcmPi5Fqmw8da6ivp65geBzddhZ2k/bfir0YELWVSVi7WMZdaAdDBVXmH2epAHzTiiu3dvIAjGArQgTjtLa1f7pp2q1NU/RimFmGAMAGgpe/aGpMoof9ZqQn0fwWbaJv/ar9vlvg0x7tHeIkjAw03rvEmRTFfBbH0N3jKawR/B7DEvz2hgqhFrVtg4vp2RmjMRBgxWaCl9eeYhip3kZnjmEPjO8W7iCCr8NU+H1uZcjyFTsuUCvEwIuzdQsAVARDxpW81qng+jZ9ygy5q9DAop/rw9SOy8y/DKRr/kKUQpXW+HCQtJyu622kLMjfxYkaORG7Q9gW7rDdf/yoFCEeBbVNhgyGkPoCr0brMmqCYPbWji3uvDNIFoc9KvswPZy/HEXaNe02P0ktkrYjBRvhzesPXhDZfbpiwyZMDqE+pTiSpRIS2OMxk9S5jg883TmbD0YdMIEIrsXSQBcbZPM06EurG0aJ+QGOh5PsTTxsIp7wkn9Ea6bk49ti1NVtUCjoK51qVxRGkQZrzVrWL50jUzuKY9tbO79BOrfEtW4Np3e1UQTHTO3qKJBCpL9Eg+2MU2CXNuJspMAjKLBJpda8cYxTdhdOgC5bcdZbgdGYR+WEcRJAgGRpxF1i90pyLu3NfTa/YPk+5IrIXC1M6fAwj2v2bFmMOUF7SZlU85OR+iR/WrBYwO7FpehuafXggC5euwXZrH2Ihl4iOvQUHFb9a8WTIirATm5RRjvxbzQdoMA9qCtlIrJhBfWaUYl6TSyyH4WRC+Oe2cQyMjpjEo8krfqULNwIVjL7uTuZpbdkazmvyyt6t5TE1nvzyhfuRHmnNstVWrDjySJ/K9x52b5NE9+WPg== X-MS-Exchange-AntiSpam-ExternalHop-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-ExternalHop-MessageData-0: giPlSvsrS+ATu63w07w+Tx37aP9B5uxv/U10AbjS8Vsftm4sSs9op+DbafYLXvrr3c9qrzKreoXBbQ1yQwXEvOHVPKeNk4VvGigf6vpBPyiAfLdrq4A7oER6Y2bl7nUZpZdYyGOUc3lUx3DOsTkTTGNs/gAQkPqKIEZUUFuITYjE0OYytg4doW66Fc0DKv9p5c8qbnFQZKO/h/vtgIwxCU0caX7vbnMeSwQkimcpZwnxpHk3s7cwZpZ016+Ft+VaywALqhqayhXMnMCFpvbV1x9s69fo8GsPELlVusIFP6P6R2spJjVcdICAGHsVSPFgmr4KKdbH1fYxCHKvWB2dfNVvGLIABhIGfHHL/a9P9GG/J29RLv2TE9JkFq3vUndEEtZX0XDX6HJ8++9s+m0w+ix17c3OROA+pnEoKPG0xvhP+N9nazOa6aY8gzkcjQSMvi2R1wvMVpiB3wFTcSnU+oDWjv3/wd1uzrOVb8QFgk8q2LCE9hkTmBiCDo4I0E5l4yoJ+OZn7ohq6DAcvjNErWGK4xGGERifXBh1hbpFAX+oJRWylMLp1p79AGiD/YRJQPnLliulAGMiBWnQadhwnDg5ukfMOGEtMrvzxkLa4dJ0PKlDGzQnU+lPDZalkF34eSbQWRELXjN3kOKuDDgYTIt18gcsz89Vp99xqJuaNn44sAgaKZFtNFeaf6gZI2paWQLMrGacaMbIYL03MaoZ/Em83UYLF4Ly1ec89my8Y286EtSiYuNu1jmOGtwDZtOZ X-OriginatorOrg: oracle.com X-MS-Exchange-CrossTenant-Network-Message-Id: 6dc29b0e-de65-4e01-64cd-08db8f8728bf X-MS-Exchange-CrossTenant-AuthSource: BYAPR10MB2888.namprd10.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 28 Jul 2023 16:24:47.5061 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 4e2c6054-71cb-48f1-bd6c-3a9705aca71b X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: uFdVOT5ME7dQGTPr0bZisjDf9+d1HBycCBWGV22DQ/816GPcwKEvtMyqlENIsENB1x6on3dZFdvfrd7yZsPIzMc3RYduHNYGwcXAW7+7AiI= X-MS-Exchange-Transport-CrossTenantHeadersStamped: CH0PR10MB5225 X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.254,Aquarius:18.0.957,Hydra:6.0.591,FMLib:17.11.176.26 definitions=2023-07-27_10,2023-07-26_01,2023-05-22_02 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 adultscore=0 phishscore=0 bulkscore=0 malwarescore=0 mlxscore=0 spamscore=0 mlxlogscore=999 suspectscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-2306200000 definitions=main-2307280149 X-Proofpoint-ORIG-GUID: bhwCiUPSmwtziUynmNmZUlqoFDiK1fGv X-Proofpoint-GUID: bhwCiUPSmwtziUynmNmZUlqoFDiK1fGv X-Spam-Status: No, score=-12.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: binutils@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: "Jose E. Marchesi via Binutils" From: "Jose E. Marchesi" Reply-To: "Jose E. Marchesi" Errors-To: binutils-bounces+ouuuleilei=gmail.com@sourceware.org Sender: "Binutils" X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1772682232368795236 X-GMAIL-MSGID: 1772682232368795236 The BPF jump-always instruction (JA), like all other jump instructions in the ISA, get a signed 16-bit displacement target argument denoted in number of 64-bit words minus one. This can sometimes be overflown. The BPF V4 ISA thus introduced support for a jump-always instruction (JAL) that gets a signed 32-bit displacement instead. This patch makes the BPF assembler to perform the following relaxations when the disp16 field gets overflown, unless the option -mno-relax is specified: JA disp16 -> JAL disp32 Jxx disp16 -> Jxx +1; JA +1; JAL disp32 Documentation and tests added. Tested in bpf-unknown-none. gas/ChangeLog: 2023-07-28 Jose E. Marchesi PR gas/30690 * config/tc-bpf.c (struct bpf_insn): Add fields is_relaxable and relaxed_exp. (enum options): Add OPTION_NO_RELAX. (md_longopts): Likewise for -mno-relax. (do_relax): New global. (md_parse_option): Handle OPTION_NO_RELAX. (RELAX_BRANCH_ENCODE): Define. (RELAX_BRANCH_P): Likewise. (RELAX_BRANCH_LENGTH): Likewise. (RELAX_BRANCH_CONST): Likewise. (RELAX_BRANCH_UNCOND): Likewise. (relaxed_branch_length): New function. (md_estimate_size_before_relax): Likewise. (read_insn_word): Likewise. (encode_int16): Likewise. (encode_int32): Likewise. (write_insn_bytes): Likewise. (md_convert_frag): Likewise. (encode_insn): Likewise. (install_insn_fixups): Likewise. (add_fixed_insn): Likewise. (add_relaxed_insn): Likewise. (md_assemble): Move instruction encoding logic to the above new functions. * testsuite/gas/bpf/jump-relax-ja.d: New test. * testsuite/gas/bpf/jump-relax-ja-be.d: Likewise. * testsuite/gas/bpf/jump-relax-ja.s: And corresponding source. * testsuite/gas/bpf/jump-relax-jump.d: New test. * testsuite/gas/bpf/jump-relax-jump-be.d: Likewise. * testsuite/gas/bpf/jump-relax-jump.s: And corresponding source. * testsuite/gas/bpf/bpf.exp: Run new tests. * doc/c-bpf.texi (BPF Options): Document -mno-relax. --- gas/ChangeLog | 36 + gas/config/tc-bpf.c | 1020 +++++++++++++++------- gas/doc/c-bpf.texi | 4 + gas/testsuite/gas/bpf/bpf.exp | 6 + gas/testsuite/gas/bpf/jump-relax-ja-be.d | 19 + gas/testsuite/gas/bpf/jump-relax-ja.d | 19 + gas/testsuite/gas/bpf/jump-relax-ja.s | 20 + gas/testsuite/gas/bpf/jump-relax-jump.d | 25 + gas/testsuite/gas/bpf/jump-relax-jump.s | 17 + 9 files changed, 858 insertions(+), 308 deletions(-) create mode 100644 gas/testsuite/gas/bpf/jump-relax-ja-be.d create mode 100644 gas/testsuite/gas/bpf/jump-relax-ja.d create mode 100644 gas/testsuite/gas/bpf/jump-relax-ja.s create mode 100644 gas/testsuite/gas/bpf/jump-relax-jump.d create mode 100644 gas/testsuite/gas/bpf/jump-relax-jump.s diff --git a/gas/ChangeLog b/gas/ChangeLog index 147c20c460d..1f3735d70af 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,39 @@ +2023-07-28 Jose E. Marchesi + + PR gas/30690 + * config/tc-bpf.c (struct bpf_insn): Add fields is_relaxable and + relaxed_exp. + (enum options): Add OPTION_NO_RELAX. + (md_longopts): Likewise for -mno-relax. + (do_relax): New global. + (md_parse_option): Handle OPTION_NO_RELAX. + (RELAX_BRANCH_ENCODE): Define. + (RELAX_BRANCH_P): Likewise. + (RELAX_BRANCH_LENGTH): Likewise. + (RELAX_BRANCH_CONST): Likewise. + (RELAX_BRANCH_UNCOND): Likewise. + (relaxed_branch_length): New function. + (md_estimate_size_before_relax): Likewise. + (read_insn_word): Likewise. + (encode_int16): Likewise. + (encode_int32): Likewise. + (write_insn_bytes): Likewise. + (md_convert_frag): Likewise. + (encode_insn): Likewise. + (install_insn_fixups): Likewise. + (add_fixed_insn): Likewise. + (add_relaxed_insn): Likewise. + (md_assemble): Move instruction encoding logic to the above + new functions. + * testsuite/gas/bpf/jump-relax-ja.d: New test. + * testsuite/gas/bpf/jump-relax-ja-be.d: Likewise. + * testsuite/gas/bpf/jump-relax-ja.s: And corresponding source. + * testsuite/gas/bpf/jump-relax-jump.d: New test. + * testsuite/gas/bpf/jump-relax-jump-be.d: Likewise. + * testsuite/gas/bpf/jump-relax-jump.s: And corresponding source. + * testsuite/gas/bpf/bpf.exp: Run new tests. + * doc/c-bpf.texi (BPF Options): Document -mno-relax. + 2023-07-26 Jose E. Marchesi * testsuite/gas/bpf/alu.s: Add test for NEGI and NEG32I. diff --git a/gas/config/tc-bpf.c b/gas/config/tc-bpf.c index faa809c05a2..969116bc5ad 100644 --- a/gas/config/tc-bpf.c +++ b/gas/config/tc-bpf.c @@ -51,6 +51,9 @@ struct bpf_insn unsigned int has_disp32 : 1; unsigned int has_imm32 : 1; unsigned int has_imm64 : 1; + + unsigned int is_relaxable : 1; + expressionS *relaxed_exp; }; const char comment_chars[] = ";#"; @@ -120,6 +123,7 @@ enum options OPTION_XBPF, OPTION_DIALECT, OPTION_ISA_SPEC, + OPTION_NO_RELAX, }; struct option md_longopts[] = @@ -129,6 +133,7 @@ struct option md_longopts[] = { "mxbpf", no_argument, NULL, OPTION_XBPF }, { "mdialect", required_argument, NULL, OPTION_DIALECT}, { "misa-spec", required_argument, NULL, OPTION_ISA_SPEC}, + { "mno-relax", no_argument, NULL, OPTION_NO_RELAX}, { NULL, no_argument, NULL, 0 }, }; @@ -144,6 +149,11 @@ const char * md_shortopts = ""; static int set_target_endian = 0; extern int target_big_endian; +/* Whether to relax branch instructions. Default is yes. Can be + changed using the -mno-relax command line option. */ + +static int do_relax = 1; + /* The ISA specification can be one of BPF_V1, BPF_V2, BPF_V3, BPF_V4 or BPF_XPBF. The ISA spec to use can be configured using command-line options. It defaults to the latest BPF spec. */ @@ -203,6 +213,9 @@ md_parse_option (int c, const char * arg) /* This is an alias for -misa-spec=xbpf. */ isa_spec = BPF_XBPF; break; + case OPTION_NO_RELAX: + do_relax = 0; + break; default: return 0; } @@ -337,6 +350,151 @@ tc_gen_reloc (asection *sec ATTRIBUTE_UNUSED, fixS *fixP) } +/* Relaxations supported by this assembler. */ + +#define RELAX_BRANCH_ENCODE(uncond, constant, length) \ + ((relax_substateT) \ + (0xc0000000 \ + | ((uncond) ? 1 : 0) \ + | ((constant) ? 2 : 0) \ + | ((length) << 2))) + +#define RELAX_BRANCH_P(i) (((i) & 0xf0000000) == 0xc0000000) +#define RELAX_BRANCH_LENGTH(i) (((i) >> 2) & 0xff) +#define RELAX_BRANCH_CONST(i) (((i) & 2) != 0) +#define RELAX_BRANCH_UNCOND(i) (((i) & 1) != 0) + + +/* Compute the length of a branch seuqence, and adjust the stored + length accordingly. If FRAG is NULL, the worst-case length is + returned. */ + +static unsigned +relaxed_branch_length (fragS *fragp, asection *sec, int update) +{ + int length, uncond; + + if (!fragp) + return 8 * 3; + + uncond = RELAX_BRANCH_UNCOND (fragp->fr_subtype); + length = RELAX_BRANCH_LENGTH (fragp->fr_subtype); + + if (uncond) + /* Length is the same for both JA and JAL. */ + length = 8; + else + { + if (RELAX_BRANCH_CONST (fragp->fr_subtype)) + { + int64_t val = fragp->fr_offset; + + if (val < -32768 || val > 32767) + length = 8 * 3; + else + length = 8; + } + else if (fragp->fr_symbol != NULL + && S_IS_DEFINED (fragp->fr_symbol) + && !S_IS_WEAK (fragp->fr_symbol) + && sec == S_GET_SEGMENT (fragp->fr_symbol)) + { + offsetT val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset; + + /* Convert to 64-bit words, minus one. */ + val = (val - 8) / 8; + + /* See if it fits in the signed 16-bits field. */ + if (val < -32768 || val > 32767) + length = 8 * 3; + else + length = 8; + } + else + /* Use short version, and let the linker relax instead, if + appropriate and if supported. */ + length = 8; + } + + if (update) + fragp->fr_subtype = RELAX_BRANCH_ENCODE (uncond, + RELAX_BRANCH_CONST (fragp->fr_subtype), + length); + + return length; +} + +/* Estimate the size of a variant frag before relaxing. */ + +int +md_estimate_size_before_relax (fragS *fragp, asection *sec) +{ + return (fragp->fr_var = relaxed_branch_length (fragp, sec, true)); +} + +/* Read a BPF instruction word from BUF. */ + +static uint64_t +read_insn_word (bfd_byte *buf) +{ + return bfd_getb64 (buf); +} + +/* Write the given signed 16-bit value in the given BUFFER using the + target endianness. */ + +static void +encode_int16 (int16_t value, char *buffer) +{ + uint16_t val = value; + + if (target_big_endian) + { + buffer[0] = (val >> 8) & 0xff; + buffer[1] = val & 0xff; + } + else + { + buffer[1] = (val >> 8) & 0xff; + buffer[0] = val & 0xff; + } +} + +/* Write the given signed 32-bit value in the given BUFFER using the + target endianness. */ + +static void +encode_int32 (int32_t value, char *buffer) +{ + uint32_t val = value; + + if (target_big_endian) + { + buffer[0] = (val >> 24) & 0xff; + buffer[1] = (val >> 16) & 0xff; + buffer[2] = (val >> 8) & 0xff; + buffer[3] = val & 0xff; + } + else + { + buffer[3] = (val >> 24) & 0xff; + buffer[2] = (val >> 16) & 0xff; + buffer[1] = (val >> 8) & 0xff; + buffer[0] = value & 0xff; + } +} + +/* Write a BPF instruction to BUF. */ + +static void +write_insn_bytes (bfd_byte *buf, char *bytes) +{ + int i; + + for (i = 0; i < 8; ++i) + md_number_to_chars ((char *) buf + i, (valueT) bytes[i], 1); +} + /* *FRAGP has been relaxed to its final size, and now needs to have the bytes inside it modified to conform to the new size. @@ -347,17 +505,229 @@ tc_gen_reloc (asection *sec ATTRIBUTE_UNUSED, fixS *fixP) void md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, segT sec ATTRIBUTE_UNUSED, - fragS *fragP ATTRIBUTE_UNUSED) + fragS *fragp ATTRIBUTE_UNUSED) { - as_fatal (_("convert_frag called")); -} + bfd_byte *buf = (bfd_byte *) fragp->fr_literal + fragp->fr_fix; + expressionS exp; + fixS *fixp; + bpf_insn_word word; + int disp_is_known = 0; + int64_t disp_to_target = 0; -int -md_estimate_size_before_relax (fragS *fragP ATTRIBUTE_UNUSED, - segT segment ATTRIBUTE_UNUSED) -{ - as_fatal (_("estimate_size_before_relax called")); - return 0; + uint64_t code; + + gas_assert (RELAX_BRANCH_P (fragp->fr_subtype)); + + /* Expression to be used in any resulting relocation in the relaxed + instructions. */ + exp.X_op = O_symbol; + exp.X_add_symbol = fragp->fr_symbol; + exp.X_add_number = fragp->fr_offset; + + gas_assert (fragp->fr_var == RELAX_BRANCH_LENGTH (fragp->fr_subtype)); + + /* Read an instruction word from the instruction to be relaxed, and + get the code. */ + word = read_insn_word (buf); + code = (word >> 60) & 0xf; + + /* Determine whether the 16-bit displacement to the target is known + at this point. */ + if (RELAX_BRANCH_CONST (fragp->fr_subtype)) + { + /* XXX this loses the 32-bit value if the constant was + overflown! */ + disp_to_target = fragp->fr_offset; + disp_is_known = 1; + } + else if (fragp->fr_symbol != NULL + && S_IS_DEFINED (fragp->fr_symbol) + && !S_IS_WEAK (fragp->fr_symbol) + && sec == S_GET_SEGMENT (fragp->fr_symbol)) + { + offsetT val = S_GET_VALUE (fragp->fr_symbol) + fragp->fr_offset; + /* Convert to 64-bit blocks minus one. */ + disp_to_target = (val - 8) / 8; + disp_is_known = 1; + } + + /* Now relax particular jump instructions. */ + if (code == BPF_CODE_JA) + { + /* Unconditional jump. + JA d16 -> JAL d32 */ + + gas_assert (RELAX_BRANCH_UNCOND (fragp->fr_subtype)); + + if (disp_is_known) + { + if (disp_to_target >= -32768 && disp_to_target <= 32767) + { + /* 16-bit disp is known and in range. Install a fixup + for the disp16 if the branch value is not constant. + This will be resolved by the assembler and units + converted. */ + + if (!RELAX_BRANCH_CONST (fragp->fr_subtype)) + { + /* Install fixup for the JA. */ + reloc_howto_type *reloc_howto + = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_DISP16); + if (!reloc_howto) + abort(); + + fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal, + bfd_get_reloc_size (reloc_howto), + &exp, + reloc_howto->pc_relative, + BFD_RELOC_BPF_DISP16); + fixp->fx_file = fragp->fr_file; + fixp->fx_line = fragp->fr_line; + } + } + else + { + /* 16-bit disp is known and not in range. Turn the JA + into a JAL with a 32-bit displacement. */ + char bytes[8]; + + bytes[0] = ((BPF_CLASS_JMP32|BPF_CODE_JA|BPF_SRC_K) >> 56) & 0xff; + bytes[1] = (word >> 48) & 0xff; + bytes[2] = 0; /* disp16 high */ + bytes[3] = 0; /* disp16 lo */ + encode_int32 ((int32_t) disp_to_target, bytes + 4); + + write_insn_bytes (buf, bytes); + } + } + else + { + /* The displacement to the target is not known. Do not + relax. The linker will maybe do it if it chooses to. */ + + reloc_howto_type *reloc_howto = NULL; + + gas_assert (!RELAX_BRANCH_CONST (fragp->fr_subtype)); + + /* Install fixup for the JA. */ + reloc_howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_DISP16); + if (!reloc_howto) + abort (); + + fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal, + bfd_get_reloc_size (reloc_howto), + &exp, + reloc_howto->pc_relative, + BFD_RELOC_BPF_DISP16); + fixp->fx_file = fragp->fr_file; + fixp->fx_line = fragp->fr_line; + } + + buf += 8; + } + else + { + /* Conditional jump. + JXX d16 -> JXX +1; JA +1; JAL d32 */ + + gas_assert (!RELAX_BRANCH_UNCOND (fragp->fr_subtype)); + + if (disp_is_known) + { + if (disp_to_target >= -32768 && disp_to_target <= 32767) + { + /* 16-bit disp is known and in range. Install a fixup + for the disp16 if the branch value is not constant. + This will be resolved by the assembler and units + converted. */ + + if (!RELAX_BRANCH_CONST (fragp->fr_subtype)) + { + /* Install fixup for the branch. */ + reloc_howto_type *reloc_howto + = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_DISP16); + if (!reloc_howto) + abort(); + + fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal, + bfd_get_reloc_size (reloc_howto), + &exp, + reloc_howto->pc_relative, + BFD_RELOC_BPF_DISP16); + fixp->fx_file = fragp->fr_file; + fixp->fx_line = fragp->fr_line; + } + + buf += 8; + } + else + { + /* 16-bit disp is known and not in range. Turn the JXX + into a sequence JXX +1; JA +1; JAL d32. */ + + char bytes[8]; + + /* First, set the 16-bit offset in the current + instruction to 1. */ + + if (target_big_endian) + bfd_putb16 (1, buf + 2); + else + bfd_putl16 (1, buf + 2); + buf += 8; + + /* Then, write the JA + 1 */ + + bytes[0] = 0x05; /* JA */ + bytes[1] = 0x0; + encode_int16 (1, bytes + 2); + bytes[4] = 0x0; + bytes[5] = 0x0; + bytes[6] = 0x0; + bytes[7] = 0x0; + write_insn_bytes (buf, bytes); + buf += 8; + + /* Finally, write the JAL to the target. */ + + bytes[0] = ((BPF_CLASS_JMP32|BPF_CODE_JA|BPF_SRC_K) >> 56) & 0xff; + bytes[1] = 0; + bytes[2] = 0; + bytes[3] = 0; + encode_int32 ((int32_t) disp_to_target, bytes + 4); + write_insn_bytes (buf, bytes); + buf += 8; + } + } + else + { + /* The displacement to the target is not known. Do not + relax. The linker will maybe do it if it chooses to. */ + + reloc_howto_type *reloc_howto = NULL; + + gas_assert (!RELAX_BRANCH_CONST (fragp->fr_subtype)); + + /* Install fixup for the conditional jump. */ + reloc_howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_DISP16); + if (!reloc_howto) + abort (); + + fixp = fix_new_exp (fragp, buf - (bfd_byte *) fragp->fr_literal, + bfd_get_reloc_size (reloc_howto), + &exp, + reloc_howto->pc_relative, + BFD_RELOC_BPF_DISP16); + fixp->fx_file = fragp->fr_file; + fixp->fx_line = fragp->fr_line; + buf += 8; + } + } + + gas_assert (buf == (bfd_byte *)fragp->fr_literal + + fragp->fr_fix + fragp->fr_var); + + fragp->fr_fix += fragp->fr_var; } @@ -460,6 +830,327 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) fixP->fx_addnumber = *valP; } + +/* Instruction writing routines. */ + +/* Encode a BPF instruction in the given buffer BYTES. Non-constant + immediates are encoded as zeroes. */ + +static void +encode_insn (struct bpf_insn *insn, char *bytes) +{ + uint8_t src, dst; + + /* Zero all the bytes. */ + memset (bytes, 0, 16); + + /* First encode the opcodes. Note that we have to handle the + endianness groups of the BPF instructions: 8 | 4 | 4 | 16 | + 32. */ + if (target_big_endian) + { + /* code */ + bytes[0] = (insn->opcode >> 56) & 0xff; + /* regs */ + bytes[1] = (insn->opcode >> 48) & 0xff; + /* offset16 */ + bytes[2] = (insn->opcode >> 40) & 0xff; + bytes[3] = (insn->opcode >> 32) & 0xff; + /* imm32 */ + bytes[4] = (insn->opcode >> 24) & 0xff; + bytes[5] = (insn->opcode >> 16) & 0xff; + bytes[6] = (insn->opcode >> 8) & 0xff; + bytes[7] = insn->opcode & 0xff; + } + else + { + /* code */ + bytes[0] = (insn->opcode >> 56) & 0xff; + /* regs */ + bytes[1] = (((((insn->opcode >> 48) & 0xff) & 0xf) << 4) + | (((insn->opcode >> 48) & 0xff) & 0xf)); + /* offset16 */ + bytes[3] = (insn->opcode >> 40) & 0xff; + bytes[2] = (insn->opcode >> 32) & 0xff; + /* imm32 */ + bytes[7] = (insn->opcode >> 24) & 0xff; + bytes[6] = (insn->opcode >> 16) & 0xff; + bytes[5] = (insn->opcode >> 8) & 0xff; + bytes[4] = insn->opcode & 0xff; + } + + /* Now the registers. */ + src = insn->has_src ? insn->src : 0; + dst = insn->has_dst ? insn->dst : 0; + + if (target_big_endian) + bytes[1] = ((dst & 0xf) << 4) | (src & 0xf); + else + bytes[1] = ((src & 0xf) << 4) | (dst & 0xf); + + /* Now the immediates that are known to be constant. */ + + if (insn->has_imm32 && insn->imm32.X_op == O_constant) + encode_int32 (insn->imm32.X_add_number, bytes + 4); + + if (insn->has_disp32 && insn->disp32.X_op == O_constant) + encode_int32 (insn->disp32.X_add_number, bytes + 4); + + if (insn->has_offset16 && insn->offset16.X_op == O_constant) + encode_int16 (insn->offset16.X_add_number, bytes + 2); + + if (insn->has_disp16 && insn->disp16.X_op == O_constant) + encode_int16 (insn->disp16.X_add_number, bytes + 2); + + if (insn->has_imm64 && insn->imm64.X_op == O_constant) + { + uint64_t imm64 = insn->imm64.X_add_number; + + if (target_big_endian) + { + bytes[12] = (imm64 >> 56) & 0xff; + bytes[13] = (imm64 >> 48) & 0xff; + bytes[14] = (imm64 >> 40) & 0xff; + bytes[15] = (imm64 >> 32) & 0xff; + bytes[4] = (imm64 >> 24) & 0xff; + bytes[5] = (imm64 >> 16) & 0xff; + bytes[6] = (imm64 >> 8) & 0xff; + bytes[7] = imm64 & 0xff; + } + else + { + bytes[15] = (imm64 >> 56) & 0xff; + bytes[14] = (imm64 >> 48) & 0xff; + bytes[13] = (imm64 >> 40) & 0xff; + bytes[12] = (imm64 >> 32) & 0xff; + bytes[7] = (imm64 >> 24) & 0xff; + bytes[6] = (imm64 >> 16) & 0xff; + bytes[5] = (imm64 >> 8) & 0xff; + bytes[4] = imm64 & 0xff; + } + } +} + +/* Install the fixups in INSN in their proper location in the + specified FRAG at the location pointed by WHERE. */ + +static void +install_insn_fixups (struct bpf_insn *insn, fragS *frag, long where) +{ + if (insn->has_imm64) + { + switch (insn->imm64.X_op) + { + case O_symbol: + case O_subtract: + case O_add: + { + reloc_howto_type *reloc_howto; + int size; + + reloc_howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_64); + if (!reloc_howto) + abort (); + + size = bfd_get_reloc_size (reloc_howto); + + fix_new_exp (frag, where, + size, &insn->imm64, reloc_howto->pc_relative, + BFD_RELOC_BPF_64); + break; + } + case O_constant: + /* Already handled in encode_insn. */ + break; + default: + abort (); + } + } + + if (insn->has_imm32) + { + switch (insn->imm32.X_op) + { + case O_symbol: + case O_subtract: + case O_add: + case O_uminus: + { + reloc_howto_type *reloc_howto; + int size; + + reloc_howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32); + if (!reloc_howto) + abort (); + + size = bfd_get_reloc_size (reloc_howto); + + fix_new_exp (frag, where + 4, + size, &insn->imm32, reloc_howto->pc_relative, + BFD_RELOC_32); + break; + } + case O_constant: + /* Already handled in encode_insn. */ + break; + default: + abort (); + } + } + + if (insn->has_disp32) + { + switch (insn->disp32.X_op) + { + case O_symbol: + case O_subtract: + case O_add: + { + reloc_howto_type *reloc_howto; + int size; + unsigned int bfd_reloc + = (insn->id == BPF_INSN_CALL + ? BFD_RELOC_BPF_DISPCALL32 + : BFD_RELOC_BPF_DISP32); + + reloc_howto = bfd_reloc_type_lookup (stdoutput, bfd_reloc); + if (!reloc_howto) + abort (); + + size = bfd_get_reloc_size (reloc_howto); + + fix_new_exp (frag, where, + size, &insn->disp32, reloc_howto->pc_relative, + bfd_reloc); + break; + } + case O_constant: + /* Already handled in encode_insn. */ + break; + default: + abort (); + } + } + + if (insn->has_offset16) + { + switch (insn->offset16.X_op) + { + case O_symbol: + case O_subtract: + case O_add: + { + reloc_howto_type *reloc_howto; + int size; + + /* XXX we really need a new pc-rel offset in bytes + relocation for this. */ + reloc_howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_DISP16); + if (!reloc_howto) + abort (); + + size = bfd_get_reloc_size (reloc_howto); + + fix_new_exp (frag, where, + size, &insn->offset16, reloc_howto->pc_relative, + BFD_RELOC_BPF_DISP16); + break; + } + case O_constant: + /* Already handled in encode_insn. */ + break; + default: + abort (); + } + } + + if (insn->has_disp16) + { + switch (insn->disp16.X_op) + { + case O_symbol: + case O_subtract: + case O_add: + { + reloc_howto_type *reloc_howto; + int size; + + reloc_howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_DISP16); + if (!reloc_howto) + abort (); + + size = bfd_get_reloc_size (reloc_howto); + + fix_new_exp (frag, where, + size, &insn->disp16, reloc_howto->pc_relative, + BFD_RELOC_BPF_DISP16); + break; + } + case O_constant: + /* Already handled in encode_insn. */ + break; + default: + abort (); + } + } + +} + +/* Add a new insn to the list of instructions. */ + +static void +add_fixed_insn (struct bpf_insn *insn) +{ + char *this_frag = frag_more (insn->size); + char bytes[16]; + int i; + + /* First encode the known parts of the instruction, including + opcodes and constant immediates, and write them to the frag. */ + encode_insn (insn, bytes); + for (i = 0; i < insn->size; ++i) + md_number_to_chars (this_frag + i, (valueT) bytes[i], 1); + + /* Now install the instruction fixups. */ + install_insn_fixups (insn, frag_now, + this_frag - frag_now->fr_literal); +} + +/* Add a new relaxable to the list of instructions. */ + +static void +add_relaxed_insn (struct bpf_insn *insn, expressionS *exp) +{ + char bytes[16]; + int i; + char *this_frag; + unsigned worst_case = relaxed_branch_length (NULL, NULL, 0); + unsigned best_case = insn->size; + + /* We only support relaxing branches, for the moment. */ + relax_substateT subtype + = RELAX_BRANCH_ENCODE (insn->id == BPF_INSN_JAR, + exp->X_op == O_constant, + worst_case); + + frag_grow (worst_case); + this_frag = frag_more (0); + + /* First encode the known parts of the instruction, including + opcodes and constant immediates, and write them to the frag. */ + encode_insn (insn, bytes); + for (i = 0; i < insn->size; ++i) + md_number_to_chars (this_frag + i, (valueT) bytes[i], 1); + + /* Note that instruction fixups will be applied once the frag is + relaxed, in md_convert_frag. */ + frag_var (rs_machine_dependent, + worst_case, best_case, + subtype, exp->X_add_symbol, exp->X_add_number /* offset */, + NULL); +} + + /* Parse an operand expression. Returns the first character that is not part of the expression, or NULL in case of parse error. @@ -781,6 +1472,7 @@ md_assemble (char *str ATTRIBUTE_UNUSED) break; } insn.has_disp16 = 1; + insn.is_relaxable = 1; p += 4; } else if (strncmp (p, "%d32", 4) == 0) @@ -865,307 +1557,19 @@ md_assemble (char *str ATTRIBUTE_UNUSED) #undef PARSE_ERROR /* Generate the frags and fixups for the parsed instruction. */ - { - char *this_frag = frag_more (insn.size); - char bytes[16]; - uint8_t src, dst; - int i; - - /* Zero all the bytes. */ - memset (bytes, 0, 16); - - /* First encode the opcodes. Note that we have to handle the - endianness groups of the BPF instructions: 8 | 4 | 4 | 16 | - 32. */ - if (target_big_endian) - { - /* code */ - bytes[0] = (insn.opcode >> 56) & 0xff; - /* regs */ - bytes[1] = (insn.opcode >> 48) & 0xff; - /* offset16 */ - bytes[2] = (insn.opcode >> 40) & 0xff; - bytes[3] = (insn.opcode >> 32) & 0xff; - /* imm32 */ - bytes[4] = (insn.opcode >> 24) & 0xff; - bytes[5] = (insn.opcode >> 16) & 0xff; - bytes[6] = (insn.opcode >> 8) & 0xff; - bytes[7] = insn.opcode & 0xff; - } - else - { - /* code */ - bytes[0] = (insn.opcode >> 56) & 0xff; - /* regs */ - bytes[1] = (((((insn.opcode >> 48) & 0xff) & 0xf) << 4) - | (((insn.opcode >> 48) & 0xff) & 0xf)); - /* offset16 */ - bytes[3] = (insn.opcode >> 40) & 0xff; - bytes[2] = (insn.opcode >> 32) & 0xff; - /* imm32 */ - bytes[7] = (insn.opcode >> 24) & 0xff; - bytes[6] = (insn.opcode >> 16) & 0xff; - bytes[5] = (insn.opcode >> 8) & 0xff; - bytes[4] = insn.opcode & 0xff; - } - - /* Now the registers. */ - src = insn.has_src ? insn.src : 0; - dst = insn.has_dst ? insn.dst : 0; - - if (target_big_endian) - bytes[1] = ((dst & 0xf) << 4) | (src & 0xf); - else - bytes[1] = ((src & 0xf) << 4) | (dst & 0xf); - - /* Now the immediates. */ - if (insn.has_imm64) - { - switch (insn.imm64.X_op) - { - case O_constant: - { - uint64_t imm64 = insn.imm64.X_add_number; - - if (target_big_endian) - { - bytes[12] = (imm64 >> 56) & 0xff; - bytes[13] = (imm64 >> 48) & 0xff; - bytes[14] = (imm64 >> 40) & 0xff; - bytes[15] = (imm64 >> 32) & 0xff; - bytes[4] = (imm64 >> 24) & 0xff; - bytes[5] = (imm64 >> 16) & 0xff; - bytes[6] = (imm64 >> 8) & 0xff; - bytes[7] = imm64 & 0xff; - } - else - { - bytes[15] = (imm64 >> 56) & 0xff; - bytes[14] = (imm64 >> 48) & 0xff; - bytes[13] = (imm64 >> 40) & 0xff; - bytes[12] = (imm64 >> 32) & 0xff; - bytes[7] = (imm64 >> 24) & 0xff; - bytes[6] = (imm64 >> 16) & 0xff; - bytes[5] = (imm64 >> 8) & 0xff; - bytes[4] = imm64 & 0xff; - } - break; - } - case O_symbol: - case O_subtract: - case O_add: - { - reloc_howto_type *reloc_howto; - int size; - - reloc_howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_64); - if (!reloc_howto) - abort (); - - size = bfd_get_reloc_size (reloc_howto); - - fix_new_exp (frag_now, this_frag - frag_now->fr_literal, - size, &insn.imm64, reloc_howto->pc_relative, - BFD_RELOC_BPF_64); - break; - } - default: - abort (); - } - } - - if (insn.has_imm32) - { - switch (insn.imm32.X_op) - { - case O_constant: - { - uint32_t imm32 = insn.imm32.X_add_number; - - if (target_big_endian) - { - bytes[4] = (imm32 >> 24) & 0xff; - bytes[5] = (imm32 >> 16) & 0xff; - bytes[6] = (imm32 >> 8) & 0xff; - bytes[7] = imm32 & 0xff; - } - else - { - bytes[7] = (imm32 >> 24) & 0xff; - bytes[6] = (imm32 >> 16) & 0xff; - bytes[5] = (imm32 >> 8) & 0xff; - bytes[4] = imm32 & 0xff; - } - break; - } - case O_symbol: - case O_subtract: - case O_add: - case O_uminus: - { - reloc_howto_type *reloc_howto; - int size; - - reloc_howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_32); - if (!reloc_howto) - abort (); - - size = bfd_get_reloc_size (reloc_howto); - - fix_new_exp (frag_now, this_frag - frag_now->fr_literal + 4, - size, &insn.imm32, reloc_howto->pc_relative, - BFD_RELOC_32); - break; - } - default: - abort (); - } - } - - if (insn.has_disp32) - { - switch (insn.disp32.X_op) - { - case O_constant: - { - uint32_t disp32 = insn.disp32.X_add_number; - - if (target_big_endian) - { - bytes[4] = (disp32 >> 24) & 0xff; - bytes[5] = (disp32 >> 16) & 0xff; - bytes[6] = (disp32 >> 8) & 0xff; - bytes[7] = disp32 & 0xff; - } - else - { - bytes[7] = (disp32 >> 24) & 0xff; - bytes[6] = (disp32 >> 16) & 0xff; - bytes[5] = (disp32 >> 8) & 0xff; - bytes[4] = disp32 & 0xff; - } - break; - } - case O_symbol: - case O_subtract: - case O_add: - { - reloc_howto_type *reloc_howto; - int size; - unsigned int bfd_reloc - = (insn.id == BPF_INSN_CALL - ? BFD_RELOC_BPF_DISPCALL32 - : BFD_RELOC_BPF_DISP32); - - reloc_howto = bfd_reloc_type_lookup (stdoutput, bfd_reloc); - if (!reloc_howto) - abort (); - - size = bfd_get_reloc_size (reloc_howto); - - fix_new_exp (frag_now, this_frag - frag_now->fr_literal, - size, &insn.disp32, reloc_howto->pc_relative, - bfd_reloc); - break; - } - default: - abort (); - } - } - - if (insn.has_offset16) - { - switch (insn.offset16.X_op) - { - case O_constant: - { - uint32_t offset16 = insn.offset16.X_add_number; - - if (target_big_endian) - { - bytes[2] = (offset16 >> 8) & 0xff; - bytes[3] = offset16 & 0xff; - } - else - { - bytes[3] = (offset16 >> 8) & 0xff; - bytes[2] = offset16 & 0xff; - } - break; - } - case O_symbol: - case O_subtract: - case O_add: - { - reloc_howto_type *reloc_howto; - int size; - - reloc_howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_DISP16); - if (!reloc_howto) - abort (); - - size = bfd_get_reloc_size (reloc_howto); - - fix_new_exp (frag_now, this_frag - frag_now->fr_literal, - size, &insn.offset16, reloc_howto->pc_relative, - BFD_RELOC_BPF_DISP16); - break; - } - default: - abort (); - } - } - - if (insn.has_disp16) - { - switch (insn.disp16.X_op) - { - case O_constant: - { - uint32_t disp16 = insn.disp16.X_add_number; - - if (target_big_endian) - { - bytes[2] = (disp16 >> 8) & 0xff; - bytes[3] = disp16 & 0xff; - } - else - { - bytes[3] = (disp16 >> 8) & 0xff; - bytes[2] = disp16 & 0xff; - } - break; - } - case O_symbol: - case O_subtract: - case O_add: - { - reloc_howto_type *reloc_howto; - int size; - - reloc_howto = bfd_reloc_type_lookup (stdoutput, BFD_RELOC_BPF_DISP16); - if (!reloc_howto) - abort (); + if (do_relax && insn.is_relaxable) + { + expressionS *relaxable_exp = NULL; - size = bfd_get_reloc_size (reloc_howto); + if (insn.has_disp16) + relaxable_exp = &insn.disp16; + else + abort (); - fix_new_exp (frag_now, this_frag - frag_now->fr_literal, - size, &insn.disp16, reloc_howto->pc_relative, - BFD_RELOC_BPF_DISP16); - break; - } - default: - abort (); - } - } - - /* Emit bytes. */ - for (i = 0; i < insn.size; ++i) - { - md_number_to_chars (this_frag, (valueT) bytes[i], 1); - this_frag += 1; - } - } + add_relaxed_insn (&insn, relaxable_exp); + } + else + add_fixed_insn (&insn); /* Emit DWARF2 debugging information. */ dwarf2_emit_insn (insn.size); diff --git a/gas/doc/c-bpf.texi b/gas/doc/c-bpf.texi index 868a358cf54..6b43c77d5a0 100644 --- a/gas/doc/c-bpf.texi +++ b/gas/doc/c-bpf.texi @@ -53,6 +53,10 @@ when assembling. The BPF ISA versions supported are @option{v1} @option{v2}, @o The value @option{xbpf} can be specified to recognize extra instructions that are used by GCC for testing purposes. But beware this is not valid BPF. + +@cindex @option{-mno-relax} command-line options, BPF +@item -mno-relax +This option tells the assembler to not relax instructions. @end table Note that if no endianness option is specified in the command line, diff --git a/gas/testsuite/gas/bpf/bpf.exp b/gas/testsuite/gas/bpf/bpf.exp index 1d683d55215..6e6a0003e17 100644 --- a/gas/testsuite/gas/bpf/bpf.exp +++ b/gas/testsuite/gas/bpf/bpf.exp @@ -40,6 +40,9 @@ if {[istarget bpf*-*-*]} { run_dump_test indcall-1 run_dump_test indcall-1-pseudoc + run_dump_test jump-relax-ja + run_dump_test jump-relax-jump + # Big-endian BPF tests run_dump_test call-be run_dump_test exit-be @@ -59,4 +62,7 @@ if {[istarget bpf*-*-*]} { run_dump_test atomic-v1-be run_dump_test atomic-be run_dump_test atomic-be-pseudoc + + run_dump_test jump-relax-ja-be + run_dump_test jump-relax-jump-be } diff --git a/gas/testsuite/gas/bpf/jump-relax-ja-be.d b/gas/testsuite/gas/bpf/jump-relax-ja-be.d new file mode 100644 index 00000000000..08b85a97b45 --- /dev/null +++ b/gas/testsuite/gas/bpf/jump-relax-ja-be.d @@ -0,0 +1,19 @@ +#as: -EB -mdialect=normal +#objdump: -dr -M dec +#source: jump-relax-ja.s +#name: Relaxation of unconditional branch (JA) instructions, big-endian + +.*: +file format .*bpf.* + +Disassembly of section .text: + +0+ <.*>: + 0: 05 00 80 00 00 00 00 00 ja -32768 + 8: 05 00 7f ff 00 00 00 00 ja 32767 + 10: 05 00 ff fd 00 00 00 00 ja -3 + 18: 05 00 00 00 00 00 00 00 ja 0 + 18: R_BPF_GNU_64_16 undefined + 20: 06 00 00 00 ff ff 7f ff jal -32769 + 28: 06 00 00 00 00 00 80 00 jal 32768 + 30: 06 00 00 00 00 00 80 01 jal 32769 + 38: 06 00 00 00 00 00 80 01 jal 32769 diff --git a/gas/testsuite/gas/bpf/jump-relax-ja.d b/gas/testsuite/gas/bpf/jump-relax-ja.d new file mode 100644 index 00000000000..6b50973915d --- /dev/null +++ b/gas/testsuite/gas/bpf/jump-relax-ja.d @@ -0,0 +1,19 @@ +#as: -EL -mdialect=normal +#objdump: -dr -M dec +#source: jump-relax-ja.s +#name: Relaxation of unconditional branch (JA) instructions + +.*: +file format .*bpf.* + +Disassembly of section .text: + +0+ <.*>: + 0: 05 00 00 80 00 00 00 00 ja -32768 + 8: 05 00 ff 7f 00 00 00 00 ja 32767 + 10: 05 00 fd ff 00 00 00 00 ja -3 + 18: 05 00 00 00 00 00 00 00 ja 0 + 18: R_BPF_GNU_64_16 undefined + 20: 06 00 00 00 ff 7f ff ff jal -32769 + 28: 06 00 00 00 00 80 00 00 jal 32768 + 30: 06 00 00 00 01 80 00 00 jal 32769 + 38: 06 00 00 00 01 80 00 00 jal 32769 diff --git a/gas/testsuite/gas/bpf/jump-relax-ja.s b/gas/testsuite/gas/bpf/jump-relax-ja.s new file mode 100644 index 00000000000..8be3d7a4288 --- /dev/null +++ b/gas/testsuite/gas/bpf/jump-relax-ja.s @@ -0,0 +1,20 @@ + ;; The following two instructions have constant targets that + ;; fix in the JA 16-bit signed displacement operand. These + ;; are not relaxed. +1: ja -32768 + ja 32767 + ;; The following instruction refers to a defined symbol that + ;; is on reach, so it should not be relaxed. + ja 1b + ;; The following instruction has an undefined symbol as a + ;; target. It is not to be relaxed. + ja undefined + 10 + ;; The following instructions are relaxed to JAL instructions + ;; so they can fit their displacements. + ja -32769 + ja 32768 + ;; The following instructions refer to a defined symbol that + ;; is not on reach. They shall be relaxed to a JAL. + ja tail + tail = .text + 262160 + ja tail diff --git a/gas/testsuite/gas/bpf/jump-relax-jump.d b/gas/testsuite/gas/bpf/jump-relax-jump.d new file mode 100644 index 00000000000..cd46ea7024e --- /dev/null +++ b/gas/testsuite/gas/bpf/jump-relax-jump.d @@ -0,0 +1,25 @@ +#as: -EL -mdialect=normal +#objdump: -dr -M dec +#source: jump-relax-jump.s +#name: Relaxation of conditional branch instructions + +.*: +file format .*bpf.* + +Disassembly of section .text: + +0+ <.*>: + 0: 1d 21 00 80 00 00 00 00 jeq %r1,%r2,-32768 + 8: ad 21 ff 7f 00 00 00 00 jlt %r1,%r2,32767 + 10: bd 21 fd ff 00 00 00 00 jle %r1,%r2,-3 + 18: 3d 21 01 00 00 00 00 00 jge %r1,%r2,1 + 20: 05 00 01 00 00 00 00 00 ja 1 + 28: 06 00 00 00 ff 7f ff ff jal -32769 + 30: 2d 21 01 00 00 00 00 00 jgt %r1,%r2,1 + 38: 05 00 01 00 00 00 00 00 ja 1 + 40: 06 00 00 00 00 80 00 00 jal 32768 + 48: 1d 21 01 00 00 00 00 00 jeq %r1,%r2,1 + 50: 05 00 01 00 00 00 00 00 ja 1 + 58: 06 00 00 00 01 80 00 00 jal 32769 + 60: 2d 21 01 00 00 00 00 00 jgt %r1,%r2,1 + 68: 05 00 01 00 00 00 00 00 ja 1 + 70: 06 00 00 00 01 80 00 00 jal 32769 diff --git a/gas/testsuite/gas/bpf/jump-relax-jump.s b/gas/testsuite/gas/bpf/jump-relax-jump.s new file mode 100644 index 00000000000..dabbab84f7c --- /dev/null +++ b/gas/testsuite/gas/bpf/jump-relax-jump.s @@ -0,0 +1,17 @@ + ;; The following two instructions have constant targets that + ;; fix in the jump 16-bit signed displacement operand. +1: jeq %r1, %r2, -32768 + jlt %r1, %r2, 32767 + ;; The following instruction refers to a defined symbol that + ;; is on reach, so it should not be relaxed. + jle %r1, %r2, 1b + ;; The following instructions are relaxed to sequences + ;; involving unconditional jumps, so they can fi their + ;; displacements. + jge %r1, %r2, -32769 + jgt %r1, %r2, 32768 + ;; The following instructions refer to a defined symbol that + ;; is not on reach. They shall be relaxed. + jeq %r1, %r2, tail + tail = .text + 262160 + jgt %r1, %r2, tail