(root)/
binutils-2.41/
gas/
sframe-opt.c
       1  /* sframe-opt.c - optimize FRE and FDE information in SFrame.
       2     Copyright (C) 2022-2023 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  
      28  int
      29  sframe_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  
      73  int
      74  sframe_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  
      89  void
      90  sframe_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  }