1/* Copyright (C) 2006 Free Software Foundation, Inc. */ 2/* Contributed by Carlos O'Donell on 2006-03-14 */ 3 4/* Test that GCC follows the SPARC 32-bit psABI with regards to 5 structure return checking in a callee. When -mstd-struct-return 6 is specificed then gcc will emit code to skip the unimp insn. */ 7 8/* Origin: Carlos O'Donell <carlos@codesourcery.com> */ 9/* { dg-do run { target sparc*-*-solaris* sparc*-*-linux* sparc*-*-*bsd* } } */ 10/* { dg-options "-mstd-struct-return" } */ 11/* { dg-require-effective-target ilp32 } */ 12#include <stdio.h> 13#include <stdlib.h> 14#include <signal.h> 15 16/* Local declaration of div_t structure */ 17struct mydiv_t { 18 int rem; 19 int quot; 20}; 21 22/* Global check variable used by signal handler */ 23int check = 1; 24struct mydiv_t dcheck; 25 26struct mydiv_t foo (void) 27{ 28 struct mydiv_t bar; 29 bar.rem = 3; 30 bar.quot = 4; 31 return bar; 32} 33 34void handle_sigill (int signum) 35{ 36 if (signum == SIGILL && check == 2) 37 { 38 /* We expected a SIGILL due to a mismatch in unimp size 39 and struct mydiv_t size */ 40 exit (0); 41 } 42 else 43 abort (); 44} 45 46/* Implement 3 checks to validate SPARC 32-bit psABI callee 47 returns struct 48 49 Test1: Save area is valid. unimp size is valid. 50 Success: Save area modified correctly. 51 Failure: Save area unmodified. 52 53 Test2: Save area is valid. unimp size is invalid (invalid insn). 54 Success: Save area unmodified. check == 2. 55 Failure: Save area modified or check == 1. 56 57 Test3: Save area is invalid. unimp size is invalid (invalid size). 58 Success: Will raise a SIGILL. 59 Failure: SIGSEGV caused by write to invalid save area. */ 60 61int main (void) 62{ 63 dcheck.rem = 1; 64 dcheck.quot = 2; 65 66 /*** Test1 ***/ 67 /* Insert a call, insert unimp by hand */ 68 __asm__ ("st %1, [ %%sp + 0x40 ]\n\t" 69 "call foo\n\t" 70 " nop\n\t" 71 "unimp %2\n\t" 72 : "=m" (dcheck) 73 : "r" (&dcheck), "i" (sizeof(struct mydiv_t)) 74 : "memory"); 75 76 /* If the caller doesn't adjust the return, then it crashes. 77 Check the result too. */ 78 79 if ((dcheck.rem != 3) || (dcheck.quot !=4)) 80 abort (); 81 82 83 /*** Test 2 ***/ 84 dcheck.rem = 1; 85 dcheck.quot = 2; 86 87 /* Ignore the return of the function */ 88 __asm__ ("st %3, [ %%sp + 0x40 ]\n\t" 89 "call foo\n\t" 90 " nop\n\t" 91 "mov %2, %0\n\t" 92 : "+r" (check), "=m" (dcheck) 93 : "i" (0x2), "r" (&dcheck) 94 : "memory"); 95 96 /* If the caller does an unconditional adjustment it will skip 97 the mov, and then we can fail the test based on check's value 98 We pass a valid pointer to a save area in order to check if 99 caller incorrectly wrote to the save area aswell. There may 100 be a case where the unimp check and skip is correct, but the 101 write to the save area still occurs. */ 102 103 if (check != 2) 104 abort (); 105 106 if ((dcheck.rem != 1) || (dcheck.quot != 2)) 107 abort (); 108 109 /*** Test 3 ***/ 110 /* Prepare a test that must SIGILL. According to the spec 111 if the sizes of the save area and return don't match then 112 the copy is ignored and we return to the unimp. */ 113 114 signal (SIGILL, handle_sigill); 115 116 __asm__ ("st %%g0, [ %%sp + 0x40 ]\n\t" 117 "call foo\n\t" 118 " nop\n\t" 119 "unimp %0\n\t" 120 : /* No outputs */ 121 : "i" (sizeof(struct mydiv_t)-1) 122 : "memory"); 123 124 /* NEVER REACHED */ 125 exit (0); 126} 127