xref: /freebsd/crypto/libecc/include/libecc/words/types.h (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
1 /*
2  *  Copyright (C) 2017 - This file is part of libecc project
3  *
4  *  Authors:
5  *      Ryad BENADJILA <ryadbenadjila@gmail.com>
6  *      Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7  *      Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr>
8  *
9  *  Contributors:
10  *      Nicolas VIVET <nicolas.vivet@ssi.gouv.fr>
11  *      Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr>
12  *
13  *  This software is licensed under a dual BSD and GPL v2 license.
14  *  See LICENSE file at the root folder of the project.
15  */
16 #ifndef __TYPES_H__
17 #define __TYPES_H__
18 
19 /*** Handling the target compiler and its specificities ***/
20 #ifdef __GNUC__
21 /* gcc and clang */
22 #define ATTRIBUTE_UNUSED __attribute__((unused))
23 #define ATTRIBUTE_USED __attribute__((used))
24 #define ATTRIBUTE_PACKED __attribute__((packed))
25 #define ATTRIBUTE_SECTION(a) __attribute__((__section__((a))))
26 #ifdef USE_WARN_UNUSED_RET
27   #define ATTRIBUTE_WARN_UNUSED_RET __attribute__((warn_unused_result))
ignore_result(int unused_result)28   static inline void ignore_result(int unused_result) {
29     (void) unused_result;
30   }
31   /* NOTE: this trick using a dummy function call is here
32    * to explicitly avoid "unused return values" when we know
33    * what we are doing!
34    */
35   #define IGNORE_RET_VAL(a) ignore_result((int)(a))
36 #else
37   #define ATTRIBUTE_WARN_UNUSED_RET
38   #define IGNORE_RET_VAL(a) (a)
39 #endif /* USE_WARN_UNUSED_RET */
40 #else
41 #define ATTRIBUTE_UNUSED
42 #define ATTRIBUTE_USED
43 #define ATTRIBUTE_PACKED
44 #define ATTRIBUTE_SECTION(a)
45 #define ATTRIBUTE_WARN_UNUSED_RET
46 #define IGNORE_RET_VAL(a) (a)
47 #endif
48 
49 /* Macro to trick the compiler of thinking a variable is used.
50  * Although this should not happen, sometimes because of #define
51  * oddities we might force this.
52  */
53 #define FORCE_USED_VAR(a) ((void)(a))
54 
55 /*** Handling the types ****/
56 #ifdef WITH_STDLIB
57 
58 /*
59  * User explicitly needs to build w/ stdlib. Let's include the headers
60  * we need to get basic types: (uint*_t), NULL, etc. You can see below
61  * (i.e. under #else) what is precisely needed.
62  */
63 #include <stdint.h>
64 #include <inttypes.h>
65 #include <stddef.h>
66 #else /* WITH_STDLIB */
67 
68 /*
69  * User does not want to build w/ stdlib. Let's define basic types:
70  * (uint*_t), NULL, etc.
71  */
72 #define NULL ((void *)0)
73 typedef unsigned int size_t;
74 typedef int ssize_t;
75 /* Here is the big picture of the main programming models
76  * and their primitive types sizes in bits:
77  * (see http://www.unix.org/whitepapers/64bit.html)
78  *
79  *           | LP32 | ILP32 | LLP64 | ILP64 | LP64 |
80  *           ---------------------------------------
81  *  char     |   8  |   8   |   8   |   8   |   8  |
82  *  short    |  16  |  16   |  16   |  16   |  16  |
83  *  int      |  16  |  32   |  32   |  64   |  32  |
84  *  long     |  32  |  32   |  32   |  64   |  64  |
85  *  long long|  64  |  64   |  64   |  64   |  64  |
86  *           --------------------------------------
87  *           (long long type existence depends on the C compiler
88  *	      but should be *mandatory* in C99 compliant ones)
89  *
90  * This means that:
91  *	1) We are sure that long long are 64-bit, short are 16-bit,
92  *	   and char are 8-bit (on the vast majority of platforms).
93  *	2) The two types that are not consistent across platforms are
94  *	the int and long types (e.g., int is 16 bits and long is 32 bits
95  *	on msp430-gcc LP32, while int is 32 bits and long is 32 bits
96  *	on x86_64 Linux platforms LLP64, and long becomes 64 bits on
97  *	x86_64 Windows platforms LP64).
98  *
99  * Hence, we take a wild guess for uint32_t mapping on a primitive type
100  * and check this at compilation time using the check_data_types 'union'
101  * defined below.
102  * Our guess depends on the WORDSIZE the user provides us, since we assume
103  * this corresponds to a 'native' word size of the platform (8-bit platforms
104  * such as AVR and 16-bit platforms such as MSP430 are either LP32 and ILP32,
105  * which means that a 'long' type will be mapped to a 32 bits native type).
106  * Consequently, when the user provides us a WORDSIZE=16, we infer that
107  * uint32_t is mapped on a long type.
108  *
109  */
110 typedef unsigned long long uint64_t;
111 /* GCC defines the size of an int, use this information
112  * if it is provided
113  */
114 #ifdef __SIZEOF_INT__
115 #if(__SIZEOF_INT__ == 2)
116 #define UINT32_IS_LONG /* This will be useful for print formatting */
117 typedef unsigned long uint32_t;
118 #else
119 typedef unsigned int uint32_t;
120 #endif /* (__SIZEOF_INT__ == 2) */
121 #else
122 #if(WORDSIZE == 16)
123 /* The user has provided WORDSIZE=16, so we guess that
124  * we have LP32 or ILP32: a long type would be 32-bit.
125  */
126 #define UINT32_IS_LONG /* This will be useful for print formatting */
127 typedef unsigned long uint32_t;
128 #else
129 /* Wild guess for uint32_t mapping */
130 typedef unsigned int uint32_t;
131 #endif /* (WORDSIZE == 16) */
132 #endif /* __SIZEOF_INT__ */
133 typedef unsigned short uint16_t;
134 typedef unsigned char uint8_t;
135 /* Useful macros for our new defined types */
136 #define UINT8_MAX  (0xff)
137 #define UINT16_MAX (0xffff)
138 #define UINT32_MAX (0xffffffff)
139 #define UINT64_MAX (0xffffffffffffffffULL)
140 #define UINT8_C(c) ((uint8_t)(c ## UL))
141 #define UINT16_C(c) ((uint16_t)(c ## UL))
142 #define UINT32_C(c) ((uint32_t)(c ## UL))
143 #define UINT64_C(c) (c ## ULL)
144 
145 /* Sanity check on our guess for primitive types sizes.
146  * See https://barrgroup.com/Embedded-Systems/How-To/C-Fixed-Width-Integers-C99
147  *
148  * TODO: if you get a compilation error at this point, this means that we failed
149  * at guessing the C primitive types sizes for the current platform. You should
150  * try to adapt the uint8_t/uint16_t/uint32_t/uint64_t types definitions in this
151  * file, or find the C99 compliant stdint headers for your compiler/platform
152  * and include it.
153  */
154 typedef union {
155 	char uint8_t_incorrect[sizeof(uint8_t) == 1 ? 1 : -1];
156 	char uint16_t_incorrect[sizeof(uint16_t) == 2 ? 1 : -1];
157 	char uint32_t_incorrect[sizeof(uint32_t) == 4 ? 1 : -1];
158 	char uint64_t_incorrect[sizeof(uint64_t) == 8 ? 1 : -1];
159 } check_data_types;
160 
161 #endif /* WITH_STDLIB */
162 
163 #endif /* __TYPES_H__ */
164