Coverage Report

Created: 2024-05-15 07:13

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