v2 / thirdparty / mbedtls / library / alignment.h
687 lines · 643 sloc · 26.49 KB · 3d9911f887ecec942f9ae2a5be02d064f233b729
Raw
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#if !defined(MBEDTLS_ALIGNMENT_DISABLE_EFFICENT_UNALIGNED_ACCESS) //no-check-names
19/*
20 * Define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS for architectures where unaligned memory
21 * accesses are known to be efficient.
22 *
23 * All functions defined here will behave correctly regardless, but might be less
24 * efficient when this is not defined.
25 */
26#if defined(__ARM_FEATURE_UNALIGNED) \
27 || defined(MBEDTLS_ARCH_IS_X86) || defined(MBEDTLS_ARCH_IS_X64) \
28 || defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64)
29/*
30 * __ARM_FEATURE_UNALIGNED is defined where appropriate by armcc, gcc 7, clang 9
31 * (and later versions) for Arm v7 and later; all x86 platforms should have
32 * efficient unaligned access.
33 *
34 * https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#alignment
35 * specifies that on Windows-on-Arm64, unaligned access is safe (except for uncached
36 * device memory).
37 */
38#define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS
39#endif /* __ARM_FEATURE_UNALIGNED || MBEDTLS_ARCH_IS_X86 || MBEDTLS_ARCH_IS_X64 ||
40 * MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64 */
41#endif /* MBEDTLS_ALIGNMENT_DISABLE_EFFICENT_UNALIGNED_ACCESS */ //no-check-names
42
43#if defined(__IAR_SYSTEMS_ICC__) && \
44 (defined(MBEDTLS_ARCH_IS_ARM64) || defined(MBEDTLS_ARCH_IS_ARM32) \
45 || defined(__ICCRX__) || defined(__ICCRL78__) || defined(__ICCRISCV__))
46#pragma language=save
47#pragma language=extended
48#define MBEDTLS_POP_IAR_LANGUAGE_PRAGMA
49/* IAR recommend this technique for accessing unaligned data in
50 * https://www.iar.com/knowledge/support/technical-notes/compiler/accessing-unaligned-data
51 * This results in a single load / store instruction (if unaligned access is supported).
52 * According to that document, this is only supported on certain architectures.
53 */
54 #define UINT_UNALIGNED
55typedef uint16_t __packed mbedtls_uint16_unaligned_t;
56typedef uint32_t __packed mbedtls_uint32_unaligned_t;
57typedef uint64_t __packed mbedtls_uint64_unaligned_t;
58#elif defined(MBEDTLS_COMPILER_IS_GCC) && (MBEDTLS_GCC_VERSION >= 40504) && \
59 ((MBEDTLS_GCC_VERSION < 60300) || (!defined(MBEDTLS_EFFICIENT_UNALIGNED_ACCESS)))
60/*
61 * gcc may generate a branch to memcpy for calls like `memcpy(dest, src, 4)` rather than
62 * generating some LDR or LDRB instructions (similar for stores).
63 *
64 * This is architecture dependent: x86-64 seems fine even with old gcc; 32-bit Arm
65 * is affected. To keep it simple, we enable for all architectures.
66 *
67 * For versions of gcc < 5.4.0 this issue always happens.
68 * For gcc < 6.3.0, this issue happens at -O0
69 * For all versions, this issue happens iff unaligned access is not supported.
70 *
71 * For gcc 4.x, this implementation will generate byte-by-byte loads even if unaligned access is
72 * supported, which is correct but not optimal.
73 *
74 * For performance (and code size, in some cases), we want to avoid the branch and just generate
75 * some inline load/store instructions since the access is small and constant-size.
76 *
77 * The manual states:
78 * "The packed attribute specifies that a variable or structure field should have the smallest
79 * possible alignment—one byte for a variable"
80 * https://gcc.gnu.org/onlinedocs/gcc-4.5.4/gcc/Variable-Attributes.html
81 *
82 * Previous implementations used __attribute__((__aligned__(1)), but had issues with a gcc bug:
83 * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94662
84 *
85 * Tested with several versions of GCC from 4.5.0 up to 13.2.0
86 * We don't enable for older than 4.5.0 as this has not been tested.
87 */
88 #define UINT_UNALIGNED_STRUCT
89typedef struct {
90 uint16_t x;
91} __attribute__((packed, may_alias)) mbedtls_uint16_unaligned_t;
92typedef struct {
93 uint32_t x;
94} __attribute__((packed, may_alias)) mbedtls_uint32_unaligned_t;
95typedef struct {
96 uint64_t x;
97} __attribute__((packed, may_alias)) mbedtls_uint64_unaligned_t;
98 #endif
99
100/*
101 * We try to force mbedtls_(get|put)_unaligned_uintXX to be always inline, because this results
102 * in code that is both smaller and faster. IAR and gcc both benefit from this when optimising
103 * for size.
104 */
105
106/**
107 * Read the unsigned 16 bits integer from the given address, which need not
108 * be aligned.
109 *
110 * \param p pointer to 2 bytes of data
111 * \return Data at the given address
112 */
113#if defined(__IAR_SYSTEMS_ICC__)
114#pragma inline = forced
115#elif defined(__GNUC__)
116__attribute__((always_inline))
117#endif
118static inline uint16_t mbedtls_get_unaligned_uint16(const void *p)
119{
120 uint16_t r;
121#if defined(UINT_UNALIGNED)
122 mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
123 r = *p16;
124#elif defined(UINT_UNALIGNED_STRUCT)
125 mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
126 r = p16->x;
127#else
128 memcpy(&r, p, sizeof(r));
129#endif
130 return r;
131}
132
133/**
134 * Write the unsigned 16 bits integer to the given address, which need not
135 * be aligned.
136 *
137 * \param p pointer to 2 bytes of data
138 * \param x data to write
139 */
140#if defined(__IAR_SYSTEMS_ICC__)
141#pragma inline = forced
142#elif defined(__GNUC__)
143__attribute__((always_inline))
144#endif
145static inline void mbedtls_put_unaligned_uint16(void *p, uint16_t x)
146{
147#if defined(UINT_UNALIGNED)
148 mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
149 *p16 = x;
150#elif defined(UINT_UNALIGNED_STRUCT)
151 mbedtls_uint16_unaligned_t *p16 = (mbedtls_uint16_unaligned_t *) p;
152 p16->x = x;
153#else
154 memcpy(p, &x, sizeof(x));
155#endif
156}
157
158/**
159 * Read the unsigned 32 bits integer from the given address, which need not
160 * be aligned.
161 *
162 * \param p pointer to 4 bytes of data
163 * \return Data at the given address
164 */
165#if defined(__IAR_SYSTEMS_ICC__)
166#pragma inline = forced
167#elif defined(__GNUC__)
168__attribute__((always_inline))
169#endif
170static inline uint32_t mbedtls_get_unaligned_uint32(const void *p)
171{
172 uint32_t r;
173#if defined(UINT_UNALIGNED)
174 mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
175 r = *p32;
176#elif defined(UINT_UNALIGNED_STRUCT)
177 mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
178 r = p32->x;
179#else
180 memcpy(&r, p, sizeof(r));
181#endif
182 return r;
183}
184
185/**
186 * Write the unsigned 32 bits integer to the given address, which need not
187 * be aligned.
188 *
189 * \param p pointer to 4 bytes of data
190 * \param x data to write
191 */
192#if defined(__IAR_SYSTEMS_ICC__)
193#pragma inline = forced
194#elif defined(__GNUC__)
195__attribute__((always_inline))
196#endif
197static inline void mbedtls_put_unaligned_uint32(void *p, uint32_t x)
198{
199#if defined(UINT_UNALIGNED)
200 mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
201 *p32 = x;
202#elif defined(UINT_UNALIGNED_STRUCT)
203 mbedtls_uint32_unaligned_t *p32 = (mbedtls_uint32_unaligned_t *) p;
204 p32->x = x;
205#else
206 memcpy(p, &x, sizeof(x));
207#endif
208}
209
210/**
211 * Read the unsigned 64 bits integer from the given address, which need not
212 * be aligned.
213 *
214 * \param p pointer to 8 bytes of data
215 * \return Data at the given address
216 */
217#if defined(__IAR_SYSTEMS_ICC__)
218#pragma inline = forced
219#elif defined(__GNUC__)
220__attribute__((always_inline))
221#endif
222static inline uint64_t mbedtls_get_unaligned_uint64(const void *p)
223{
224 uint64_t r;
225#if defined(UINT_UNALIGNED)
226 mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
227 r = *p64;
228#elif defined(UINT_UNALIGNED_STRUCT)
229 mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
230 r = p64->x;
231#else
232 memcpy(&r, p, sizeof(r));
233#endif
234 return r;
235}
236
237/**
238 * Write the unsigned 64 bits integer to the given address, which need not
239 * be aligned.
240 *
241 * \param p pointer to 8 bytes of data
242 * \param x data to write
243 */
244#if defined(__IAR_SYSTEMS_ICC__)
245#pragma inline = forced
246#elif defined(__GNUC__)
247__attribute__((always_inline))
248#endif
249static inline void mbedtls_put_unaligned_uint64(void *p, uint64_t x)
250{
251#if defined(UINT_UNALIGNED)
252 mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
253 *p64 = x;
254#elif defined(UINT_UNALIGNED_STRUCT)
255 mbedtls_uint64_unaligned_t *p64 = (mbedtls_uint64_unaligned_t *) p;
256 p64->x = x;
257#else
258 memcpy(p, &x, sizeof(x));
259#endif
260}
261
262#if defined(MBEDTLS_POP_IAR_LANGUAGE_PRAGMA)
263#pragma language=restore
264#endif
265
266/** Byte Reading Macros
267 *
268 * Given a multi-byte integer \p x, MBEDTLS_BYTE_n retrieves the n-th
269 * byte from x, where byte 0 is the least significant byte.
270 */
271#define MBEDTLS_BYTE_0(x) ((uint8_t) ((x) & 0xff))
272#define MBEDTLS_BYTE_1(x) ((uint8_t) (((x) >> 8) & 0xff))
273#define MBEDTLS_BYTE_2(x) ((uint8_t) (((x) >> 16) & 0xff))
274#define MBEDTLS_BYTE_3(x) ((uint8_t) (((x) >> 24) & 0xff))
275#define MBEDTLS_BYTE_4(x) ((uint8_t) (((x) >> 32) & 0xff))
276#define MBEDTLS_BYTE_5(x) ((uint8_t) (((x) >> 40) & 0xff))
277#define MBEDTLS_BYTE_6(x) ((uint8_t) (((x) >> 48) & 0xff))
278#define MBEDTLS_BYTE_7(x) ((uint8_t) (((x) >> 56) & 0xff))
279
280/*
281 * Detect GCC built-in byteswap routines
282 */
283#if defined(__GNUC__) && !(defined(__TINYC__) && defined(__FreeBSD__))
284#if MBEDTLS_GCC_VERSION >= 40800
285#define MBEDTLS_BSWAP16 __builtin_bswap16
286#endif
287#if MBEDTLS_GCC_VERSION >= 40300
288#define MBEDTLS_BSWAP32 __builtin_bswap32
289#define MBEDTLS_BSWAP64 __builtin_bswap64
290#endif
291#endif /* defined(__GNUC__) */
292
293/*
294 * Detect Clang built-in byteswap routines
295 */
296#if defined(__clang__) && defined(__has_builtin) && !(defined(__TINYC__) && defined(__FreeBSD__))
297#if __has_builtin(__builtin_bswap16) && !defined(MBEDTLS_BSWAP16)
298#define MBEDTLS_BSWAP16 __builtin_bswap16
299#endif /* __has_builtin(__builtin_bswap16) */
300#if __has_builtin(__builtin_bswap32) && !defined(MBEDTLS_BSWAP32)
301#define MBEDTLS_BSWAP32 __builtin_bswap32
302#endif /* __has_builtin(__builtin_bswap32) */
303#if __has_builtin(__builtin_bswap64) && !defined(MBEDTLS_BSWAP64)
304#define MBEDTLS_BSWAP64 __builtin_bswap64
305#endif /* __has_builtin(__builtin_bswap64) */
306#endif /* defined(__clang__) && defined(__has_builtin) */
307
308/*
309 * Detect MSVC built-in byteswap routines
310 */
311#if defined(_MSC_VER)
312#if !defined(MBEDTLS_BSWAP16)
313#define MBEDTLS_BSWAP16 _byteswap_ushort
314#endif
315#if !defined(MBEDTLS_BSWAP32)
316#define MBEDTLS_BSWAP32 _byteswap_ulong
317#endif
318#if !defined(MBEDTLS_BSWAP64)
319#define MBEDTLS_BSWAP64 _byteswap_uint64
320#endif
321#endif /* defined(_MSC_VER) */
322
323/* Detect armcc built-in byteswap routine */
324#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 410000) && !defined(MBEDTLS_BSWAP32)
325#if defined(__ARM_ACLE) /* ARM Compiler 6 - earlier versions don't need a header */
326#include <arm_acle.h>
327#endif
328#define MBEDTLS_BSWAP32 __rev
329#endif
330
331/* Detect IAR built-in byteswap routine */
332#if defined(__IAR_SYSTEMS_ICC__)
333#if defined(__ARM_ACLE)
334#include <arm_acle.h>
335#define MBEDTLS_BSWAP16(x) ((uint16_t) __rev16((uint32_t) (x)))
336#define MBEDTLS_BSWAP32 __rev
337#define MBEDTLS_BSWAP64 __revll
338#endif
339#endif
340
341/*
342 * Where compiler built-ins are not present, fall back to C code that the
343 * compiler may be able to detect and transform into the relevant bswap or
344 * similar instruction.
345 */
346#if !defined(MBEDTLS_BSWAP16)
347static inline uint16_t mbedtls_bswap16(uint16_t x)
348{
349 return
350 (x & 0x00ff) << 8 |
351 (x & 0xff00) >> 8;
352}
353#define MBEDTLS_BSWAP16 mbedtls_bswap16
354#endif /* !defined(MBEDTLS_BSWAP16) */
355
356#if !defined(MBEDTLS_BSWAP32)
357static inline uint32_t mbedtls_bswap32(uint32_t x)
358{
359 return
360 (x & 0x000000ff) << 24 |
361 (x & 0x0000ff00) << 8 |
362 (x & 0x00ff0000) >> 8 |
363 (x & 0xff000000) >> 24;
364}
365#define MBEDTLS_BSWAP32 mbedtls_bswap32
366#endif /* !defined(MBEDTLS_BSWAP32) */
367
368#if !defined(MBEDTLS_BSWAP64)
369static inline uint64_t mbedtls_bswap64(uint64_t x)
370{
371 return
372 (x & 0x00000000000000ffULL) << 56 |
373 (x & 0x000000000000ff00ULL) << 40 |
374 (x & 0x0000000000ff0000ULL) << 24 |
375 (x & 0x00000000ff000000ULL) << 8 |
376 (x & 0x000000ff00000000ULL) >> 8 |
377 (x & 0x0000ff0000000000ULL) >> 24 |
378 (x & 0x00ff000000000000ULL) >> 40 |
379 (x & 0xff00000000000000ULL) >> 56;
380}
381#define MBEDTLS_BSWAP64 mbedtls_bswap64
382#endif /* !defined(MBEDTLS_BSWAP64) */
383
384#if !defined(__BYTE_ORDER__)
385
386#if defined(__LITTLE_ENDIAN__)
387/* IAR defines __xxx_ENDIAN__, but not __BYTE_ORDER__ */
388#define MBEDTLS_IS_BIG_ENDIAN 0
389#elif defined(__BIG_ENDIAN__)
390#define MBEDTLS_IS_BIG_ENDIAN 1
391#else
392static const uint16_t mbedtls_byte_order_detector = { 0x100 };
393#define MBEDTLS_IS_BIG_ENDIAN (*((unsigned char *) (&mbedtls_byte_order_detector)) == 0x01)
394#endif
395
396#else
397
398#if (__BYTE_ORDER__) == (__ORDER_BIG_ENDIAN__)
399#define MBEDTLS_IS_BIG_ENDIAN 1
400#else
401#define MBEDTLS_IS_BIG_ENDIAN 0
402#endif
403
404#endif /* !defined(__BYTE_ORDER__) */
405
406/**
407 * Get the unsigned 32 bits integer corresponding to four bytes in
408 * big-endian order (MSB first).
409 *
410 * \param data Base address of the memory to get the four bytes from.
411 * \param offset Offset from \p data of the first and most significant
412 * byte of the four bytes to build the 32 bits unsigned
413 * integer from.
414 */
415#define MBEDTLS_GET_UINT32_BE(data, offset) \
416 ((MBEDTLS_IS_BIG_ENDIAN) \
417 ? mbedtls_get_unaligned_uint32((data) + (offset)) \
418 : MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \
419 )
420
421/**
422 * Put in memory a 32 bits unsigned integer in big-endian order.
423 *
424 * \param n 32 bits unsigned integer to put in memory.
425 * \param data Base address of the memory where to put the 32
426 * bits unsigned integer in.
427 * \param offset Offset from \p data where to put the most significant
428 * byte of the 32 bits unsigned integer \p n.
429 */
430#define MBEDTLS_PUT_UINT32_BE(n, data, offset) \
431 { \
432 if (MBEDTLS_IS_BIG_ENDIAN) \
433 { \
434 mbedtls_put_unaligned_uint32((data) + (offset), (uint32_t) (n)); \
435 } \
436 else \
437 { \
438 mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t) (n))); \
439 } \
440 }
441
442/**
443 * Get the unsigned 32 bits integer corresponding to four bytes in
444 * little-endian order (LSB first).
445 *
446 * \param data Base address of the memory to get the four bytes from.
447 * \param offset Offset from \p data of the first and least significant
448 * byte of the four bytes to build the 32 bits unsigned
449 * integer from.
450 */
451#define MBEDTLS_GET_UINT32_LE(data, offset) \
452 ((MBEDTLS_IS_BIG_ENDIAN) \
453 ? MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \
454 : mbedtls_get_unaligned_uint32((data) + (offset)) \
455 )
456
457
458/**
459 * Put in memory a 32 bits unsigned integer in little-endian order.
460 *
461 * \param n 32 bits unsigned integer to put in memory.
462 * \param data Base address of the memory where to put the 32
463 * bits unsigned integer in.
464 * \param offset Offset from \p data where to put the least significant
465 * byte of the 32 bits unsigned integer \p n.
466 */
467#define MBEDTLS_PUT_UINT32_LE(n, data, offset) \
468 { \
469 if (MBEDTLS_IS_BIG_ENDIAN) \
470 { \
471 mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t) (n))); \
472 } \
473 else \
474 { \
475 mbedtls_put_unaligned_uint32((data) + (offset), ((uint32_t) (n))); \
476 } \
477 }
478
479/**
480 * Get the unsigned 16 bits integer corresponding to two bytes in
481 * little-endian order (LSB first).
482 *
483 * \param data Base address of the memory to get the two bytes from.
484 * \param offset Offset from \p data of the first and least significant
485 * byte of the two bytes to build the 16 bits unsigned
486 * integer from.
487 */
488#define MBEDTLS_GET_UINT16_LE(data, offset) \
489 ((MBEDTLS_IS_BIG_ENDIAN) \
490 ? MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \
491 : mbedtls_get_unaligned_uint16((data) + (offset)) \
492 )
493
494/**
495 * Put in memory a 16 bits unsigned integer in little-endian order.
496 *
497 * \param n 16 bits unsigned integer to put in memory.
498 * \param data Base address of the memory where to put the 16
499 * bits unsigned integer in.
500 * \param offset Offset from \p data where to put the least significant
501 * byte of the 16 bits unsigned integer \p n.
502 */
503#define MBEDTLS_PUT_UINT16_LE(n, data, offset) \
504 { \
505 if (MBEDTLS_IS_BIG_ENDIAN) \
506 { \
507 mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t) (n))); \
508 } \
509 else \
510 { \
511 mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t) (n)); \
512 } \
513 }
514
515/**
516 * Get the unsigned 16 bits integer corresponding to two bytes in
517 * big-endian order (MSB first).
518 *
519 * \param data Base address of the memory to get the two bytes from.
520 * \param offset Offset from \p data of the first and most significant
521 * byte of the two bytes to build the 16 bits unsigned
522 * integer from.
523 */
524#define MBEDTLS_GET_UINT16_BE(data, offset) \
525 ((MBEDTLS_IS_BIG_ENDIAN) \
526 ? mbedtls_get_unaligned_uint16((data) + (offset)) \
527 : MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \
528 )
529
530/**
531 * Put in memory a 16 bits unsigned integer in big-endian order.
532 *
533 * \param n 16 bits unsigned integer to put in memory.
534 * \param data Base address of the memory where to put the 16
535 * bits unsigned integer in.
536 * \param offset Offset from \p data where to put the most significant
537 * byte of the 16 bits unsigned integer \p n.
538 */
539#define MBEDTLS_PUT_UINT16_BE(n, data, offset) \
540 { \
541 if (MBEDTLS_IS_BIG_ENDIAN) \
542 { \
543 mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t) (n)); \
544 } \
545 else \
546 { \
547 mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t) (n))); \
548 } \
549 }
550
551/**
552 * Get the unsigned 24 bits integer corresponding to three bytes in
553 * big-endian order (MSB first).
554 *
555 * \param data Base address of the memory to get the three bytes from.
556 * \param offset Offset from \p data of the first and most significant
557 * byte of the three bytes to build the 24 bits unsigned
558 * integer from.
559 */
560#define MBEDTLS_GET_UINT24_BE(data, offset) \
561 ( \
562 ((uint32_t) (data)[(offset)] << 16) \
563 | ((uint32_t) (data)[(offset) + 1] << 8) \
564 | ((uint32_t) (data)[(offset) + 2]) \
565 )
566
567/**
568 * Put in memory a 24 bits unsigned integer in big-endian order.
569 *
570 * \param n 24 bits unsigned integer to put in memory.
571 * \param data Base address of the memory where to put the 24
572 * bits unsigned integer in.
573 * \param offset Offset from \p data where to put the most significant
574 * byte of the 24 bits unsigned integer \p n.
575 */
576#define MBEDTLS_PUT_UINT24_BE(n, data, offset) \
577 { \
578 (data)[(offset)] = MBEDTLS_BYTE_2(n); \
579 (data)[(offset) + 1] = MBEDTLS_BYTE_1(n); \
580 (data)[(offset) + 2] = MBEDTLS_BYTE_0(n); \
581 }
582
583/**
584 * Get the unsigned 24 bits integer corresponding to three bytes in
585 * little-endian order (LSB first).
586 *
587 * \param data Base address of the memory to get the three bytes from.
588 * \param offset Offset from \p data of the first and least significant
589 * byte of the three bytes to build the 24 bits unsigned
590 * integer from.
591 */
592#define MBEDTLS_GET_UINT24_LE(data, offset) \
593 ( \
594 ((uint32_t) (data)[(offset)]) \
595 | ((uint32_t) (data)[(offset) + 1] << 8) \
596 | ((uint32_t) (data)[(offset) + 2] << 16) \
597 )
598
599/**
600 * Put in memory a 24 bits unsigned integer in little-endian order.
601 *
602 * \param n 24 bits unsigned integer to put in memory.
603 * \param data Base address of the memory where to put the 24
604 * bits unsigned integer in.
605 * \param offset Offset from \p data where to put the least significant
606 * byte of the 24 bits unsigned integer \p n.
607 */
608#define MBEDTLS_PUT_UINT24_LE(n, data, offset) \
609 { \
610 (data)[(offset)] = MBEDTLS_BYTE_0(n); \
611 (data)[(offset) + 1] = MBEDTLS_BYTE_1(n); \
612 (data)[(offset) + 2] = MBEDTLS_BYTE_2(n); \
613 }
614
615/**
616 * Get the unsigned 64 bits integer corresponding to eight bytes in
617 * big-endian order (MSB first).
618 *
619 * \param data Base address of the memory to get the eight bytes from.
620 * \param offset Offset from \p data of the first and most significant
621 * byte of the eight bytes to build the 64 bits unsigned
622 * integer from.
623 */
624#define MBEDTLS_GET_UINT64_BE(data, offset) \
625 ((MBEDTLS_IS_BIG_ENDIAN) \
626 ? mbedtls_get_unaligned_uint64((data) + (offset)) \
627 : MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \
628 )
629
630/**
631 * Put in memory a 64 bits unsigned integer in big-endian order.
632 *
633 * \param n 64 bits unsigned integer to put in memory.
634 * \param data Base address of the memory where to put the 64
635 * bits unsigned integer in.
636 * \param offset Offset from \p data where to put the most significant
637 * byte of the 64 bits unsigned integer \p n.
638 */
639#define MBEDTLS_PUT_UINT64_BE(n, data, offset) \
640 { \
641 if (MBEDTLS_IS_BIG_ENDIAN) \
642 { \
643 mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t) (n)); \
644 } \
645 else \
646 { \
647 mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t) (n))); \
648 } \
649 }
650
651/**
652 * Get the unsigned 64 bits integer corresponding to eight bytes in
653 * little-endian order (LSB first).
654 *
655 * \param data Base address of the memory to get the eight bytes from.
656 * \param offset Offset from \p data of the first and least significant
657 * byte of the eight bytes to build the 64 bits unsigned
658 * integer from.
659 */
660#define MBEDTLS_GET_UINT64_LE(data, offset) \
661 ((MBEDTLS_IS_BIG_ENDIAN) \
662 ? MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \
663 : mbedtls_get_unaligned_uint64((data) + (offset)) \
664 )
665
666/**
667 * Put in memory a 64 bits unsigned integer in little-endian order.
668 *
669 * \param n 64 bits unsigned integer to put in memory.
670 * \param data Base address of the memory where to put the 64
671 * bits unsigned integer in.
672 * \param offset Offset from \p data where to put the least significant
673 * byte of the 64 bits unsigned integer \p n.
674 */
675#define MBEDTLS_PUT_UINT64_LE(n, data, offset) \
676 { \
677 if (MBEDTLS_IS_BIG_ENDIAN) \
678 { \
679 mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t) (n))); \
680 } \
681 else \
682 { \
683 mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t) (n)); \
684 } \
685 }
686
687#endif /* MBEDTLS_LIBRARY_ALIGNMENT_H */
688