(root)/
gcc-13.2.0/
gcc/
testsuite/
gcc.target/
arm/
pr85434.c
       1  /* { dg-do compile } */
       2  /* { dg-require-effective-target fstack_protector }*/
       3  /* { dg-require-effective-target fpic }*/
       4  /* { dg-additional-options "-Os -fpic -fstack-protector-strong" } */
       5  
       6  #include <stddef.h>
       7  #include <stdint.h>
       8  
       9  
      10  static const unsigned char base64_enc_map[64] =
      11  {
      12      'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
      13      'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
      14      'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
      15      'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
      16      'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
      17      'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
      18      '8', '9', '+', '/'
      19  };
      20  
      21  #define BASE64_SIZE_T_MAX   ( (size_t) -1 ) /* SIZE_T_MAX is not standard */
      22  
      23  
      24  void doSmth(void *x);
      25  
      26  #include <string.h>
      27  
      28  
      29  void check(int n) {
      30    
      31      if (!(n % 2 && n % 3 && n % 5)) {
      32   __asm__  (   "add    r8, r8, #1;" );
      33      }
      34  }
      35  
      36  uint32_t test(
      37    uint32_t a1,
      38    uint32_t a2,
      39    size_t a3,
      40    size_t a4,
      41    size_t a5,
      42    size_t a6)
      43  {
      44    uint32_t nResult = 0;
      45    uint8_t* h = 0L;
      46    uint8_t X[128];
      47    uint8_t mac[64];
      48    size_t len;
      49  
      50    doSmth(&a1);
      51    doSmth(&a2);
      52    doSmth(&a3);
      53    doSmth(&a4);
      54    doSmth(&a5);
      55    doSmth(&a6);
      56  
      57    if (a1 && a2 && a3 && a4 && a5 && a6) {
      58      nResult = 1;
      59      h = (void*)X;
      60      len = sizeof(X);
      61      memset(X, a2, len);
      62      len -= 64;
      63      memcpy(mac ,X, len);
      64      *(h + len) = a6;
      65  
      66      {
      67  
      68  
      69          unsigned char *dst = X;
      70          size_t dlen = a3;
      71          size_t *olen = &a6;
      72          const unsigned char *src = mac;
      73          size_t slen = a4;
      74      size_t i, n;
      75      int C1, C2, C3;
      76      unsigned char *p;
      77  
      78      if( slen == 0 )
      79      {
      80          *olen = 0;
      81          return( 0 );
      82      }
      83  
      84      n = slen / 3 + ( slen % 3 != 0 );
      85  
      86      if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 )
      87      {
      88          *olen = BASE64_SIZE_T_MAX;
      89          return( 0 );
      90      }
      91  
      92      n *= 4;
      93  
      94      if( ( dlen < n + 1 ) || ( NULL == dst ) )
      95      {
      96          *olen = n + 1;
      97          return( 0 );
      98      }
      99  
     100      n = ( slen / 3 ) * 3;
     101  
     102      for( i = 0, p = dst; i < n; i += 3 )
     103      {
     104          C1 = *src++;
     105          C2 = *src++;
     106          C3 = *src++;
     107  
     108          check(i);
     109  
     110          *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
     111          *p++ = base64_enc_map[(((C1 &  3) << 4) + (C2 >> 4)) & 0x3F];
     112          *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
     113          *p++ = base64_enc_map[C3 & 0x3F];
     114      }
     115  
     116      if( i < slen )
     117      {
     118          C1 = *src++;
     119          C2 = ( ( i + 1 ) < slen ) ? *src++ : 0;
     120  
     121          *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
     122          *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
     123  
     124          if( ( i + 1 ) < slen )
     125               *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
     126          else *p++ = '=';
     127  
     128          *p++ = '=';
     129      }
     130  
     131      *olen = p - dst;
     132      *p = 0;
     133  
     134  }
     135  
     136    __asm__ ("mov r8, %0;" : "=r" ( nResult ));
     137    }
     138    else
     139    {
     140      nResult = 2;
     141    }
     142  
     143    doSmth(X);
     144    doSmth(mac);
     145  
     146  
     147    return nResult;
     148  }
     149  
     150  /* The pattern below catches sequences of instructions that were generated
     151     for ARM and Thumb-2 before the fix for this PR. They are of the form:
     152  
     153     ldr     rX, <offset from sp or fp>
     154     <optional non ldr instructions>
     155     ldr     rY, <offset from sp or fp>
     156     ldr     rZ, [rX]
     157     <optional non ldr instructions>
     158     cmp     rY, rZ
     159     <optional non cmp instructions>
     160     bl      __stack_chk_fail
     161  
     162     Ideally the optional block would check for the various rX, rY and rZ
     163     registers not being set but this is not possible due to back references
     164     being illegal in lookahead expression in Tcl, thus preventing to use the
     165     only construct that allow to negate a regexp from using the backreferences
     166     to those registers.  Instead we go for the heuristic of allowing non ldr/cmp
     167     instructions with the assumptions that (i) those are not part of the stack
     168     protector sequences and (ii) they would only be scheduled here if they don't
     169     conflict with registers used by stack protector.
     170  
     171     Note on the regexp logic:
     172     Allowing non X instructions (where X is ldr or cmp) is done by looking for
     173     some non newline spaces, followed by something which is not X, followed by
     174     an alphanumeric character followed by anything but a newline and ended by a
     175     newline the whole thing an undetermined number of times. The alphanumeric
     176     character is there to force the match of the negative lookahead for X to
     177     only happen after all the initial spaces and thus to check the mnemonic.
     178     This prevents it to match one of the initial space.  */
     179  /* { dg-final { scan-assembler-not {ldr[ \t]+([^,]+), \[(?:sp|fp)[^]]*\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+ldr[ \t]+([^,]+), \[(?:sp|fp)[^]]*\]\n[ \t]+ldr[ \t]+([^,]+), \[\1\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+cmp[ \t]+\2, \3(?:\n[ \t]+(?!cmp)\w[^\n]*)*\n[ \t]+bl[ \t]+__stack_chk_fail} } } */
     180  
     181  /* Likewise for Thumb-1 sequences of instructions prior to the fix for this PR
     182     which had the form:
     183  
     184     ldr     rS, <offset from sp or fp>
     185     <optional non ldr instructions>
     186     ldr     rT, <PC relative offset>
     187     <optional non ldr instructions>
     188     ldr     rX, [rS, rT]
     189     <optional non ldr instructions>
     190     ldr     rY, <offset from sp or fp>
     191     ldr     rZ, [rX]
     192     <optional non ldr instructions>
     193     cmp     rY, rZ
     194     <optional non cmp instructions>
     195     bl      __stack_chk_fail
     196  
     197    Note on the regexp logic:
     198    PC relative offset is checked by looking for a source operand that does not
     199    contain [ or ].  */
     200  /* { dg-final { scan-assembler-not {ldr[ \t]+([^,]+), \[(?:sp|fp)[^]]*\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+ldr[ \t]+([^,]+), [^][\n]*(?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+ldr[ \t]+([^,]+), \[\1, \2\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+ldr[ \t]+([^,]+), \[(?:sp|fp)[^]]*\]\n[ \t]+ldr[ \t]+([^,]+), \[\3\](?:\n[ \t]+(?!ldr)\w[^\n]*)*\n[ \t]+cmp[ \t]+\4, \5(?:\n[ \t]+(?!cmp)\w[^\n]*)*\n[ \t]+bl[ \t]+__stack_chk_fail} } } */