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