1  /* Test for IFUNC handling with local definitions.
       2     Copyright (C) 2019-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  /* This test is based on gcc.dg/attr-ifunc-4.c.  */
      20  
      21  #include <config.h>
      22  
      23  # include <stdbool.h>
      24  # include <stdio.h>
      25  
      26  /* Do not use the test framework, so that the process setup is not
      27     disturbed.  */
      28  
      29  static volatile int implementation_called;
      30  static volatile int resolver_called;
      31  
      32  /* Just a random constant, to check that we called the right
      33     function.  */
      34  enum { random_constant = 0x3a88d66d };
      35  
      36  static int
      37  implementation (void)
      38  {
      39    ++implementation_called;
      40    return random_constant;
      41  }
      42  
      43  static __typeof__ (implementation) *
      44  inhibit_stack_protector
      45  resolver (void)
      46  {
      47    ++resolver_called;
      48    return implementation;
      49  }
      50  
      51  static int magic (void) __attribute__ ((ifunc ("resolver")));
      52  
      53  int
      54  main (void)
      55  {
      56    bool errors = false;
      57  
      58    if (implementation_called != 0)
      59      {
      60        printf ("error: initial value of implementation_called is not zero:"
      61                " %d\n", implementation_called);
      62        errors = true;
      63      }
      64  
      65    /* This can be zero if the reference is bound lazily.  */
      66    printf ("info: initial value of resolver_called: %d\n", resolver_called);
      67  
      68    int magic_value = magic ();
      69    if (magic_value != random_constant)
      70      {
      71        printf ("error: invalid magic value: 0x%x\n", magic_value);
      72        errors = true;
      73      }
      74  
      75    printf ("info: resolver_called value: %d\n", resolver_called);
      76    if (resolver_called == 0)
      77      {
      78        /* In theory, the resolver could be called multiple times if
      79           several relocations are needed.  */
      80        puts ("error: invalid resolver_called value (must not be zero)");
      81        errors = true;
      82      }
      83  
      84    printf ("info: implementation_called value: %d\n", implementation_called);
      85    if (implementation_called != 1)
      86      {
      87        puts ("error: invalid implementation_called value (must be 1)");
      88        errors = true;
      89      }
      90  
      91    return errors;
      92  }