1 /**
2 * \file alignment.h
3 *
4 * \brief Utility code for dealing with unaligned memory accesses
5 */
6 /*
7 * Copyright The Mbed TLS Contributors
8 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
9 */
10
11 #ifndef MBEDTLS_LIBRARY_ALIGNMENT_H
12 #define MBEDTLS_LIBRARY_ALIGNMENT_H
13
14 #include <stdint.h>
15 #include <string.h>
16 #include <stdlib.h>
17
18 /*
19 * Define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS for architectures where unaligned memory
20 * accesses are known to be efficient.
21 *
22 * All functions defined here will behave correctly regardless, but might be less
23 * efficient when this is not defined.
24 */
25 #if defined(__ARM_FEATURE_UNALIGNED) \
26 || defined(__i386__) || defined(__amd64__) || defined(__x86_64__)
27 /*
28 * __ARM_FEATURE_UNALIGNED is defined where appropriate by armcc, gcc 7, clang 9
29 * (and later versions) for Arm v7 and later; all x86 platforms should have
30 * efficient unaligned access.
31 */
32 #define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS
33 #endif
34
35 /**
36 * Read the unsigned 16 bits integer from the given address, which need not
37 * be aligned.
38 *
39 * \param p pointer to 2 bytes of data
40 * \return Data at the given address
41 */
mbedtls_get_unaligned_uint16(const void * p)42 inline uint16_t mbedtls_get_unaligned_uint16(const void *p)
43 {
44 uint16_t r;
45 memcpy(&r, p, sizeof(r));
46 return r;
47 }
48
49 /**
50 * Write the unsigned 16 bits integer to the given address, which need not
51 * be aligned.
52 *
53 * \param p pointer to 2 bytes of data
54 * \param x data to write
55 */
mbedtls_put_unaligned_uint16(void * p,uint16_t x)56 inline void mbedtls_put_unaligned_uint16(void *p, uint16_t x)
57 {
58 memcpy(p, &x, sizeof(x));
59 }
60
61 /**
62 * Read the unsigned 32 bits integer from the given address, which need not
63 * be aligned.
64 *
65 * \param p pointer to 4 bytes of data
66 * \return Data at the given address
67 */
mbedtls_get_unaligned_uint32(const void * p)68 inline uint32_t mbedtls_get_unaligned_uint32(const void *p)
69 {
70 uint32_t r;
71 memcpy(&r, p, sizeof(r));
72 return r;
73 }
74
75 /**
76 * Write the unsigned 32 bits integer to the given address, which need not
77 * be aligned.
78 *
79 * \param p pointer to 4 bytes of data
80 * \param x data to write
81 */
mbedtls_put_unaligned_uint32(void * p,uint32_t x)82 inline void mbedtls_put_unaligned_uint32(void *p, uint32_t x)
83 {
84 memcpy(p, &x, sizeof(x));
85 }
86
87 /**
88 * Read the unsigned 64 bits integer from the given address, which need not
89 * be aligned.
90 *
91 * \param p pointer to 8 bytes of data
92 * \return Data at the given address
93 */
mbedtls_get_unaligned_uint64(const void * p)94 inline uint64_t mbedtls_get_unaligned_uint64(const void *p)
95 {
96 uint64_t r;
97 memcpy(&r, p, sizeof(r));
98 return r;
99 }
100
101 /**
102 * Write the unsigned 64 bits integer to the given address, which need not
103 * be aligned.
104 *
105 * \param p pointer to 8 bytes of data
106 * \param x data to write
107 */
mbedtls_put_unaligned_uint64(void * p,uint64_t x)108 inline void mbedtls_put_unaligned_uint64(void *p, uint64_t x)
109 {
110 memcpy(p, &x, sizeof(x));
111 }
112
113 /** Byte Reading Macros
114 *
115 * Given a multi-byte integer \p x, MBEDTLS_BYTE_n retrieves the n-th
116 * byte from x, where byte 0 is the least significant byte.
117 */
118 #define MBEDTLS_BYTE_0(x) ((uint8_t) ((x) & 0xff))
119 #define MBEDTLS_BYTE_1(x) ((uint8_t) (((x) >> 8) & 0xff))
120 #define MBEDTLS_BYTE_2(x) ((uint8_t) (((x) >> 16) & 0xff))
121 #define MBEDTLS_BYTE_3(x) ((uint8_t) (((x) >> 24) & 0xff))
122 #define MBEDTLS_BYTE_4(x) ((uint8_t) (((x) >> 32) & 0xff))
123 #define MBEDTLS_BYTE_5(x) ((uint8_t) (((x) >> 40) & 0xff))
124 #define MBEDTLS_BYTE_6(x) ((uint8_t) (((x) >> 48) & 0xff))
125 #define MBEDTLS_BYTE_7(x) ((uint8_t) (((x) >> 56) & 0xff))
126
127 /*
128 * Detect GCC built-in byteswap routines
129 */
130 #if defined(__GNUC__) && defined(__GNUC_PREREQ)
131 #if __GNUC_PREREQ(4, 8)
132 #define MBEDTLS_BSWAP16 __builtin_bswap16
133 #endif /* __GNUC_PREREQ(4,8) */
134 #if __GNUC_PREREQ(4, 3)
135 #define MBEDTLS_BSWAP32 __builtin_bswap32
136 #define MBEDTLS_BSWAP64 __builtin_bswap64
137 #endif /* __GNUC_PREREQ(4,3) */
138 #endif /* defined(__GNUC__) && defined(__GNUC_PREREQ) */
139
140 /*
141 * Detect Clang built-in byteswap routines
142 */
143 #if defined(__clang__) && defined(__has_builtin)
144 #if __has_builtin(__builtin_bswap16) && !defined(MBEDTLS_BSWAP16)
145 #define MBEDTLS_BSWAP16 __builtin_bswap16
146 #endif /* __has_builtin(__builtin_bswap16) */
147 #if __has_builtin(__builtin_bswap32) && !defined(MBEDTLS_BSWAP32)
148 #define MBEDTLS_BSWAP32 __builtin_bswap32
149 #endif /* __has_builtin(__builtin_bswap32) */
150 #if __has_builtin(__builtin_bswap64) && !defined(MBEDTLS_BSWAP64)
151 #define MBEDTLS_BSWAP64 __builtin_bswap64
152 #endif /* __has_builtin(__builtin_bswap64) */
153 #endif /* defined(__clang__) && defined(__has_builtin) */
154
155 /*
156 * Detect MSVC built-in byteswap routines
157 */
158 #if defined(_MSC_VER)
159 #if !defined(MBEDTLS_BSWAP16)
160 #define MBEDTLS_BSWAP16 _byteswap_ushort
161 #endif
162 #if !defined(MBEDTLS_BSWAP32)
163 #define MBEDTLS_BSWAP32 _byteswap_ulong
164 #endif
165 #if !defined(MBEDTLS_BSWAP64)
166 #define MBEDTLS_BSWAP64 _byteswap_uint64
167 #endif
168 #endif /* defined(_MSC_VER) */
169
170 /* Detect armcc built-in byteswap routine */
171 #if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 410000) && !defined(MBEDTLS_BSWAP32)
172 #if defined(__ARM_ACLE) /* ARM Compiler 6 - earlier versions don't need a header */
173 #include <arm_acle.h>
174 #endif
175 #define MBEDTLS_BSWAP32 __rev
176 #endif
177
178 /*
179 * Where compiler built-ins are not present, fall back to C code that the
180 * compiler may be able to detect and transform into the relevant bswap or
181 * similar instruction.
182 */
183 #if !defined(MBEDTLS_BSWAP16)
mbedtls_bswap16(uint16_t x)184 static inline uint16_t mbedtls_bswap16(uint16_t x)
185 {
186 return
187 (x & 0x00ff) << 8 |
188 (x & 0xff00) >> 8;
189 }
190 #define MBEDTLS_BSWAP16 mbedtls_bswap16
191 #endif /* !defined(MBEDTLS_BSWAP16) */
192
193 #if !defined(MBEDTLS_BSWAP32)
mbedtls_bswap32(uint32_t x)194 static inline uint32_t mbedtls_bswap32(uint32_t x)
195 {
196 return
197 (x & 0x000000ff) << 24 |
198 (x & 0x0000ff00) << 8 |
199 (x & 0x00ff0000) >> 8 |
200 (x & 0xff000000) >> 24;
201 }
202 #define MBEDTLS_BSWAP32 mbedtls_bswap32
203 #endif /* !defined(MBEDTLS_BSWAP32) */
204
205 #if !defined(MBEDTLS_BSWAP64)
mbedtls_bswap64(uint64_t x)206 static inline uint64_t mbedtls_bswap64(uint64_t x)
207 {
208 return
209 (x & 0x00000000000000ffULL) << 56 |
210 (x & 0x000000000000ff00ULL) << 40 |
211 (x & 0x0000000000ff0000ULL) << 24 |
212 (x & 0x00000000ff000000ULL) << 8 |
213 (x & 0x000000ff00000000ULL) >> 8 |
214 (x & 0x0000ff0000000000ULL) >> 24 |
215 (x & 0x00ff000000000000ULL) >> 40 |
216 (x & 0xff00000000000000ULL) >> 56;
217 }
218 #define MBEDTLS_BSWAP64 mbedtls_bswap64
219 #endif /* !defined(MBEDTLS_BSWAP64) */
220
221 #if !defined(__BYTE_ORDER__)
222 static const uint16_t mbedtls_byte_order_detector = { 0x100 };
223 #define MBEDTLS_IS_BIG_ENDIAN (*((unsigned char *) (&mbedtls_byte_order_detector)) == 0x01)
224 #else
225 #define MBEDTLS_IS_BIG_ENDIAN ((__BYTE_ORDER__) == (__ORDER_BIG_ENDIAN__))
226 #endif /* !defined(__BYTE_ORDER__) */
227
228 /**
229 * Get the unsigned 32 bits integer corresponding to four bytes in
230 * big-endian order (MSB first).
231 *
232 * \param data Base address of the memory to get the four bytes from.
233 * \param offset Offset from \p data of the first and most significant
234 * byte of the four bytes to build the 32 bits unsigned
235 * integer from.
236 */
237 #define MBEDTLS_GET_UINT32_BE(data, offset) \
238 ((MBEDTLS_IS_BIG_ENDIAN) \
239 ? mbedtls_get_unaligned_uint32((data) + (offset)) \
240 : MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \
241 )
242
243 /**
244 * Put in memory a 32 bits unsigned integer in big-endian order.
245 *
246 * \param n 32 bits unsigned integer to put in memory.
247 * \param data Base address of the memory where to put the 32
248 * bits unsigned integer in.
249 * \param offset Offset from \p data where to put the most significant
250 * byte of the 32 bits unsigned integer \p n.
251 */
252 #define MBEDTLS_PUT_UINT32_BE(n, data, offset) \
253 { \
254 if (MBEDTLS_IS_BIG_ENDIAN) \
255 { \
256 mbedtls_put_unaligned_uint32((data) + (offset), (uint32_t) (n)); \
257 } \
258 else \
259 { \
260 mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t) (n))); \
261 } \
262 }
263
264 /**
265 * Get the unsigned 32 bits integer corresponding to four bytes in
266 * little-endian order (LSB first).
267 *
268 * \param data Base address of the memory to get the four bytes from.
269 * \param offset Offset from \p data of the first and least significant
270 * byte of the four bytes to build the 32 bits unsigned
271 * integer from.
272 */
273 #define MBEDTLS_GET_UINT32_LE(data, offset) \
274 ((MBEDTLS_IS_BIG_ENDIAN) \
275 ? MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \
276 : mbedtls_get_unaligned_uint32((data) + (offset)) \
277 )
278
279
280 /**
281 * Put in memory a 32 bits unsigned integer in little-endian order.
282 *
283 * \param n 32 bits unsigned integer to put in memory.
284 * \param data Base address of the memory where to put the 32
285 * bits unsigned integer in.
286 * \param offset Offset from \p data where to put the least significant
287 * byte of the 32 bits unsigned integer \p n.
288 */
289 #define MBEDTLS_PUT_UINT32_LE(n, data, offset) \
290 { \
291 if (MBEDTLS_IS_BIG_ENDIAN) \
292 { \
293 mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t) (n))); \
294 } \
295 else \
296 { \
297 mbedtls_put_unaligned_uint32((data) + (offset), ((uint32_t) (n))); \
298 } \
299 }
300
301 /**
302 * Get the unsigned 16 bits integer corresponding to two bytes in
303 * little-endian order (LSB first).
304 *
305 * \param data Base address of the memory to get the two bytes from.
306 * \param offset Offset from \p data of the first and least significant
307 * byte of the two bytes to build the 16 bits unsigned
308 * integer from.
309 */
310 #define MBEDTLS_GET_UINT16_LE(data, offset) \
311 ((MBEDTLS_IS_BIG_ENDIAN) \
312 ? MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \
313 : mbedtls_get_unaligned_uint16((data) + (offset)) \
314 )
315
316 /**
317 * Put in memory a 16 bits unsigned integer in little-endian order.
318 *
319 * \param n 16 bits unsigned integer to put in memory.
320 * \param data Base address of the memory where to put the 16
321 * bits unsigned integer in.
322 * \param offset Offset from \p data where to put the least significant
323 * byte of the 16 bits unsigned integer \p n.
324 */
325 #define MBEDTLS_PUT_UINT16_LE(n, data, offset) \
326 { \
327 if (MBEDTLS_IS_BIG_ENDIAN) \
328 { \
329 mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t) (n))); \
330 } \
331 else \
332 { \
333 mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t) (n)); \
334 } \
335 }
336
337 /**
338 * Get the unsigned 16 bits integer corresponding to two bytes in
339 * big-endian order (MSB first).
340 *
341 * \param data Base address of the memory to get the two bytes from.
342 * \param offset Offset from \p data of the first and most significant
343 * byte of the two bytes to build the 16 bits unsigned
344 * integer from.
345 */
346 #define MBEDTLS_GET_UINT16_BE(data, offset) \
347 ((MBEDTLS_IS_BIG_ENDIAN) \
348 ? mbedtls_get_unaligned_uint16((data) + (offset)) \
349 : MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \
350 )
351
352 /**
353 * Put in memory a 16 bits unsigned integer in big-endian order.
354 *
355 * \param n 16 bits unsigned integer to put in memory.
356 * \param data Base address of the memory where to put the 16
357 * bits unsigned integer in.
358 * \param offset Offset from \p data where to put the most significant
359 * byte of the 16 bits unsigned integer \p n.
360 */
361 #define MBEDTLS_PUT_UINT16_BE(n, data, offset) \
362 { \
363 if (MBEDTLS_IS_BIG_ENDIAN) \
364 { \
365 mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t) (n)); \
366 } \
367 else \
368 { \
369 mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t) (n))); \
370 } \
371 }
372
373 /**
374 * Get the unsigned 24 bits integer corresponding to three bytes in
375 * big-endian order (MSB first).
376 *
377 * \param data Base address of the memory to get the three bytes from.
378 * \param offset Offset from \p data of the first and most significant
379 * byte of the three bytes to build the 24 bits unsigned
380 * integer from.
381 */
382 #define MBEDTLS_GET_UINT24_BE(data, offset) \
383 ( \
384 ((uint32_t) (data)[(offset)] << 16) \
385 | ((uint32_t) (data)[(offset) + 1] << 8) \
386 | ((uint32_t) (data)[(offset) + 2]) \
387 )
388
389 /**
390 * Put in memory a 24 bits unsigned integer in big-endian order.
391 *
392 * \param n 24 bits unsigned integer to put in memory.
393 * \param data Base address of the memory where to put the 24
394 * bits unsigned integer in.
395 * \param offset Offset from \p data where to put the most significant
396 * byte of the 24 bits unsigned integer \p n.
397 */
398 #define MBEDTLS_PUT_UINT24_BE(n, data, offset) \
399 { \
400 (data)[(offset)] = MBEDTLS_BYTE_2(n); \
401 (data)[(offset) + 1] = MBEDTLS_BYTE_1(n); \
402 (data)[(offset) + 2] = MBEDTLS_BYTE_0(n); \
403 }
404
405 /**
406 * Get the unsigned 24 bits integer corresponding to three bytes in
407 * little-endian order (LSB first).
408 *
409 * \param data Base address of the memory to get the three bytes from.
410 * \param offset Offset from \p data of the first and least significant
411 * byte of the three bytes to build the 24 bits unsigned
412 * integer from.
413 */
414 #define MBEDTLS_GET_UINT24_LE(data, offset) \
415 ( \
416 ((uint32_t) (data)[(offset)]) \
417 | ((uint32_t) (data)[(offset) + 1] << 8) \
418 | ((uint32_t) (data)[(offset) + 2] << 16) \
419 )
420
421 /**
422 * Put in memory a 24 bits unsigned integer in little-endian order.
423 *
424 * \param n 24 bits unsigned integer to put in memory.
425 * \param data Base address of the memory where to put the 24
426 * bits unsigned integer in.
427 * \param offset Offset from \p data where to put the least significant
428 * byte of the 24 bits unsigned integer \p n.
429 */
430 #define MBEDTLS_PUT_UINT24_LE(n, data, offset) \
431 { \
432 (data)[(offset)] = MBEDTLS_BYTE_0(n); \
433 (data)[(offset) + 1] = MBEDTLS_BYTE_1(n); \
434 (data)[(offset) + 2] = MBEDTLS_BYTE_2(n); \
435 }
436
437 /**
438 * Get the unsigned 64 bits integer corresponding to eight bytes in
439 * big-endian order (MSB first).
440 *
441 * \param data Base address of the memory to get the eight bytes from.
442 * \param offset Offset from \p data of the first and most significant
443 * byte of the eight bytes to build the 64 bits unsigned
444 * integer from.
445 */
446 #define MBEDTLS_GET_UINT64_BE(data, offset) \
447 ((MBEDTLS_IS_BIG_ENDIAN) \
448 ? mbedtls_get_unaligned_uint64((data) + (offset)) \
449 : MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \
450 )
451
452 /**
453 * Put in memory a 64 bits unsigned integer in big-endian order.
454 *
455 * \param n 64 bits unsigned integer to put in memory.
456 * \param data Base address of the memory where to put the 64
457 * bits unsigned integer in.
458 * \param offset Offset from \p data where to put the most significant
459 * byte of the 64 bits unsigned integer \p n.
460 */
461 #define MBEDTLS_PUT_UINT64_BE(n, data, offset) \
462 { \
463 if (MBEDTLS_IS_BIG_ENDIAN) \
464 { \
465 mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t) (n)); \
466 } \
467 else \
468 { \
469 mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t) (n))); \
470 } \
471 }
472
473 /**
474 * Get the unsigned 64 bits integer corresponding to eight bytes in
475 * little-endian order (LSB first).
476 *
477 * \param data Base address of the memory to get the eight bytes from.
478 * \param offset Offset from \p data of the first and least significant
479 * byte of the eight bytes to build the 64 bits unsigned
480 * integer from.
481 */
482 #define MBEDTLS_GET_UINT64_LE(data, offset) \
483 ((MBEDTLS_IS_BIG_ENDIAN) \
484 ? MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \
485 : mbedtls_get_unaligned_uint64((data) + (offset)) \
486 )
487
488 /**
489 * Put in memory a 64 bits unsigned integer in little-endian order.
490 *
491 * \param n 64 bits unsigned integer to put in memory.
492 * \param data Base address of the memory where to put the 64
493 * bits unsigned integer in.
494 * \param offset Offset from \p data where to put the least significant
495 * byte of the 64 bits unsigned integer \p n.
496 */
497 #define MBEDTLS_PUT_UINT64_LE(n, data, offset) \
498 { \
499 if (MBEDTLS_IS_BIG_ENDIAN) \
500 { \
501 mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t) (n))); \
502 } \
503 else \
504 { \
505 mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t) (n)); \
506 } \
507 }
508
509 #endif /* MBEDTLS_LIBRARY_ALIGNMENT_H */
510