23
23
* efficient when this is not defined.
24
24
*/
25
25
#if defined(__ARM_FEATURE_UNALIGNED ) \
26
- || defined(__i386__ ) || defined(__amd64__ ) || defined(__x86_64__ )
26
+ || defined(MBEDTLS_ARCH_IS_X86 ) || defined(MBEDTLS_ARCH_IS_X64 ) \
27
+ || defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64 )
27
28
/*
28
29
* __ARM_FEATURE_UNALIGNED is defined where appropriate by armcc, gcc 7, clang 9
29
30
* (and later versions) for Arm v7 and later; all x86 platforms should have
30
31
* efficient unaligned access.
32
+ *
33
+ * https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#alignment
34
+ * specifies that on Windows-on-Arm64, unaligned access is safe (except for uncached
35
+ * device memory).
31
36
*/
32
37
#define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS
33
38
#endif
34
39
40
+ #if defined(__IAR_SYSTEMS_ICC__ ) && \
41
+ (defined(MBEDTLS_ARCH_IS_ARM64 ) || defined(MBEDTLS_ARCH_IS_ARM32 ) \
42
+ || defined(__ICCRX__ ) || defined(__ICCRL78__ ) || defined(__ICCRISCV__ ))
43
+ #pragma language=save
44
+ #pragma language=extended
45
+ #define MBEDTLS_POP_IAR_LANGUAGE_PRAGMA
46
+ /* IAR recommend this technique for accessing unaligned data in
47
+ * https://www.iar.com/knowledge/support/technical-notes/compiler/accessing-unaligned-data
48
+ * This results in a single load / store instruction (if unaligned access is supported).
49
+ * According to that document, this is only supported on certain architectures.
50
+ */
51
+ #define UINT_UNALIGNED
52
+ typedef uint16_t __packed mbedtls_uint16_unaligned_t ;
53
+ typedef uint32_t __packed mbedtls_uint32_unaligned_t ;
54
+ typedef uint64_t __packed mbedtls_uint64_unaligned_t ;
55
+ #elif defined(MBEDTLS_COMPILER_IS_GCC ) && (MBEDTLS_GCC_VERSION >= 40504 ) && \
56
+ ((MBEDTLS_GCC_VERSION < 60300 ) || (!defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS )))
57
+ /*
58
+ * gcc may generate a branch to memcpy for calls like `memcpy(dest, src, 4)` rather than
59
+ * generating some LDR or LDRB instructions (similar for stores).
60
+ *
61
+ * This is architecture dependent: x86-64 seems fine even with old gcc; 32-bit Arm
62
+ * is affected. To keep it simple, we enable for all architectures.
63
+ *
64
+ * For versions of gcc < 5.4.0 this issue always happens.
65
+ * For gcc < 6.3.0, this issue happens at -O0
66
+ * For all versions, this issue happens iff unaligned access is not supported.
67
+ *
68
+ * For gcc 4.x, this implementation will generate byte-by-byte loads even if unaligned access is
69
+ * supported, which is correct but not optimal.
70
+ *
71
+ * For performance (and code size, in some cases), we want to avoid the branch and just generate
72
+ * some inline load/store instructions since the access is small and constant-size.
73
+ *
74
+ * The manual states:
75
+ * "The packed attribute specifies that a variable or structure field should have the smallest
76
+ * possible alignment—one byte for a variable"
77
+ * https://gcc.gnu.org/onlinedocs/gcc-4.5.4/gcc/Variable-Attributes.html
78
+ *
79
+ * Previous implementations used __attribute__((__aligned__(1)), but had issues with a gcc bug:
80
+ * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94662
81
+ *
82
+ * Tested with several versions of GCC from 4.5.0 up to 13.2.0
83
+ * We don't enable for older than 4.5.0 as this has not been tested.
84
+ */
85
+ #define UINT_UNALIGNED_STRUCT
86
+ typedef struct {
87
+ uint16_t x ;
88
+ } __attribute__((packed )) mbedtls_uint16_unaligned_t ;
89
+ typedef struct {
90
+ uint32_t x ;
91
+ } __attribute__((packed )) mbedtls_uint32_unaligned_t ;
92
+ typedef struct {
93
+ uint64_t x ;
94
+ } __attribute__((packed )) mbedtls_uint64_unaligned_t ;
95
+ #endif
96
+
97
+ /*
98
+ * We try to force mbedtls_(get|put)_unaligned_uintXX to be always inline, because this results
99
+ * in code that is both smaller and faster. IAR and gcc both benefit from this when optimising
100
+ * for size.
101
+ */
102
+
35
103
/**
36
104
* Read the unsigned 16 bits integer from the given address, which need not
37
105
* be aligned.
38
106
*
39
107
* \param p pointer to 2 bytes of data
40
108
* \return Data at the given address
41
109
*/
42
- inline uint16_t mbedtls_get_unaligned_uint16 (const void * p )
110
+ #if defined(__IAR_SYSTEMS_ICC__ )
111
+ #pragma inline = forced
112
+ #elif defined(__GNUC__ )
113
+ __attribute__((always_inline ))
114
+ #endif
115
+ static inline uint16_t mbedtls_get_unaligned_uint16 (const void * p )
43
116
{
44
117
uint16_t r ;
118
+ #if defined(UINT_UNALIGNED )
119
+ mbedtls_uint16_unaligned_t * p16 = (mbedtls_uint16_unaligned_t * ) p ;
120
+ r = * p16 ;
121
+ #elif defined(UINT_UNALIGNED_STRUCT )
122
+ mbedtls_uint16_unaligned_t * p16 = (mbedtls_uint16_unaligned_t * ) p ;
123
+ r = p16 -> x ;
124
+ #else
45
125
memcpy (& r , p , sizeof (r ));
126
+ #endif
46
127
return r ;
47
128
}
48
129
@@ -53,9 +134,22 @@ inline uint16_t mbedtls_get_unaligned_uint16(const void *p)
53
134
* \param p pointer to 2 bytes of data
54
135
* \param x data to write
55
136
*/
56
- inline void mbedtls_put_unaligned_uint16 (void * p , uint16_t x )
137
+ #if defined(__IAR_SYSTEMS_ICC__ )
138
+ #pragma inline = forced
139
+ #elif defined(__GNUC__ )
140
+ __attribute__((always_inline ))
141
+ #endif
142
+ static inline void mbedtls_put_unaligned_uint16 (void * p , uint16_t x )
57
143
{
144
+ #if defined(UINT_UNALIGNED )
145
+ mbedtls_uint16_unaligned_t * p16 = (mbedtls_uint16_unaligned_t * ) p ;
146
+ * p16 = x ;
147
+ #elif defined(UINT_UNALIGNED_STRUCT )
148
+ mbedtls_uint16_unaligned_t * p16 = (mbedtls_uint16_unaligned_t * ) p ;
149
+ p16 -> x = x ;
150
+ #else
58
151
memcpy (p , & x , sizeof (x ));
152
+ #endif
59
153
}
60
154
61
155
/**
@@ -65,10 +159,23 @@ inline void mbedtls_put_unaligned_uint16(void *p, uint16_t x)
65
159
* \param p pointer to 4 bytes of data
66
160
* \return Data at the given address
67
161
*/
68
- inline uint32_t mbedtls_get_unaligned_uint32 (const void * p )
162
+ #if defined(__IAR_SYSTEMS_ICC__ )
163
+ #pragma inline = forced
164
+ #elif defined(__GNUC__ )
165
+ __attribute__((always_inline ))
166
+ #endif
167
+ static inline uint32_t mbedtls_get_unaligned_uint32 (const void * p )
69
168
{
70
169
uint32_t r ;
170
+ #if defined(UINT_UNALIGNED )
171
+ mbedtls_uint32_unaligned_t * p32 = (mbedtls_uint32_unaligned_t * ) p ;
172
+ r = * p32 ;
173
+ #elif defined(UINT_UNALIGNED_STRUCT )
174
+ mbedtls_uint32_unaligned_t * p32 = (mbedtls_uint32_unaligned_t * ) p ;
175
+ r = p32 -> x ;
176
+ #else
71
177
memcpy (& r , p , sizeof (r ));
178
+ #endif
72
179
return r ;
73
180
}
74
181
@@ -79,9 +186,22 @@ inline uint32_t mbedtls_get_unaligned_uint32(const void *p)
79
186
* \param p pointer to 4 bytes of data
80
187
* \param x data to write
81
188
*/
82
- inline void mbedtls_put_unaligned_uint32 (void * p , uint32_t x )
189
+ #if defined(__IAR_SYSTEMS_ICC__ )
190
+ #pragma inline = forced
191
+ #elif defined(__GNUC__ )
192
+ __attribute__((always_inline ))
193
+ #endif
194
+ static inline void mbedtls_put_unaligned_uint32 (void * p , uint32_t x )
83
195
{
196
+ #if defined(UINT_UNALIGNED )
197
+ mbedtls_uint32_unaligned_t * p32 = (mbedtls_uint32_unaligned_t * ) p ;
198
+ * p32 = x ;
199
+ #elif defined(UINT_UNALIGNED_STRUCT )
200
+ mbedtls_uint32_unaligned_t * p32 = (mbedtls_uint32_unaligned_t * ) p ;
201
+ p32 -> x = x ;
202
+ #else
84
203
memcpy (p , & x , sizeof (x ));
204
+ #endif
85
205
}
86
206
87
207
/**
@@ -91,10 +211,23 @@ inline void mbedtls_put_unaligned_uint32(void *p, uint32_t x)
91
211
* \param p pointer to 8 bytes of data
92
212
* \return Data at the given address
93
213
*/
94
- inline uint64_t mbedtls_get_unaligned_uint64 (const void * p )
214
+ #if defined(__IAR_SYSTEMS_ICC__ )
215
+ #pragma inline = forced
216
+ #elif defined(__GNUC__ )
217
+ __attribute__((always_inline ))
218
+ #endif
219
+ static inline uint64_t mbedtls_get_unaligned_uint64 (const void * p )
95
220
{
96
221
uint64_t r ;
222
+ #if defined(UINT_UNALIGNED )
223
+ mbedtls_uint64_unaligned_t * p64 = (mbedtls_uint64_unaligned_t * ) p ;
224
+ r = * p64 ;
225
+ #elif defined(UINT_UNALIGNED_STRUCT )
226
+ mbedtls_uint64_unaligned_t * p64 = (mbedtls_uint64_unaligned_t * ) p ;
227
+ r = p64 -> x ;
228
+ #else
97
229
memcpy (& r , p , sizeof (r ));
230
+ #endif
98
231
return r ;
99
232
}
100
233
@@ -105,11 +238,28 @@ inline uint64_t mbedtls_get_unaligned_uint64(const void *p)
105
238
* \param p pointer to 8 bytes of data
106
239
* \param x data to write
107
240
*/
108
- inline void mbedtls_put_unaligned_uint64 (void * p , uint64_t x )
241
+ #if defined(__IAR_SYSTEMS_ICC__ )
242
+ #pragma inline = forced
243
+ #elif defined(__GNUC__ )
244
+ __attribute__((always_inline ))
245
+ #endif
246
+ static inline void mbedtls_put_unaligned_uint64 (void * p , uint64_t x )
109
247
{
248
+ #if defined(UINT_UNALIGNED )
249
+ mbedtls_uint64_unaligned_t * p64 = (mbedtls_uint64_unaligned_t * ) p ;
250
+ * p64 = x ;
251
+ #elif defined(UINT_UNALIGNED_STRUCT )
252
+ mbedtls_uint64_unaligned_t * p64 = (mbedtls_uint64_unaligned_t * ) p ;
253
+ p64 -> x = x ;
254
+ #else
110
255
memcpy (p , & x , sizeof (x ));
256
+ #endif
111
257
}
112
258
259
+ #if defined(MBEDTLS_POP_IAR_LANGUAGE_PRAGMA )
260
+ #pragma language=restore
261
+ #endif
262
+
113
263
/** Byte Reading Macros
114
264
*
115
265
* Given a multi-byte integer \p x, MBEDTLS_BYTE_n retrieves the n-th
@@ -175,6 +325,16 @@ inline void mbedtls_put_unaligned_uint64(void *p, uint64_t x)
175
325
#define MBEDTLS_BSWAP32 __rev
176
326
#endif
177
327
328
+ /* Detect IAR built-in byteswap routine */
329
+ #if defined(__IAR_SYSTEMS_ICC__ )
330
+ #if defined(__ARM_ACLE )
331
+ #include <arm_acle.h>
332
+ #define MBEDTLS_BSWAP16 (x ) ((uint16_t) __rev16((uint32_t) (x)))
333
+ #define MBEDTLS_BSWAP32 __rev
334
+ #define MBEDTLS_BSWAP64 __revll
335
+ #endif
336
+ #endif
337
+
178
338
/*
179
339
* Where compiler built-ins are not present, fall back to C code that the
180
340
* compiler may be able to detect and transform into the relevant bswap or
@@ -219,10 +379,25 @@ static inline uint64_t mbedtls_bswap64(uint64_t x)
219
379
#endif /* !defined(MBEDTLS_BSWAP64) */
220
380
221
381
#if !defined(__BYTE_ORDER__ )
382
+
383
+ #if defined(__LITTLE_ENDIAN__ )
384
+ /* IAR defines __xxx_ENDIAN__, but not __BYTE_ORDER__ */
385
+ #define MBEDTLS_IS_BIG_ENDIAN 0
386
+ #elif defined(__BIG_ENDIAN__ )
387
+ #define MBEDTLS_IS_BIG_ENDIAN 1
388
+ #else
222
389
static const uint16_t mbedtls_byte_order_detector = { 0x100 };
223
390
#define MBEDTLS_IS_BIG_ENDIAN (*((unsigned char *) (&mbedtls_byte_order_detector)) == 0x01)
391
+ #endif
392
+
393
+ #else
394
+
395
+ #if (__BYTE_ORDER__ ) == (__ORDER_BIG_ENDIAN__ )
396
+ #define MBEDTLS_IS_BIG_ENDIAN 1
224
397
#else
225
- #define MBEDTLS_IS_BIG_ENDIAN ((__BYTE_ORDER__) == (__ORDER_BIG_ENDIAN__))
398
+ #define MBEDTLS_IS_BIG_ENDIAN 0
399
+ #endif
400
+
226
401
#endif /* !defined(__BYTE_ORDER__) */
227
402
228
403
/**
0 commit comments