1 | /** |
---|
2 | * |
---|
3 | * Varargs for PYR/GNU CC |
---|
4 | * |
---|
5 | * WARNING -- WARNING -- DANGER |
---|
6 | * |
---|
7 | * The code in this file implements varargs for gcc on a pyr in |
---|
8 | * a way that is compatible with code compiled by the Pyramid Technology |
---|
9 | * C compiler. |
---|
10 | * As such, it depends strongly on the Pyramid conventions for |
---|
11 | * parameter passing.ct and independent implementation. |
---|
12 | * These (somewhat bizarre) parameter-passing conventions are described |
---|
13 | * in the ``OSx Operating System Porting Guide''. |
---|
14 | * |
---|
15 | * A quick summary is useful: |
---|
16 | * 12 of the 48 register-windowed regs available for |
---|
17 | * parameter passing. Parameters of a function call that are eligible |
---|
18 | * to be passed in registers are assigned registers from TR0/PR0 onwards; |
---|
19 | * all other arguments are passed on the stack. |
---|
20 | * Structure and union parameters are *never* passed in registers, |
---|
21 | * even if they are small enough to fit. They are always passed on |
---|
22 | * the stack. |
---|
23 | * |
---|
24 | * Double-sized parameters cannot be passed in TR11, because |
---|
25 | * TR12 is not used for passing parameters. If, in the absence of this |
---|
26 | * rule, a double-sized param would have been passed in TR11, |
---|
27 | * that parameter is passed on the stack and no parameters are |
---|
28 | * passed in TR11. |
---|
29 | * |
---|
30 | * It is only known to work for passing 32-bit integer quantities |
---|
31 | * (ie chars, shorts, ints/enums, longs), doubles, or pointers. |
---|
32 | * Passing structures on a Pyramid via varargs is a loser. |
---|
33 | * Passing an object larger than 8 bytes on a pyramid via varargs may |
---|
34 | * also be a loser. |
---|
35 | * |
---|
36 | */ |
---|
37 | |
---|
38 | |
---|
39 | /* |
---|
40 | * pointer to next stack parameter in __va_buf[0] |
---|
41 | * pointer to next parameter register in __va_buf[1] |
---|
42 | * Count of registers seen at __va_buf[2] |
---|
43 | * saved pr0..pr11 in __va_buf[3..14] |
---|
44 | * # of calls to va_arg (debugging) at __va_buf[15] |
---|
45 | */ |
---|
46 | |
---|
47 | /* Define __gnuc_va_list. */ |
---|
48 | |
---|
49 | #ifndef __GNUC_VA_LIST |
---|
50 | #define __GNUC_VA_LIST |
---|
51 | |
---|
52 | typedef void *__voidptr; |
---|
53 | #if 1 |
---|
54 | |
---|
55 | typedef struct __va_regs { |
---|
56 | __voidptr __stackp,__regp,__count; |
---|
57 | __voidptr __pr0,__pr1,__pr2,__pr3,__pr4,__pr5,__pr6,__pr7,__pr8,__pr9,__pr10,__pr11; |
---|
58 | } __va_regs; |
---|
59 | |
---|
60 | typedef __va_regs __va_buf; |
---|
61 | #else |
---|
62 | |
---|
63 | /* __va_buf[0] = address of next arg passed on the stack |
---|
64 | __va_buf[1] = address of next arg passed in a register |
---|
65 | __va_buf[2] = register-# of next arg passed in a register |
---|
66 | */ |
---|
67 | typedef __voidptr(*__va_buf); |
---|
68 | |
---|
69 | #endif |
---|
70 | |
---|
71 | typedef __va_buf __gnuc_va_list; |
---|
72 | |
---|
73 | #endif /* not __GNUC_VA_LIST */ |
---|
74 | |
---|
75 | /* If this is for internal libc use, don't define anything but |
---|
76 | __gnuc_va_list. */ |
---|
77 | #if defined (_STDARG_H) || defined (_VARARGS_H) |
---|
78 | |
---|
79 | /* In GCC version 2, we want an ellipsis at the end of the declaration |
---|
80 | of the argument list. GCC version 1 can't parse it. */ |
---|
81 | |
---|
82 | #if __GNUC__ > 1 |
---|
83 | #define __va_ellipsis ... |
---|
84 | #else |
---|
85 | #define __va_ellipsis |
---|
86 | #endif |
---|
87 | |
---|
88 | #define va_alist \ |
---|
89 | __va0,__va1,__va2,__va3,__va4,__va5,__va6,__va7,__va8,__va9,__va10,__va11, \ |
---|
90 | __builtin_va_alist |
---|
91 | |
---|
92 | /* The ... causes current_function_varargs to be set in cc1. */ |
---|
93 | #define va_dcl __voidptr va_alist; __va_ellipsis |
---|
94 | |
---|
95 | |
---|
96 | /* __asm ("rcsp %0" : "=r" ( _AP [0]));*/ |
---|
97 | |
---|
98 | #define va_start(_AP) \ |
---|
99 | _AP = ((struct __va_regs) { \ |
---|
100 | &(_AP.__pr0), (void*)&__builtin_va_alist, (void*)0, \ |
---|
101 | __va0,__va1,__va2,__va3,__va4,__va5, \ |
---|
102 | __va6,__va7,__va8,__va9,__va10,__va11}) |
---|
103 | |
---|
104 | |
---|
105 | /* Avoid errors if compiling GCC v2 with GCC v1. */ |
---|
106 | #if __GNUC__ == 1 |
---|
107 | #define __extension__ |
---|
108 | #endif |
---|
109 | |
---|
110 | /* We cast to void * and then to TYPE * because this avoids |
---|
111 | a warning about increasing the alignment requirement. */ |
---|
112 | #define va_arg(_AP, _MODE) \ |
---|
113 | __extension__ \ |
---|
114 | (*({__voidptr *__ap = (__voidptr*)&_AP; \ |
---|
115 | register int __size = sizeof (_MODE); \ |
---|
116 | register int __onstack = \ |
---|
117 | (__size > 8 || ( (int)(__ap[2]) > 11) || \ |
---|
118 | (__size==8 && (int)(__ap[2])==11)); \ |
---|
119 | register int* __param_addr = ((int*)((__ap) [__onstack])); \ |
---|
120 | \ |
---|
121 | ((void *)__ap[__onstack])+=__size; \ |
---|
122 | if (__onstack==0 || (int)(__ap[2])==11) \ |
---|
123 | __ap[2]+= (__size >> 2); \ |
---|
124 | (( _MODE *) (void *) __param_addr); \ |
---|
125 | })) |
---|
126 | |
---|
127 | void va_end (__gnuc_va_list); /* Defined in libgcc.a */ |
---|
128 | #define va_end(_X) ((void)0) |
---|
129 | |
---|
130 | #endif /* defined (_STDARG_H) || defined (_VARARGS_H) */ |
---|