1 /* sframe-opt.c - optimize FRE and FDE information in SFrame.
2 Copyright (C) 2022-2024 Free Software Foundation, Inc.
4 This file is part of GAS, the GNU Assembler.
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)
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.
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
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. */
29 sframe_estimate_size_before_relax (fragS
*frag
)
36 /* We are dealing with two different kind of fragments here which need
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
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
46 if (exp
->X_op
== O_modulus
)
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. */
52 /* Get the width expression from the symbol. */
53 widthS
= exp
->X_op_symbol
;
54 width
= resolve_symbol_value (widthS
);
56 if (width
< (offsetT
) SFRAME_FRE_TYPE_ADDR1_LIMIT
)
58 else if (width
< (offsetT
) SFRAME_FRE_TYPE_ADDR2_LIMIT
)
64 frag
->fr_subtype
= (frag
->fr_subtype
& ~7) | (ret
& 7);
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. */
74 sframe_relax_frag (fragS
*frag
)
78 oldsize
= frag
->fr_subtype
& 7;
81 newsize
= sframe_estimate_size_before_relax (frag
);
82 return newsize
- oldsize
;
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. */
90 sframe_convert_frag (fragS
*frag
)
97 uint8_t fde_type
, fre_type
;
102 symbolS
*fsizeS
, *diffS
;
104 /* We are dealing with two different kind of fragments here which need
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
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
)
115 /* Gather the existing value of the rest of the data except
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
);
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
;
131 fre_type
= SFRAME_FRE_TYPE_ADDR4
;
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
);
137 frag
->fr_literal
[frag
->fr_fix
] = value
;
139 /* Fragment for the start address in an SFrame FRE. */
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
);
150 switch (frag
->fr_subtype
& 7)
153 gas_assert (fsize
< (offsetT
) SFRAME_FRE_TYPE_ADDR1_LIMIT
);
154 frag
->fr_literal
[frag
->fr_fix
] = diff
;
157 gas_assert (fsize
< (offsetT
) SFRAME_FRE_TYPE_ADDR2_LIMIT
);
158 md_number_to_chars (frag
->fr_literal
+ frag
->fr_fix
, diff
, 2);
161 md_number_to_chars (frag
->fr_literal
+ frag
->fr_fix
, diff
, 4);
168 frag
->fr_fix
+= frag
->fr_subtype
& 7;
169 frag
->fr_type
= rs_fill
;
170 frag
->fr_subtype
= 0;
172 /* FIXME do this now because we have evaluated and fixed up the fragments