1/* sframe-opt.c - optimize FRE and FDE information in SFrame. 2 Copyright (C) 2022-2024 Free Software Foundation, Inc. 3 4 This file is part of GAS, the GNU Assembler. 5 6 GAS is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3, or (at your option) 9 any later version. 10 11 GAS is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GAS; see the file COPYING. If not, write to the Free 18 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 19 02110-1301, USA. */ 20 21#include "as.h" 22#include "sframe.h" 23 24/* The function estimates the size of a rs_sframe variant frag based on 25 the current values of the symbols. It is called before the 26 relaxation loop. We set fr_subtype{0:2} to the expected length. */ 27 28int 29sframe_estimate_size_before_relax (fragS *frag) 30{ 31 offsetT width; 32 expressionS *exp; 33 symbolS *widthS; 34 int ret; 35 36 /* We are dealing with two different kind of fragments here which need 37 to be fixed up: 38 - first, FRE start address in each FRE, and 39 - second, Function info in each FDE (function info stores the FRE type) 40 The two kind of fragments can be differentiated based on the opcode 41 of the symbol. */ 42 exp = symbol_get_value_expression (frag->fr_symbol); 43 gas_assert ((exp->X_op == O_modulus) || (exp->X_op == O_absent)); 44 /* Fragment for function info in an SFrame FDE will always write 45 only one byte. */ 46 if (exp->X_op == O_modulus) 47 ret = 1; 48 /* Fragment for the start address in an SFrame FRE may write out 49 1/2/4 bytes depending on the value of the diff. */ 50 else 51 { 52 /* Get the width expression from the symbol. */ 53 widthS = exp->X_op_symbol; 54 width = resolve_symbol_value (widthS); 55 56 if (width < (offsetT) SFRAME_FRE_TYPE_ADDR1_LIMIT) 57 ret = 1; 58 else if (width < (offsetT) SFRAME_FRE_TYPE_ADDR2_LIMIT) 59 ret = 2; 60 else 61 ret = 4; 62 } 63 64 frag->fr_subtype = (frag->fr_subtype & ~7) | (ret & 7); 65 66 return ret; 67} 68 69/* This function relaxes a rs_sframe variant frag based on the current 70 values of the symbols. fr_subtype{0:2} is the current length of 71 the frag. This returns the change in frag length. */ 72 73int 74sframe_relax_frag (fragS *frag) 75{ 76 int oldsize, newsize; 77 78 oldsize = frag->fr_subtype & 7; 79 if (oldsize == 7) 80 oldsize = -1; 81 newsize = sframe_estimate_size_before_relax (frag); 82 return newsize - oldsize; 83} 84 85/* This function converts a rs_sframe variant frag into a normal fill 86 frag. This is called after all relaxation has been done. 87 fr_subtype{0:2} will be the desired length of the frag. */ 88 89void 90sframe_convert_frag (fragS *frag) 91{ 92 offsetT fsize; 93 offsetT diff; 94 offsetT value; 95 96 offsetT rest_of_data; 97 uint8_t fde_type, fre_type; 98 uint8_t pauth_key; 99 100 expressionS *exp; 101 symbolS *dataS; 102 symbolS *fsizeS, *diffS; 103 104 /* We are dealing with two different kind of fragments here which need 105 to be fixed up: 106 - first, FRE start address in each FRE, and 107 - second, Function info in each FDE (function info stores the FRE type) 108 The two kind of fragments can be differentiated based on the opcode 109 of the symbol. */ 110 exp = symbol_get_value_expression (frag->fr_symbol); 111 gas_assert ((exp->X_op == O_modulus) || (exp->X_op == O_absent)); 112 /* Fragment for function info in an SFrame FDE. */ 113 if (exp->X_op == O_modulus) 114 { 115 /* Gather the existing value of the rest of the data except 116 the fre_type. */ 117 dataS = exp->X_add_symbol; 118 rest_of_data = (symbol_get_value_expression(dataS))->X_add_number; 119 fde_type = SFRAME_V1_FUNC_FDE_TYPE (rest_of_data); 120 pauth_key = SFRAME_V1_FUNC_PAUTH_KEY (rest_of_data); 121 gas_assert (fde_type == SFRAME_FDE_TYPE_PCINC); 122 123 /* Calculate the applicable fre_type. */ 124 fsizeS = exp->X_op_symbol; 125 fsize = resolve_symbol_value (fsizeS); 126 if (fsize < (offsetT) SFRAME_FRE_TYPE_ADDR1_LIMIT) 127 fre_type = SFRAME_FRE_TYPE_ADDR1; 128 else if (fsize < (offsetT) SFRAME_FRE_TYPE_ADDR2_LIMIT) 129 fre_type = SFRAME_FRE_TYPE_ADDR2; 130 else 131 fre_type = SFRAME_FRE_TYPE_ADDR4; 132 133 /* Create the new function info. */ 134 value = SFRAME_V1_FUNC_INFO (fde_type, fre_type); 135 value = SFRAME_V1_FUNC_INFO_UPDATE_PAUTH_KEY (pauth_key, value); 136 137 frag->fr_literal[frag->fr_fix] = value; 138 } 139 /* Fragment for the start address in an SFrame FRE. */ 140 else 141 { 142 /* Get the fsize expression from the symbol. */ 143 fsizeS = exp->X_op_symbol; 144 fsize = resolve_symbol_value (fsizeS); 145 /* Get the diff expression from the symbol. */ 146 diffS= exp->X_add_symbol; 147 diff = resolve_symbol_value (diffS); 148 value = diff; 149 150 switch (frag->fr_subtype & 7) 151 { 152 case 1: 153 gas_assert (fsize < (offsetT) SFRAME_FRE_TYPE_ADDR1_LIMIT); 154 frag->fr_literal[frag->fr_fix] = diff; 155 break; 156 case 2: 157 gas_assert (fsize < (offsetT) SFRAME_FRE_TYPE_ADDR2_LIMIT); 158 md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 2); 159 break; 160 case 4: 161 md_number_to_chars (frag->fr_literal + frag->fr_fix, diff, 4); 162 break; 163 default: 164 abort (); 165 } 166 } 167 168 frag->fr_fix += frag->fr_subtype & 7; 169 frag->fr_type = rs_fill; 170 frag->fr_subtype = 0; 171 frag->fr_offset = 0; 172 /* FIXME do this now because we have evaluated and fixed up the fragments 173 manually ? */ 174 frag->fr_symbol = 0; 175} 176