aboutsummaryrefslogtreecommitdiff
path: root/elf/dl-misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/dl-misc.c')
-rw-r--r--elf/dl-misc.c84
1 files changed, 84 insertions, 0 deletions
diff --git a/elf/dl-misc.c b/elf/dl-misc.c
index c5d3e0e..c469b5a 100644
--- a/elf/dl-misc.c
+++ b/elf/dl-misc.c
@@ -360,3 +360,87 @@ _dl_higher_prime_number (unsigned long int n)
return *low;
}
+
+/* A stripped down strtoul-like implementation for very early use. It
+ does not set errno if the result is outside bounds because it may get
+ called before errno may have been set up. */
+
+uint64_t
+internal_function
+_dl_strtoul (const char *nptr, char **endptr)
+{
+ uint64_t result = 0;
+ bool positive = true;
+ unsigned max_digit;
+
+ while (*nptr == ' ' || *nptr == '\t')
+ ++nptr;
+
+ if (*nptr == '-')
+ {
+ positive = false;
+ ++nptr;
+ }
+ else if (*nptr == '+')
+ ++nptr;
+
+ if (*nptr < '0' || *nptr > '9')
+ {
+ if (endptr != NULL)
+ *endptr = (char *) nptr;
+ return 0UL;
+ }
+
+ int base = 10;
+ max_digit = 9;
+ if (*nptr == '0')
+ {
+ if (nptr[1] == 'x' || nptr[1] == 'X')
+ {
+ base = 16;
+ nptr += 2;
+ }
+ else
+ {
+ base = 8;
+ max_digit = 7;
+ }
+ }
+
+ while (1)
+ {
+ int digval;
+ if (*nptr >= '0' && *nptr <= '0' + max_digit)
+ digval = *nptr - '0';
+ else if (base == 16)
+ {
+ if (*nptr >= 'a' && *nptr <= 'f')
+ digval = *nptr - 'a' + 10;
+ else if (*nptr >= 'A' && *nptr <= 'F')
+ digval = *nptr - 'A' + 10;
+ else
+ break;
+ }
+ else
+ break;
+
+ if (result >= (UINT64_MAX - digval) / base)
+ {
+ if (endptr != NULL)
+ *endptr = (char *) nptr;
+ return UINT64_MAX;
+ }
+ result *= base;
+ result += digval;
+ ++nptr;
+ }
+
+ if (endptr != NULL)
+ *endptr = (char *) nptr;
+
+ /* Avoid 64-bit multiplication. */
+ if (!positive)
+ result = -result;
+
+ return result;
+}