cat <<EOF > a.c
#include <stdio.h>

static void my_foo (void) { printf ("Hello, world!\n"); }
void (*ptr1) (void) = my_foo;
static void (*resolve_foo (void)) (void) { return ptr1; }
void foo (void) __attribute__ ((ifunc ("resolve_foo")));
EOF
cat <<EOF > b.c
#include <stdio.h>

#if VERSION==1
void foo (void) { printf ("Don't call me!\n"); }
#else
extern void foo (void);
#endif
void (*ptr2) = foo;
void bar (void)
{
  foo ();
}
EOF
cat <<EOF > main.c
extern void foo (void);
extern void bar (void);

int main (void)
{
  foo ();
  bar ();
  return 0;
}
EOF
gcc a.c -o a.so  -fPIC -shared
gcc b.c -o b1.so -fPIC -shared -DVERSION=1
gcc b.c -o b2.so -fPIC -shared -DVERSION=2
gcc main.c ./a.so ./b1.so -o test1
gcc main.c ./a.so ./b2.so -o test2
gcc main.c ./b1.so ./a.so -o test3
gcc main.c ./b2.so ./a.so -o test4
echo "Test 1:"; ./test1 || true
echo "Test 2:"; ./test2 || true
echo "Test 3:"; ./test3 || true
echo "Test 4:"; ./test4 || true
rm -f a.c b.c main.c a.so b1.so b2.so test1 test2 test3 test4
