/* * Bdragon's single file ifunc torture test for FreeBSD (POWER9 only) * * Test cases: * cc -o ifunc_torture_test ifunc_torture_test.c * - use -static / -fpic / -fPIC / -fPIE * - use alternate linker with -fuse-ld * - use ports gcc * * Ideal behavior: All lines are identical * Acceptable behavior: Lines differ, but only in groups (indicates multiple resolver calls) * Unacceptable behavior: * * Missing lines. (Indicates PLT malfunction) * * Program crashes. (Indicates link issues) * * RTLD crashes (with error message). (Indicates assertion hit) * * RTLD crashes (with NO error message). (Indicates assertion hit AND PLT malfunction) */ #include #include #include #include #include void indirect1(void); /* Four implementations making PLT calls (printf), chosen at random */ static void thefunc_one(void) { printf("This is thefunc one\n"); } static void thefunc_two(void) { printf("This is thefunc two\n"); } static void thefunc_three(void) { printf("This is thefunc three\n"); } static void thefunc_four(void) { printf("This is thefunc four\n"); } /* POWER9 only plt-less resolver */ static int arc4random_proxy(int a) { unsigned long rndval; // Randomness without a PLT call. __asm __volatile(".long 0x7c0205e6 | (%0 << 21)" : "+r"(rndval)); return ((int)(rndval % a)); } /* Needs D22787 */ DEFINE_UIFUNC(, void, thefunc, (void)) { int foo = arc4random_proxy(4); switch (foo) { default: return &thefunc_four; case 0: return &thefunc_one; case 1: return &thefunc_two; case 2: return &thefunc_three; } } int main(int argc, char* argv[]) { printf("Inside program!\n"); printf("Direct call to ifunc (you should see two lines):\n"); printf("-------------\n"); thefunc(); thefunc(); printf("-------------\n"); printf("Indirect call to ifunc (you should see two lines):\n"); printf("-------------\n"); indirect1(); indirect1(); printf("-------------\n"); printf("Assigning function pointer.\n"); void (*theptr)(void) = &thefunc; printf("About to call via function pointer! (you should see three lines):\n"); printf("-------------\n"); (*theptr)(); (*theptr)(); (*theptr)(); printf("-------------\n"); printf("thefunc is %p\n", thefunc); printf("The pointer was %p\n", theptr); printf("Made it to the end of the test.\n"); return 0; } void __attribute__((noinline)) indirect1() { thefunc(); }