|
@@ -43,6 +43,72 @@ __attribute__ (( noinline )) int flsl_var ( long value ) {
|
43
|
43
|
return flsl ( value );
|
44
|
44
|
}
|
45
|
45
|
|
|
46
|
+/**
|
|
47
|
+ * Check current stack pointer
|
|
48
|
+ *
|
|
49
|
+ * @ret stack A value at a fixed offset from the current stack pointer
|
|
50
|
+ *
|
|
51
|
+ * Used by check_divmod()
|
|
52
|
+ */
|
|
53
|
+static __attribute__ (( noinline )) void * stack_check ( void ) {
|
|
54
|
+ int a;
|
|
55
|
+ void *ret;
|
|
56
|
+
|
|
57
|
+ /* Hide the fact that we are returning the address of a local
|
|
58
|
+ * variable, to prevent a compiler warning.
|
|
59
|
+ */
|
|
60
|
+ __asm__ ( "\n" : "=g" ( ret ) : "0" ( &a ) );
|
|
61
|
+
|
|
62
|
+ return ret;
|
|
63
|
+}
|
|
64
|
+
|
|
65
|
+/**
|
|
66
|
+ * Check division/modulus operation
|
|
67
|
+ *
|
|
68
|
+ * One aspect of the calling convention for the implicit arithmetic
|
|
69
|
+ * functions (__udivmoddi4() etc) is whether the caller or the callee
|
|
70
|
+ * is expected to pop any stack-based arguments. This distinction can
|
|
71
|
+ * be masked if the compiler chooses to uses a frame pointer in the
|
|
72
|
+ * caller, since the caller will then reload the stack pointer from
|
|
73
|
+ * the frame pointer and so can mask an error in the value of the
|
|
74
|
+ * stack pointer.
|
|
75
|
+ *
|
|
76
|
+ * We run the division operation in a loop, and check that the stack
|
|
77
|
+ * pointer does not change value on the second iteration. To prevent
|
|
78
|
+ * the compiler from performing various optimisations which might
|
|
79
|
+ * invalidate our intended test (such as unrolling the loop, or moving
|
|
80
|
+ * the division operation outside the loop), we include some dummy
|
|
81
|
+ * inline assembly code.
|
|
82
|
+ */
|
|
83
|
+#define check_divmod( dividend, divisor, OP ) ( { \
|
|
84
|
+ uint64_t result; \
|
|
85
|
+ int count = 2; \
|
|
86
|
+ void *check = NULL; \
|
|
87
|
+ \
|
|
88
|
+ /* Prevent compiler from unrolling the loop */ \
|
|
89
|
+ __asm__ ( "\n" : "=g" ( count ) : "0" ( count ) ); \
|
|
90
|
+ \
|
|
91
|
+ do { \
|
|
92
|
+ /* Check that stack pointer does not change between \
|
|
93
|
+ * loop iterations. \
|
|
94
|
+ */ \
|
|
95
|
+ if ( check ) { \
|
|
96
|
+ assert ( check == stack_check() ); \
|
|
97
|
+ } else { \
|
|
98
|
+ check = stack_check(); \
|
|
99
|
+ } \
|
|
100
|
+ \
|
|
101
|
+ /* Perform division, preventing the compiler from \
|
|
102
|
+ * moving the division out of the loop. \
|
|
103
|
+ */ \
|
|
104
|
+ __asm__ ( "\n" : "=g" ( dividend ), "=g" ( divisor ) \
|
|
105
|
+ : "0" ( dividend ), "1" ( divisor ) ); \
|
|
106
|
+ result = ( dividend OP divisor ); \
|
|
107
|
+ __asm__ ( "\n" : "=g" ( result ) : "0" ( result ) ); \
|
|
108
|
+ \
|
|
109
|
+ } while ( --count ); \
|
|
110
|
+ result; } )
|
|
111
|
+
|
46
|
112
|
/**
|
47
|
113
|
* Force a use of runtime 64-bit unsigned integer division
|
48
|
114
|
*
|
|
@@ -52,7 +118,8 @@ __attribute__ (( noinline )) int flsl_var ( long value ) {
|
52
|
118
|
*/
|
53
|
119
|
__attribute__ (( noinline )) uint64_t u64div_var ( uint64_t dividend,
|
54
|
120
|
uint64_t divisor ) {
|
55
|
|
- return ( dividend / divisor );
|
|
121
|
+
|
|
122
|
+ return check_divmod ( dividend, divisor, / );
|
56
|
123
|
}
|
57
|
124
|
|
58
|
125
|
/**
|
|
@@ -64,7 +131,8 @@ __attribute__ (( noinline )) uint64_t u64div_var ( uint64_t dividend,
|
64
|
131
|
*/
|
65
|
132
|
__attribute__ (( noinline )) uint64_t u64mod_var ( uint64_t dividend,
|
66
|
133
|
uint64_t divisor ) {
|
67
|
|
- return ( dividend % divisor );
|
|
134
|
+
|
|
135
|
+ return check_divmod ( dividend, divisor, % );
|
68
|
136
|
}
|
69
|
137
|
|
70
|
138
|
/**
|
|
@@ -76,7 +144,8 @@ __attribute__ (( noinline )) uint64_t u64mod_var ( uint64_t dividend,
|
76
|
144
|
*/
|
77
|
145
|
__attribute__ (( noinline )) int64_t s64div_var ( int64_t dividend,
|
78
|
146
|
int64_t divisor ) {
|
79
|
|
- return ( dividend / divisor );
|
|
147
|
+
|
|
148
|
+ return check_divmod ( dividend, divisor, / );
|
80
|
149
|
}
|
81
|
150
|
|
82
|
151
|
/**
|
|
@@ -88,7 +157,8 @@ __attribute__ (( noinline )) int64_t s64div_var ( int64_t dividend,
|
88
|
157
|
*/
|
89
|
158
|
__attribute__ (( noinline )) int64_t s64mod_var ( int64_t dividend,
|
90
|
159
|
int64_t divisor ) {
|
91
|
|
- return ( dividend % divisor );
|
|
160
|
+
|
|
161
|
+ return check_divmod ( dividend, divisor, % );
|
92
|
162
|
}
|
93
|
163
|
|
94
|
164
|
/**
|