xref: /third_party/mbedtls/library/alignment.h (revision a8e1175b)
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(MBEDTLS_ARCH_IS_X86) || defined(MBEDTLS_ARCH_IS_X64) \
27    || defined(MBEDTLS_PLATFORM_IS_WINDOWS_ON_ARM64)
28/*
29 * __ARM_FEATURE_UNALIGNED is defined where appropriate by armcc, gcc 7, clang 9
30 * (and later versions) for Arm v7 and later; all x86 platforms should have
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).
36 */
37#define MBEDTLS_EFFICIENT_UNALIGNED_ACCESS
38#endif
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
52typedef uint16_t __packed mbedtls_uint16_unaligned_t;
53typedef uint32_t __packed mbedtls_uint32_unaligned_t;
54typedef 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
86typedef struct {
87    uint16_t x;
88} __attribute__((packed)) mbedtls_uint16_unaligned_t;
89typedef struct {
90    uint32_t x;
91} __attribute__((packed)) mbedtls_uint32_unaligned_t;
92typedef 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
103/**
104 * Read the unsigned 16 bits integer from the given address, which need not
105 * be aligned.
106 *
107 * \param   p pointer to 2 bytes of data
108 * \return  Data at the given address
109 */
110uint16_t mbedtls_get_unaligned_uint16(const void *p);
111
112/**
113 * Write the unsigned 16 bits integer to the given address, which need not
114 * be aligned.
115 *
116 * \param   p pointer to 2 bytes of data
117 * \param   x data to write
118 */
119void mbedtls_put_unaligned_uint16(void *p, uint16_t x);
120
121/**
122 * Read the unsigned 32 bits integer from the given address, which need not
123 * be aligned.
124 *
125 * \param   p pointer to 4 bytes of data
126 * \return  Data at the given address
127 */
128uint32_t mbedtls_get_unaligned_uint32(const void *p);
129
130/**
131 * Write the unsigned 32 bits integer to the given address, which need not
132 * be aligned.
133 *
134 * \param   p pointer to 4 bytes of data
135 * \param   x data to write
136 */
137void mbedtls_put_unaligned_uint32(void *p, uint32_t x);
138
139/**
140 * Read the unsigned 64 bits integer from the given address, which need not
141 * be aligned.
142 *
143 * \param   p pointer to 8 bytes of data
144 * \return  Data at the given address
145 */
146uint64_t mbedtls_get_unaligned_uint64(const void *p);
147
148/**
149 * Write the unsigned 64 bits integer to the given address, which need not
150 * be aligned.
151 *
152 * \param   p pointer to 8 bytes of data
153 * \param   x data to write
154 */
155void mbedtls_put_unaligned_uint64(void *p, uint64_t x);
156#if defined(MBEDTLS_POP_IAR_LANGUAGE_PRAGMA)
157#pragma language=restore
158#endif
159
160/** Byte Reading Macros
161 *
162 * Given a multi-byte integer \p x, MBEDTLS_BYTE_n retrieves the n-th
163 * byte from x, where byte 0 is the least significant byte.
164 */
165#define MBEDTLS_BYTE_0(x) ((uint8_t) ((x)         & 0xff))
166#define MBEDTLS_BYTE_1(x) ((uint8_t) (((x) >>  8) & 0xff))
167#define MBEDTLS_BYTE_2(x) ((uint8_t) (((x) >> 16) & 0xff))
168#define MBEDTLS_BYTE_3(x) ((uint8_t) (((x) >> 24) & 0xff))
169#define MBEDTLS_BYTE_4(x) ((uint8_t) (((x) >> 32) & 0xff))
170#define MBEDTLS_BYTE_5(x) ((uint8_t) (((x) >> 40) & 0xff))
171#define MBEDTLS_BYTE_6(x) ((uint8_t) (((x) >> 48) & 0xff))
172#define MBEDTLS_BYTE_7(x) ((uint8_t) (((x) >> 56) & 0xff))
173
174/*
175 * Detect GCC built-in byteswap routines
176 */
177#if defined(__GNUC__) && defined(__GNUC_PREREQ)
178#if __GNUC_PREREQ(4, 8)
179#define MBEDTLS_BSWAP16 __builtin_bswap16
180#endif /* __GNUC_PREREQ(4,8) */
181#if __GNUC_PREREQ(4, 3)
182#define MBEDTLS_BSWAP32 __builtin_bswap32
183#define MBEDTLS_BSWAP64 __builtin_bswap64
184#endif /* __GNUC_PREREQ(4,3) */
185#endif /* defined(__GNUC__) && defined(__GNUC_PREREQ) */
186
187/*
188 * Detect Clang built-in byteswap routines
189 */
190#if defined(__clang__) && defined(__has_builtin)
191#if __has_builtin(__builtin_bswap16) && !defined(MBEDTLS_BSWAP16)
192#define MBEDTLS_BSWAP16 __builtin_bswap16
193#endif /* __has_builtin(__builtin_bswap16) */
194#if __has_builtin(__builtin_bswap32) && !defined(MBEDTLS_BSWAP32)
195#define MBEDTLS_BSWAP32 __builtin_bswap32
196#endif /* __has_builtin(__builtin_bswap32) */
197#if __has_builtin(__builtin_bswap64) && !defined(MBEDTLS_BSWAP64)
198#define MBEDTLS_BSWAP64 __builtin_bswap64
199#endif /* __has_builtin(__builtin_bswap64) */
200#endif /* defined(__clang__) && defined(__has_builtin) */
201
202/*
203 * Detect MSVC built-in byteswap routines
204 */
205#if defined(_MSC_VER)
206#if !defined(MBEDTLS_BSWAP16)
207#define MBEDTLS_BSWAP16 _byteswap_ushort
208#endif
209#if !defined(MBEDTLS_BSWAP32)
210#define MBEDTLS_BSWAP32 _byteswap_ulong
211#endif
212#if !defined(MBEDTLS_BSWAP64)
213#define MBEDTLS_BSWAP64 _byteswap_uint64
214#endif
215#endif /* defined(_MSC_VER) */
216
217/* Detect armcc built-in byteswap routine */
218#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 410000) && !defined(MBEDTLS_BSWAP32)
219#if defined(__ARM_ACLE)  /* ARM Compiler 6 - earlier versions don't need a header */
220#include <arm_acle.h>
221#endif
222#define MBEDTLS_BSWAP32 __rev
223#endif
224
225/* Detect IAR built-in byteswap routine */
226#if defined(__IAR_SYSTEMS_ICC__)
227#if defined(__ARM_ACLE)
228#include <arm_acle.h>
229#define MBEDTLS_BSWAP16(x) ((uint16_t) __rev16((uint32_t) (x)))
230#define MBEDTLS_BSWAP32 __rev
231#define MBEDTLS_BSWAP64 __revll
232#endif
233#endif
234
235/*
236 * Where compiler built-ins are not present, fall back to C code that the
237 * compiler may be able to detect and transform into the relevant bswap or
238 * similar instruction.
239 */
240#if !defined(MBEDTLS_BSWAP16)
241static inline uint16_t mbedtls_bswap16(uint16_t x)
242{
243    return
244        (x & 0x00ff) << 8 |
245        (x & 0xff00) >> 8;
246}
247#define MBEDTLS_BSWAP16 mbedtls_bswap16
248#endif /* !defined(MBEDTLS_BSWAP16) */
249
250#if !defined(MBEDTLS_BSWAP32)
251static inline uint32_t mbedtls_bswap32(uint32_t x)
252{
253    return
254        (x & 0x000000ff) << 24 |
255        (x & 0x0000ff00) <<  8 |
256        (x & 0x00ff0000) >>  8 |
257        (x & 0xff000000) >> 24;
258}
259#define MBEDTLS_BSWAP32 mbedtls_bswap32
260#endif /* !defined(MBEDTLS_BSWAP32) */
261
262#if !defined(MBEDTLS_BSWAP64)
263static inline uint64_t mbedtls_bswap64(uint64_t x)
264{
265    return
266        (x & 0x00000000000000ffULL) << 56 |
267        (x & 0x000000000000ff00ULL) << 40 |
268        (x & 0x0000000000ff0000ULL) << 24 |
269        (x & 0x00000000ff000000ULL) <<  8 |
270        (x & 0x000000ff00000000ULL) >>  8 |
271        (x & 0x0000ff0000000000ULL) >> 24 |
272        (x & 0x00ff000000000000ULL) >> 40 |
273        (x & 0xff00000000000000ULL) >> 56;
274}
275#define MBEDTLS_BSWAP64 mbedtls_bswap64
276#endif /* !defined(MBEDTLS_BSWAP64) */
277
278#if !defined(__BYTE_ORDER__)
279
280#if defined(__LITTLE_ENDIAN__)
281/* IAR defines __xxx_ENDIAN__, but not __BYTE_ORDER__ */
282#define MBEDTLS_IS_BIG_ENDIAN 0
283#elif defined(__BIG_ENDIAN__)
284#define MBEDTLS_IS_BIG_ENDIAN 1
285#else
286static const uint16_t mbedtls_byte_order_detector = { 0x100 };
287#define MBEDTLS_IS_BIG_ENDIAN (*((unsigned char *) (&mbedtls_byte_order_detector)) == 0x01)
288#endif
289
290#else
291
292#if (__BYTE_ORDER__) == (__ORDER_BIG_ENDIAN__)
293#define MBEDTLS_IS_BIG_ENDIAN 1
294#else
295#define MBEDTLS_IS_BIG_ENDIAN 0
296#endif
297
298#endif /* !defined(__BYTE_ORDER__) */
299
300/**
301 * Get the unsigned 32 bits integer corresponding to four bytes in
302 * big-endian order (MSB first).
303 *
304 * \param   data    Base address of the memory to get the four bytes from.
305 * \param   offset  Offset from \p data of the first and most significant
306 *                  byte of the four bytes to build the 32 bits unsigned
307 *                  integer from.
308 */
309#define MBEDTLS_GET_UINT32_BE(data, offset)                                \
310    ((MBEDTLS_IS_BIG_ENDIAN)                                               \
311        ? mbedtls_get_unaligned_uint32((data) + (offset))                  \
312        : MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \
313    )
314
315/**
316 * Put in memory a 32 bits unsigned integer in big-endian order.
317 *
318 * \param   n       32 bits unsigned integer to put in memory.
319 * \param   data    Base address of the memory where to put the 32
320 *                  bits unsigned integer in.
321 * \param   offset  Offset from \p data where to put the most significant
322 *                  byte of the 32 bits unsigned integer \p n.
323 */
324#define MBEDTLS_PUT_UINT32_BE(n, data, offset)                                   \
325    {                                                                            \
326        if (MBEDTLS_IS_BIG_ENDIAN)                                               \
327        {                                                                        \
328            mbedtls_put_unaligned_uint32((data) + (offset), (uint32_t) (n));     \
329        }                                                                        \
330        else                                                                     \
331        {                                                                        \
332            mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t) (n))); \
333        }                                                                        \
334    }
335
336/**
337 * Get the unsigned 32 bits integer corresponding to four bytes in
338 * little-endian order (LSB first).
339 *
340 * \param   data    Base address of the memory to get the four bytes from.
341 * \param   offset  Offset from \p data of the first and least significant
342 *                  byte of the four bytes to build the 32 bits unsigned
343 *                  integer from.
344 */
345#define MBEDTLS_GET_UINT32_LE(data, offset)                                \
346    ((MBEDTLS_IS_BIG_ENDIAN)                                               \
347        ? MBEDTLS_BSWAP32(mbedtls_get_unaligned_uint32((data) + (offset))) \
348        : mbedtls_get_unaligned_uint32((data) + (offset))                  \
349    )
350
351
352/**
353 * Put in memory a 32 bits unsigned integer in little-endian order.
354 *
355 * \param   n       32 bits unsigned integer to put in memory.
356 * \param   data    Base address of the memory where to put the 32
357 *                  bits unsigned integer in.
358 * \param   offset  Offset from \p data where to put the least significant
359 *                  byte of the 32 bits unsigned integer \p n.
360 */
361#define MBEDTLS_PUT_UINT32_LE(n, data, offset)                                   \
362    {                                                                            \
363        if (MBEDTLS_IS_BIG_ENDIAN)                                               \
364        {                                                                        \
365            mbedtls_put_unaligned_uint32((data) + (offset), MBEDTLS_BSWAP32((uint32_t) (n))); \
366        }                                                                        \
367        else                                                                     \
368        {                                                                        \
369            mbedtls_put_unaligned_uint32((data) + (offset), ((uint32_t) (n)));   \
370        }                                                                        \
371    }
372
373/**
374 * Get the unsigned 16 bits integer corresponding to two bytes in
375 * little-endian order (LSB first).
376 *
377 * \param   data    Base address of the memory to get the two bytes from.
378 * \param   offset  Offset from \p data of the first and least significant
379 *                  byte of the two bytes to build the 16 bits unsigned
380 *                  integer from.
381 */
382#define MBEDTLS_GET_UINT16_LE(data, offset)                                \
383    ((MBEDTLS_IS_BIG_ENDIAN)                                               \
384        ? MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \
385        : mbedtls_get_unaligned_uint16((data) + (offset))                  \
386    )
387
388/**
389 * Put in memory a 16 bits unsigned integer in little-endian order.
390 *
391 * \param   n       16 bits unsigned integer to put in memory.
392 * \param   data    Base address of the memory where to put the 16
393 *                  bits unsigned integer in.
394 * \param   offset  Offset from \p data where to put the least significant
395 *                  byte of the 16 bits unsigned integer \p n.
396 */
397#define MBEDTLS_PUT_UINT16_LE(n, data, offset)                                   \
398    {                                                                            \
399        if (MBEDTLS_IS_BIG_ENDIAN)                                               \
400        {                                                                        \
401            mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t) (n))); \
402        }                                                                        \
403        else                                                                     \
404        {                                                                        \
405            mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t) (n));     \
406        }                                                                        \
407    }
408
409/**
410 * Get the unsigned 16 bits integer corresponding to two bytes in
411 * big-endian order (MSB first).
412 *
413 * \param   data    Base address of the memory to get the two bytes from.
414 * \param   offset  Offset from \p data of the first and most significant
415 *                  byte of the two bytes to build the 16 bits unsigned
416 *                  integer from.
417 */
418#define MBEDTLS_GET_UINT16_BE(data, offset)                                \
419    ((MBEDTLS_IS_BIG_ENDIAN)                                               \
420        ? mbedtls_get_unaligned_uint16((data) + (offset))                  \
421        : MBEDTLS_BSWAP16(mbedtls_get_unaligned_uint16((data) + (offset))) \
422    )
423
424/**
425 * Put in memory a 16 bits unsigned integer in big-endian order.
426 *
427 * \param   n       16 bits unsigned integer to put in memory.
428 * \param   data    Base address of the memory where to put the 16
429 *                  bits unsigned integer in.
430 * \param   offset  Offset from \p data where to put the most significant
431 *                  byte of the 16 bits unsigned integer \p n.
432 */
433#define MBEDTLS_PUT_UINT16_BE(n, data, offset)                                   \
434    {                                                                            \
435        if (MBEDTLS_IS_BIG_ENDIAN)                                               \
436        {                                                                        \
437            mbedtls_put_unaligned_uint16((data) + (offset), (uint16_t) (n));     \
438        }                                                                        \
439        else                                                                     \
440        {                                                                        \
441            mbedtls_put_unaligned_uint16((data) + (offset), MBEDTLS_BSWAP16((uint16_t) (n))); \
442        }                                                                        \
443    }
444
445/**
446 * Get the unsigned 24 bits integer corresponding to three bytes in
447 * big-endian order (MSB first).
448 *
449 * \param   data    Base address of the memory to get the three bytes from.
450 * \param   offset  Offset from \p data of the first and most significant
451 *                  byte of the three bytes to build the 24 bits unsigned
452 *                  integer from.
453 */
454#define MBEDTLS_GET_UINT24_BE(data, offset)        \
455    (                                              \
456        ((uint32_t) (data)[(offset)] << 16)        \
457        | ((uint32_t) (data)[(offset) + 1] << 8)   \
458        | ((uint32_t) (data)[(offset) + 2])        \
459    )
460
461/**
462 * Put in memory a 24 bits unsigned integer in big-endian order.
463 *
464 * \param   n       24 bits unsigned integer to put in memory.
465 * \param   data    Base address of the memory where to put the 24
466 *                  bits unsigned integer in.
467 * \param   offset  Offset from \p data where to put the most significant
468 *                  byte of the 24 bits unsigned integer \p n.
469 */
470#define MBEDTLS_PUT_UINT24_BE(n, data, offset)                \
471    {                                                         \
472        (data)[(offset)] = MBEDTLS_BYTE_2(n);                 \
473        (data)[(offset) + 1] = MBEDTLS_BYTE_1(n);             \
474        (data)[(offset) + 2] = MBEDTLS_BYTE_0(n);             \
475    }
476
477/**
478 * Get the unsigned 24 bits integer corresponding to three bytes in
479 * little-endian order (LSB first).
480 *
481 * \param   data    Base address of the memory to get the three bytes from.
482 * \param   offset  Offset from \p data of the first and least significant
483 *                  byte of the three bytes to build the 24 bits unsigned
484 *                  integer from.
485 */
486#define MBEDTLS_GET_UINT24_LE(data, offset)               \
487    (                                                     \
488        ((uint32_t) (data)[(offset)])                     \
489        | ((uint32_t) (data)[(offset) + 1] <<  8)         \
490        | ((uint32_t) (data)[(offset) + 2] << 16)         \
491    )
492
493/**
494 * Put in memory a 24 bits unsigned integer in little-endian order.
495 *
496 * \param   n       24 bits unsigned integer to put in memory.
497 * \param   data    Base address of the memory where to put the 24
498 *                  bits unsigned integer in.
499 * \param   offset  Offset from \p data where to put the least significant
500 *                  byte of the 24 bits unsigned integer \p n.
501 */
502#define MBEDTLS_PUT_UINT24_LE(n, data, offset)                \
503    {                                                         \
504        (data)[(offset)] = MBEDTLS_BYTE_0(n);                 \
505        (data)[(offset) + 1] = MBEDTLS_BYTE_1(n);             \
506        (data)[(offset) + 2] = MBEDTLS_BYTE_2(n);             \
507    }
508
509/**
510 * Get the unsigned 64 bits integer corresponding to eight bytes in
511 * big-endian order (MSB first).
512 *
513 * \param   data    Base address of the memory to get the eight bytes from.
514 * \param   offset  Offset from \p data of the first and most significant
515 *                  byte of the eight bytes to build the 64 bits unsigned
516 *                  integer from.
517 */
518#define MBEDTLS_GET_UINT64_BE(data, offset)                                \
519    ((MBEDTLS_IS_BIG_ENDIAN)                                               \
520        ? mbedtls_get_unaligned_uint64((data) + (offset))                  \
521        : MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \
522    )
523
524/**
525 * Put in memory a 64 bits unsigned integer in big-endian order.
526 *
527 * \param   n       64 bits unsigned integer to put in memory.
528 * \param   data    Base address of the memory where to put the 64
529 *                  bits unsigned integer in.
530 * \param   offset  Offset from \p data where to put the most significant
531 *                  byte of the 64 bits unsigned integer \p n.
532 */
533#define MBEDTLS_PUT_UINT64_BE(n, data, offset)                                   \
534    {                                                                            \
535        if (MBEDTLS_IS_BIG_ENDIAN)                                               \
536        {                                                                        \
537            mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t) (n));     \
538        }                                                                        \
539        else                                                                     \
540        {                                                                        \
541            mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t) (n))); \
542        }                                                                        \
543    }
544
545/**
546 * Get the unsigned 64 bits integer corresponding to eight bytes in
547 * little-endian order (LSB first).
548 *
549 * \param   data    Base address of the memory to get the eight bytes from.
550 * \param   offset  Offset from \p data of the first and least significant
551 *                  byte of the eight bytes to build the 64 bits unsigned
552 *                  integer from.
553 */
554#define MBEDTLS_GET_UINT64_LE(data, offset)                                \
555    ((MBEDTLS_IS_BIG_ENDIAN)                                               \
556        ? MBEDTLS_BSWAP64(mbedtls_get_unaligned_uint64((data) + (offset))) \
557        : mbedtls_get_unaligned_uint64((data) + (offset))                  \
558    )
559
560/**
561 * Put in memory a 64 bits unsigned integer in little-endian order.
562 *
563 * \param   n       64 bits unsigned integer to put in memory.
564 * \param   data    Base address of the memory where to put the 64
565 *                  bits unsigned integer in.
566 * \param   offset  Offset from \p data where to put the least significant
567 *                  byte of the 64 bits unsigned integer \p n.
568 */
569#define MBEDTLS_PUT_UINT64_LE(n, data, offset)                                   \
570    {                                                                            \
571        if (MBEDTLS_IS_BIG_ENDIAN)                                               \
572        {                                                                        \
573            mbedtls_put_unaligned_uint64((data) + (offset), MBEDTLS_BSWAP64((uint64_t) (n))); \
574        }                                                                        \
575        else                                                                     \
576        {                                                                        \
577            mbedtls_put_unaligned_uint64((data) + (offset), (uint64_t) (n));     \
578        }                                                                        \
579    }
580
581#endif /* MBEDTLS_LIBRARY_ALIGNMENT_H */
582