1 /* SPDX-License-Identifier: LGPL-2.1 OR MIT */ 2 /* 3 * stdlib function definitions for NOLIBC 4 * Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu> 5 */ 6 7 #ifndef _NOLIBC_STDLIB_H 8 #define _NOLIBC_STDLIB_H 9 10 #include "std.h" 11 #include "arch.h" 12 #include "types.h" 13 #include "sys.h" 14 15 16 /* Buffer used to store int-to-ASCII conversions. Will only be implemented if 17 * any of the related functions is implemented. The area is large enough to 18 * store "18446744073709551615" or "-9223372036854775808" and the final zero. 19 */ 20 static __attribute__((unused)) char itoa_buffer[21]; 21 22 /* 23 * As much as possible, please keep functions alphabetically sorted. 24 */ 25 26 /* must be exported, as it's used by libgcc for various divide functions */ 27 __attribute__((weak,unused,noreturn,section(".text.nolibc_abort"))) 28 void abort(void) 29 { 30 sys_kill(sys_getpid(), SIGABRT); 31 for (;;); 32 } 33 34 static __attribute__((unused)) 35 long atol(const char *s) 36 { 37 unsigned long ret = 0; 38 unsigned long d; 39 int neg = 0; 40 41 if (*s == '-') { 42 neg = 1; 43 s++; 44 } 45 46 while (1) { 47 d = (*s++) - '0'; 48 if (d > 9) 49 break; 50 ret *= 10; 51 ret += d; 52 } 53 54 return neg ? -ret : ret; 55 } 56 57 static __attribute__((unused)) 58 int atoi(const char *s) 59 { 60 return atol(s); 61 } 62 63 /* Converts the unsigned long integer <in> to its hex representation into 64 * buffer <buffer>, which must be long enough to store the number and the 65 * trailing zero (17 bytes for "ffffffffffffffff" or 9 for "ffffffff"). The 66 * buffer is filled from the first byte, and the number of characters emitted 67 * (not counting the trailing zero) is returned. The function is constructed 68 * in a way to optimize the code size and avoid any divide that could add a 69 * dependency on large external functions. 70 */ 71 static __attribute__((unused)) 72 int utoh_r(unsigned long in, char *buffer) 73 { 74 signed char pos = (~0UL > 0xfffffffful) ? 60 : 28; 75 int digits = 0; 76 int dig; 77 78 do { 79 dig = in >> pos; 80 in -= (uint64_t)dig << pos; 81 pos -= 4; 82 if (dig || digits || pos < 0) { 83 if (dig > 9) 84 dig += 'a' - '0' - 10; 85 buffer[digits++] = '0' + dig; 86 } 87 } while (pos >= 0); 88 89 buffer[digits] = 0; 90 return digits; 91 } 92 93 /* converts unsigned long <in> to an hex string using the static itoa_buffer 94 * and returns the pointer to that string. 95 */ 96 static inline __attribute__((unused)) 97 char *utoh(unsigned long in) 98 { 99 utoh_r(in, itoa_buffer); 100 return itoa_buffer; 101 } 102 103 /* Converts the unsigned long integer <in> to its string representation into 104 * buffer <buffer>, which must be long enough to store the number and the 105 * trailing zero (21 bytes for 18446744073709551615 in 64-bit, 11 for 106 * 4294967295 in 32-bit). The buffer is filled from the first byte, and the 107 * number of characters emitted (not counting the trailing zero) is returned. 108 * The function is constructed in a way to optimize the code size and avoid 109 * any divide that could add a dependency on large external functions. 110 */ 111 static __attribute__((unused)) 112 int utoa_r(unsigned long in, char *buffer) 113 { 114 unsigned long lim; 115 int digits = 0; 116 int pos = (~0UL > 0xfffffffful) ? 19 : 9; 117 int dig; 118 119 do { 120 for (dig = 0, lim = 1; dig < pos; dig++) 121 lim *= 10; 122 123 if (digits || in >= lim || !pos) { 124 for (dig = 0; in >= lim; dig++) 125 in -= lim; 126 buffer[digits++] = '0' + dig; 127 } 128 } while (pos--); 129 130 buffer[digits] = 0; 131 return digits; 132 } 133 134 /* Converts the signed long integer <in> to its string representation into 135 * buffer <buffer>, which must be long enough to store the number and the 136 * trailing zero (21 bytes for -9223372036854775808 in 64-bit, 12 for 137 * -2147483648 in 32-bit). The buffer is filled from the first byte, and the 138 * number of characters emitted (not counting the trailing zero) is returned. 139 */ 140 static __attribute__((unused)) 141 int itoa_r(long in, char *buffer) 142 { 143 char *ptr = buffer; 144 int len = 0; 145 146 if (in < 0) { 147 in = -in; 148 *(ptr++) = '-'; 149 len++; 150 } 151 len += utoa_r(in, ptr); 152 return len; 153 } 154 155 /* for historical compatibility, same as above but returns the pointer to the 156 * buffer. 157 */ 158 static inline __attribute__((unused)) 159 char *ltoa_r(long in, char *buffer) 160 { 161 itoa_r(in, buffer); 162 return buffer; 163 } 164 165 /* converts long integer <in> to a string using the static itoa_buffer and 166 * returns the pointer to that string. 167 */ 168 static inline __attribute__((unused)) 169 char *itoa(long in) 170 { 171 itoa_r(in, itoa_buffer); 172 return itoa_buffer; 173 } 174 175 /* converts long integer <in> to a string using the static itoa_buffer and 176 * returns the pointer to that string. Same as above, for compatibility. 177 */ 178 static inline __attribute__((unused)) 179 char *ltoa(long in) 180 { 181 itoa_r(in, itoa_buffer); 182 return itoa_buffer; 183 } 184 185 /* converts unsigned long integer <in> to a string using the static itoa_buffer 186 * and returns the pointer to that string. 187 */ 188 static inline __attribute__((unused)) 189 char *utoa(unsigned long in) 190 { 191 utoa_r(in, itoa_buffer); 192 return itoa_buffer; 193 } 194 195 /* Converts the unsigned 64-bit integer <in> to its hex representation into 196 * buffer <buffer>, which must be long enough to store the number and the 197 * trailing zero (17 bytes for "ffffffffffffffff"). The buffer is filled from 198 * the first byte, and the number of characters emitted (not counting the 199 * trailing zero) is returned. The function is constructed in a way to optimize 200 * the code size and avoid any divide that could add a dependency on large 201 * external functions. 202 */ 203 static __attribute__((unused)) 204 int u64toh_r(uint64_t in, char *buffer) 205 { 206 signed char pos = 60; 207 int digits = 0; 208 int dig; 209 210 do { 211 if (sizeof(long) >= 8) { 212 dig = (in >> pos) & 0xF; 213 } else { 214 /* 32-bit platforms: avoid a 64-bit shift */ 215 uint32_t d = (pos >= 32) ? (in >> 32) : in; 216 dig = (d >> (pos & 31)) & 0xF; 217 } 218 if (dig > 9) 219 dig += 'a' - '0' - 10; 220 pos -= 4; 221 if (dig || digits || pos < 0) 222 buffer[digits++] = '0' + dig; 223 } while (pos >= 0); 224 225 buffer[digits] = 0; 226 return digits; 227 } 228 229 /* converts uint64_t <in> to an hex string using the static itoa_buffer and 230 * returns the pointer to that string. 231 */ 232 static inline __attribute__((unused)) 233 char *u64toh(uint64_t in) 234 { 235 u64toh_r(in, itoa_buffer); 236 return itoa_buffer; 237 } 238 239 /* Converts the unsigned 64-bit integer <in> to its string representation into 240 * buffer <buffer>, which must be long enough to store the number and the 241 * trailing zero (21 bytes for 18446744073709551615). The buffer is filled from 242 * the first byte, and the number of characters emitted (not counting the 243 * trailing zero) is returned. The function is constructed in a way to optimize 244 * the code size and avoid any divide that could add a dependency on large 245 * external functions. 246 */ 247 static __attribute__((unused)) 248 int u64toa_r(uint64_t in, char *buffer) 249 { 250 unsigned long long lim; 251 int digits = 0; 252 int pos = 19; /* start with the highest possible digit */ 253 int dig; 254 255 do { 256 for (dig = 0, lim = 1; dig < pos; dig++) 257 lim *= 10; 258 259 if (digits || in >= lim || !pos) { 260 for (dig = 0; in >= lim; dig++) 261 in -= lim; 262 buffer[digits++] = '0' + dig; 263 } 264 } while (pos--); 265 266 buffer[digits] = 0; 267 return digits; 268 } 269 270 /* Converts the signed 64-bit integer <in> to its string representation into 271 * buffer <buffer>, which must be long enough to store the number and the 272 * trailing zero (21 bytes for -9223372036854775808). The buffer is filled from 273 * the first byte, and the number of characters emitted (not counting the 274 * trailing zero) is returned. 275 */ 276 static __attribute__((unused)) 277 int i64toa_r(int64_t in, char *buffer) 278 { 279 char *ptr = buffer; 280 int len = 0; 281 282 if (in < 0) { 283 in = -in; 284 *(ptr++) = '-'; 285 len++; 286 } 287 len += u64toa_r(in, ptr); 288 return len; 289 } 290 291 /* converts int64_t <in> to a string using the static itoa_buffer and returns 292 * the pointer to that string. 293 */ 294 static inline __attribute__((unused)) 295 char *i64toa(int64_t in) 296 { 297 i64toa_r(in, itoa_buffer); 298 return itoa_buffer; 299 } 300 301 /* converts uint64_t <in> to a string using the static itoa_buffer and returns 302 * the pointer to that string. 303 */ 304 static inline __attribute__((unused)) 305 char *u64toa(uint64_t in) 306 { 307 u64toa_r(in, itoa_buffer); 308 return itoa_buffer; 309 } 310 311 #endif /* _NOLIBC_STDLIB_H */ 312