Some functions like raise() and memcpy() are permanently exported because they're needed by libgcc on certain platforms. However most of the time they are not needed and needlessly take space. Let's move them to their own sub-section, called .text.nolibc_<function>. This allows ld to get rid of them if unused when passed --gc-sections. Signed-off-by: Willy Tarreau <w@1wt.eu> Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
340 lines
8.4 KiB
C
340 lines
8.4 KiB
C
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
|
/*
|
|
* stdlib function definitions for NOLIBC
|
|
* Copyright (C) 2017-2021 Willy Tarreau <w@1wt.eu>
|
|
*/
|
|
|
|
#ifndef _NOLIBC_STDLIB_H
|
|
#define _NOLIBC_STDLIB_H
|
|
|
|
#include "std.h"
|
|
#include "arch.h"
|
|
#include "types.h"
|
|
#include "sys.h"
|
|
|
|
|
|
/* Buffer used to store int-to-ASCII conversions. Will only be implemented if
|
|
* any of the related functions is implemented. The area is large enough to
|
|
* store "18446744073709551615" or "-9223372036854775808" and the final zero.
|
|
*/
|
|
static __attribute__((unused)) char itoa_buffer[21];
|
|
|
|
/*
|
|
* As much as possible, please keep functions alphabetically sorted.
|
|
*/
|
|
|
|
static __attribute__((unused))
|
|
long atol(const char *s)
|
|
{
|
|
unsigned long ret = 0;
|
|
unsigned long d;
|
|
int neg = 0;
|
|
|
|
if (*s == '-') {
|
|
neg = 1;
|
|
s++;
|
|
}
|
|
|
|
while (1) {
|
|
d = (*s++) - '0';
|
|
if (d > 9)
|
|
break;
|
|
ret *= 10;
|
|
ret += d;
|
|
}
|
|
|
|
return neg ? -ret : ret;
|
|
}
|
|
|
|
static __attribute__((unused))
|
|
int atoi(const char *s)
|
|
{
|
|
return atol(s);
|
|
}
|
|
|
|
/* Converts the unsigned long integer <in> to its hex representation into
|
|
* buffer <buffer>, which must be long enough to store the number and the
|
|
* trailing zero (17 bytes for "ffffffffffffffff" or 9 for "ffffffff"). The
|
|
* buffer is filled from the first byte, and the number of characters emitted
|
|
* (not counting the trailing zero) is returned. The function is constructed
|
|
* in a way to optimize the code size and avoid any divide that could add a
|
|
* dependency on large external functions.
|
|
*/
|
|
static __attribute__((unused))
|
|
int utoh_r(unsigned long in, char *buffer)
|
|
{
|
|
signed char pos = (~0UL > 0xfffffffful) ? 60 : 28;
|
|
int digits = 0;
|
|
int dig;
|
|
|
|
do {
|
|
dig = in >> pos;
|
|
in -= (uint64_t)dig << pos;
|
|
pos -= 4;
|
|
if (dig || digits || pos < 0) {
|
|
if (dig > 9)
|
|
dig += 'a' - '0' - 10;
|
|
buffer[digits++] = '0' + dig;
|
|
}
|
|
} while (pos >= 0);
|
|
|
|
buffer[digits] = 0;
|
|
return digits;
|
|
}
|
|
|
|
/* converts unsigned long <in> to an hex string using the static itoa_buffer
|
|
* and returns the pointer to that string.
|
|
*/
|
|
static inline __attribute__((unused))
|
|
char *utoh(unsigned long in)
|
|
{
|
|
utoh_r(in, itoa_buffer);
|
|
return itoa_buffer;
|
|
}
|
|
|
|
/* Converts the unsigned long integer <in> to its string representation into
|
|
* buffer <buffer>, which must be long enough to store the number and the
|
|
* trailing zero (21 bytes for 18446744073709551615 in 64-bit, 11 for
|
|
* 4294967295 in 32-bit). The buffer is filled from the first byte, and the
|
|
* number of characters emitted (not counting the trailing zero) is returned.
|
|
* The function is constructed in a way to optimize the code size and avoid
|
|
* any divide that could add a dependency on large external functions.
|
|
*/
|
|
static __attribute__((unused))
|
|
int utoa_r(unsigned long in, char *buffer)
|
|
{
|
|
unsigned long lim;
|
|
int digits = 0;
|
|
int pos = (~0UL > 0xfffffffful) ? 19 : 9;
|
|
int dig;
|
|
|
|
do {
|
|
for (dig = 0, lim = 1; dig < pos; dig++)
|
|
lim *= 10;
|
|
|
|
if (digits || in >= lim || !pos) {
|
|
for (dig = 0; in >= lim; dig++)
|
|
in -= lim;
|
|
buffer[digits++] = '0' + dig;
|
|
}
|
|
} while (pos--);
|
|
|
|
buffer[digits] = 0;
|
|
return digits;
|
|
}
|
|
|
|
/* Converts the signed long integer <in> to its string representation into
|
|
* buffer <buffer>, which must be long enough to store the number and the
|
|
* trailing zero (21 bytes for -9223372036854775808 in 64-bit, 12 for
|
|
* -2147483648 in 32-bit). The buffer is filled from the first byte, and the
|
|
* number of characters emitted (not counting the trailing zero) is returned.
|
|
*/
|
|
static __attribute__((unused))
|
|
int itoa_r(long in, char *buffer)
|
|
{
|
|
char *ptr = buffer;
|
|
int len = 0;
|
|
|
|
if (in < 0) {
|
|
in = -in;
|
|
*(ptr++) = '-';
|
|
len++;
|
|
}
|
|
len += utoa_r(in, ptr);
|
|
return len;
|
|
}
|
|
|
|
/* for historical compatibility, same as above but returns the pointer to the
|
|
* buffer.
|
|
*/
|
|
static inline __attribute__((unused))
|
|
char *ltoa_r(long in, char *buffer)
|
|
{
|
|
itoa_r(in, buffer);
|
|
return buffer;
|
|
}
|
|
|
|
/* converts long integer <in> to a string using the static itoa_buffer and
|
|
* returns the pointer to that string.
|
|
*/
|
|
static inline __attribute__((unused))
|
|
char *itoa(long in)
|
|
{
|
|
itoa_r(in, itoa_buffer);
|
|
return itoa_buffer;
|
|
}
|
|
|
|
/* converts long integer <in> to a string using the static itoa_buffer and
|
|
* returns the pointer to that string. Same as above, for compatibility.
|
|
*/
|
|
static inline __attribute__((unused))
|
|
char *ltoa(long in)
|
|
{
|
|
itoa_r(in, itoa_buffer);
|
|
return itoa_buffer;
|
|
}
|
|
|
|
/* converts unsigned long integer <in> to a string using the static itoa_buffer
|
|
* and returns the pointer to that string.
|
|
*/
|
|
static inline __attribute__((unused))
|
|
char *utoa(unsigned long in)
|
|
{
|
|
utoa_r(in, itoa_buffer);
|
|
return itoa_buffer;
|
|
}
|
|
|
|
/* Converts the unsigned 64-bit integer <in> to its hex representation into
|
|
* buffer <buffer>, which must be long enough to store the number and the
|
|
* trailing zero (17 bytes for "ffffffffffffffff"). The buffer is filled from
|
|
* the first byte, and the number of characters emitted (not counting the
|
|
* trailing zero) is returned. The function is constructed in a way to optimize
|
|
* the code size and avoid any divide that could add a dependency on large
|
|
* external functions.
|
|
*/
|
|
static __attribute__((unused))
|
|
int u64toh_r(uint64_t in, char *buffer)
|
|
{
|
|
signed char pos = 60;
|
|
int digits = 0;
|
|
int dig;
|
|
|
|
do {
|
|
if (sizeof(long) >= 8) {
|
|
dig = (in >> pos) & 0xF;
|
|
} else {
|
|
/* 32-bit platforms: avoid a 64-bit shift */
|
|
uint32_t d = (pos >= 32) ? (in >> 32) : in;
|
|
dig = (d >> (pos & 31)) & 0xF;
|
|
}
|
|
if (dig > 9)
|
|
dig += 'a' - '0' - 10;
|
|
pos -= 4;
|
|
if (dig || digits || pos < 0)
|
|
buffer[digits++] = '0' + dig;
|
|
} while (pos >= 0);
|
|
|
|
buffer[digits] = 0;
|
|
return digits;
|
|
}
|
|
|
|
/* converts uint64_t <in> to an hex string using the static itoa_buffer and
|
|
* returns the pointer to that string.
|
|
*/
|
|
static inline __attribute__((unused))
|
|
char *u64toh(uint64_t in)
|
|
{
|
|
u64toh_r(in, itoa_buffer);
|
|
return itoa_buffer;
|
|
}
|
|
|
|
/* Converts the unsigned 64-bit integer <in> to its string representation into
|
|
* buffer <buffer>, which must be long enough to store the number and the
|
|
* trailing zero (21 bytes for 18446744073709551615). The buffer is filled from
|
|
* the first byte, and the number of characters emitted (not counting the
|
|
* trailing zero) is returned. The function is constructed in a way to optimize
|
|
* the code size and avoid any divide that could add a dependency on large
|
|
* external functions.
|
|
*/
|
|
static __attribute__((unused))
|
|
int u64toa_r(uint64_t in, char *buffer)
|
|
{
|
|
unsigned long long lim;
|
|
int digits = 0;
|
|
int pos = 19; /* start with the highest possible digit */
|
|
int dig;
|
|
|
|
do {
|
|
for (dig = 0, lim = 1; dig < pos; dig++)
|
|
lim *= 10;
|
|
|
|
if (digits || in >= lim || !pos) {
|
|
for (dig = 0; in >= lim; dig++)
|
|
in -= lim;
|
|
buffer[digits++] = '0' + dig;
|
|
}
|
|
} while (pos--);
|
|
|
|
buffer[digits] = 0;
|
|
return digits;
|
|
}
|
|
|
|
/* Converts the signed 64-bit integer <in> to its string representation into
|
|
* buffer <buffer>, which must be long enough to store the number and the
|
|
* trailing zero (21 bytes for -9223372036854775808). The buffer is filled from
|
|
* the first byte, and the number of characters emitted (not counting the
|
|
* trailing zero) is returned.
|
|
*/
|
|
static __attribute__((unused))
|
|
int i64toa_r(int64_t in, char *buffer)
|
|
{
|
|
char *ptr = buffer;
|
|
int len = 0;
|
|
|
|
if (in < 0) {
|
|
in = -in;
|
|
*(ptr++) = '-';
|
|
len++;
|
|
}
|
|
len += u64toa_r(in, ptr);
|
|
return len;
|
|
}
|
|
|
|
/* converts int64_t <in> to a string using the static itoa_buffer and returns
|
|
* the pointer to that string.
|
|
*/
|
|
static inline __attribute__((unused))
|
|
char *i64toa(int64_t in)
|
|
{
|
|
i64toa_r(in, itoa_buffer);
|
|
return itoa_buffer;
|
|
}
|
|
|
|
/* converts uint64_t <in> to a string using the static itoa_buffer and returns
|
|
* the pointer to that string.
|
|
*/
|
|
static inline __attribute__((unused))
|
|
char *u64toa(uint64_t in)
|
|
{
|
|
u64toa_r(in, itoa_buffer);
|
|
return itoa_buffer;
|
|
}
|
|
|
|
static __attribute__((unused))
|
|
int msleep(unsigned int msecs)
|
|
{
|
|
struct timeval my_timeval = { msecs / 1000, (msecs % 1000) * 1000 };
|
|
|
|
if (sys_select(0, 0, 0, 0, &my_timeval) < 0)
|
|
return (my_timeval.tv_sec * 1000) +
|
|
(my_timeval.tv_usec / 1000) +
|
|
!!(my_timeval.tv_usec % 1000);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/* This one is not marked static as it's needed by libgcc for divide by zero */
|
|
__attribute__((weak,unused,section(".text.nolibc_raise")))
|
|
int raise(int signal)
|
|
{
|
|
return sys_kill(sys_getpid(), signal);
|
|
}
|
|
|
|
static __attribute__((unused))
|
|
unsigned int sleep(unsigned int seconds)
|
|
{
|
|
struct timeval my_timeval = { seconds, 0 };
|
|
|
|
if (sys_select(0, 0, 0, 0, &my_timeval) < 0)
|
|
return my_timeval.tv_sec + !!my_timeval.tv_usec;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
static __attribute__((unused))
|
|
int tcsetpgrp(int fd, pid_t pid)
|
|
{
|
|
return ioctl(fd, TIOCSPGRP, &pid);
|
|
}
|
|
|
|
#endif /* _NOLIBC_STDLIB_H */
|