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