A C standard library written in sysl: the module sh.sysl.cstd, with C headers in include/.
It is not a general-purpose libc competing with musl. It exists for two consumers:
- keel, the research kernel in sysl (
github.com/sysl-lang/keel). C programs are ported to keel through it. - Bare-metal boards. sysl's freestanding targets have no libc, so a vendored C package that
includes
<string.h>or<assert.h>fails there with'string.h' file not found. cstd supplies the headers and the symbols behind them.
Every function is an ordinary sysl function over raw pointers, which is what the C signatures
require, exported under its C name with @export.
| header | functions |
|---|---|
string.h |
strlen strnlen strcmp strncmp strcpy strncpy strcat strncat strchr strrchr strstr strspn strcspn strpbrk strtok strtok_r strerror strerror_r strerror_l strsignal stpcpy stpncpy strlcpy strlcat strdup strndup strcoll strcoll_l strxfrm strxfrm_l memcpy memmove memset memcmp memchr memmem — all of POSIX.1-2024's base <string.h> |
ctype.h |
isalnum isalpha isblank iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper, and the _l variant of each, for the C locale |
locale.h |
setlocale localeconv newlocale duplocale freelocale uselocale getlocalename_l, for the C locale |
stdlib.h |
atoi atol atof strtol strtoul strtoll strtoull strtod strtof abs labs llabs div ldiv lldiv qsort bsearch |
inttypes.h |
every PRI*/SCN* macro for the target's <stdint.h> types, imaxdiv_t, imaxabs imaxdiv strtoimax strtoumax wcstoimax wcstoumax |
strings.h |
strcasecmp strncasecmp strcasecmp_l strncasecmp_l (ASCII folding, C locale), ffs ffsl ffsll |
assert.h |
assert (honours NDEBUG at each inclusion; failure writes Assertion failed: expr (file: func: line) to descriptor 2, then abort), static_assert |
endian.h |
POSIX.1-2024's BYTE_ORDER LITTLE_ENDIAN BIG_ENDIAN and be16toh be32toh be64toh htobe16 htobe32 htobe64 htole16 htole32 htole64 le16toh le32toh le64toh |
stdbit.h |
ISO C23's 14 families (stdc_leading_zeros stdc_leading_ones stdc_trailing_zeros stdc_trailing_ones stdc_first_leading_zero stdc_first_leading_one stdc_first_trailing_zero stdc_first_trailing_one stdc_count_zeros stdc_count_ones stdc_has_single_bit stdc_bit_width stdc_bit_floor stdc_bit_ceil), each as _uc _us _ui _ul _ull functions and as a type-generic macro, with __STDC_ENDIAN_*__ and __STDC_VERSION_STDBIT_H__ |
errno.h |
errno as POSIX's macro over __errno_location(): one per thread where the build has thread-local storage (a hosted target, the Linux half), one object on a board; Linux's codes from EPERM to ETIMEDOUT |
stdio.h |
printf dprintf sprintf snprintf vprintf vdprintf vsprintf vsnprintf |
setjmp.h |
setjmp longjmp sigsetjmp siglongjmp |
time.h |
gmtime gmtime_r localtime localtime_r mktime timegm difftime strftime strftime_l tzset, and on a freestanding target time clock timespec_get over clock_gettime; struct tm (with tm_gmtoff, tm_zone), struct itimerspec, clock_t, timer_t, CLOCKS_PER_SEC, TIME_UTC, TIMER_ABSTIME |
math.h |
all 57 functions of POSIX.1-2024 in double and float, and in long double where it is a double; the classification and comparison macros, HUGE_VAL, INFINITY, NAN, the FP_ and MATH_ constants and M_PI and friends |
-
setjmpis assembly per processor (sh/sysl/cstd/setjmp.sysl): aarch64 (x19–x30, sp, d8–d15; x18 left alone), thumb in Armv6-M's instructions so every Cortex-M runs it (r4–r11, sp, lr, and s16–s31 where the target has floating-point registers,#if fpu), and riscv32 (ra, sp, s0–s11).<setjmp.h>refuses to compile anywhere else.longjmpwith 0 makessetjmpreturn 1. -
sigjmp_bufisjmp_buf, andsiglongjmpislongjmp.sigsetjmpwith a non-zerosavemaskreads the mask, and puts it back after asiglongjmp, through an externalsigprocmaskthat the platform supplies, as it supplieswrite.sigsetjmpsits in a section of its own, so a board that links onlysetjmpwith--gc-sectionsneeds nosigprocmask. -
endian.h's byte order is the compiler's (__BYTE_ORDER__), and the conversions do not assume it: the host's order is read off the bytes of au16holding 1, and the rule (swap when the host's order is not the wanted one) is a function of that order, whichendian_tests.sysldrives under both. Every target runs little-endian, so the big-endian half of the rule is tested at the sysl level and not by running on a big-endian machine. The twelve are functions only, which the page allows. -
stdbit.his cstd's alone: clang does not ship one. Neither Apple clang 21's resource directory nor Homebrew's LLVM 23.1's carries it (both havestdckdint.hand nostdbit.h; the header is left to the C library), so cstd must supply it, and the 70 functions behind it exist in the archive. Were a clang to add one,-I <cstd>/includeis searched before-isystem <resource>/include, so cstd's would still be the one included.unsigned longis measured, so it is 32 bits on a Cortex-M.stdc_bit_ceilof a value past the largest power of two the type holds is undefined in C; here it is 0. The generic macros accept the five unsigned types and refuse anything else at compile time. -
The printf family takes C99's
%d %i %u %o %x %X %c %s %p %n %%and%f %F %e %E %g %G %a %A, the flags- + space # 0, a width and a precision as a number or*, and the lengthshh h l ll j z t. There is nolong double, soLis not taken and%Lfis copied out as written. There is noFILE:printfwrites to descriptor 1 anddprintfto the one it is given, both throughwrite, which the platform supplies. Output gathers in a 256-byte buffer on the stack and nothing allocates. -
Where C leaves a choice, musl's answer is taken, since keel targets musl compatibility:
%pis%#zx, so a null pointer prints0(glibc prints(nil));%sof a null pointer prints(null); a conversion C does not define is copied out as written. -
Floats print their exact value, correctly rounded. A double is
m × 2^e, so its decimal expansion is finite; it is built exactly in base-10^9 limbs (as musl'sfmt_fpdoes) and rounded half to even where the precision says, so%.0fof 0.5 is0,%.20fof 0.1 is0.10000000000000000555, and%fof 1e300 prints all of its 301 digits. No float arithmetic is done, so a soft-float board prints exactly what a hosted machine does.%ais exact hex, a subnormal normalised to0x1p-1074as musl prints it. Infinity and NaN areinf/nan(upper case underF E G A), signed by the sign bit as musl does. -
strtodandstrtofare correctly rounded for any length of input, through the standard library'ssysl.text.real_prefix/f32_prefix: Eisel-Lemire on the first nineteen digits, and an exact big-integer comparison against the halfway point where more digits could decide it. Decimal and hex forms,inf,infinity,nanandnan(...)are read. Overflow answers ±infinity and an underflow a zero or subnormal, each withERANGE(every subnormal result sets it; C leaves underflow'serrnoto the implementation). No number at all leavesendptrat the text and setsEINVAL, as the integerstrto*do here. -
longis measured with ac type, sostrtolanswers 32 bits on a Cortex-M and 64 on an LP64 machine. -
The
strto*functions take base 0 or 2–36, skip leading white space, read one sign and an optional0x, setendptr, and saturate withERANGE. -
qsortis a heapsort: O(n log n) on every input, constant stack, any element size, not stable. -
strerrorknows0and every codeerrno.hdefines, in glibc's words; any other code answers the fixed textUnknown error, because formatting the number in would need a formatter. -
strtokkeeps one save pointer for the whole program, as C does;strtok_rkeeps it in the caller's hands. -
strdupandstrndupcall an externalmallocthat the program supplies (the Linux half's, a board's, or the host's), and setENOMEMthemselves when it answers null.strndupreads at mostnbytes and allocates only what it copies. -
Only the C locale exists:
locale_tis an opaque pointer the_lfunctions ignore,strcollisstrcmp, andstrxfrmcopies its source when it fits (and touches nothing when it does not). -
strerror_ris POSIX'sintform: a message cut to fit is still terminated and answersERANGE, an unknown code answersEINVALwithUnknown errorin the buffer.strsignalgives glibc's words for each signalsignal.hdefines andUnknown signalfor any other number. -
Text with no number in it, or a base C does not define, sets
EINVAL, as the BSD libcs do. C leaves that case unspecified.
- There is no time-zone database: local time is UTC.
localtimeisgmtime,mktimeistimegm,tzsetreads noTZ, and everystruct tmcstd fills hastm_isdst0,tm_gmtoff0 andtm_zone"UTC".mktimeignores thetm_isdstit is given.tznameis{"UTC", "UTC"};daylightandtimezoneare XSI and not offered. - The calendar is proleptic Gregorian over every
time_t, in 64-bit integers with no table (Howard Hinnant'sdays_from_civil), so year 1, negative years and years far past 9999 are exact. A time whose yeartm_yearcannot hold makesgmtimeanswer null andmktime/timegmanswer -1, withEOVERFLOW.mktimeandtimegmnormalise every field (a month of 13, a day of 0, a second of 60 or -1) and settm_wdayandtm_yday.time_tislong, so 32 bits on a Cortex-M. strftimetakes every POSIX.1-2024 conversion,EandO(ignored, as in the C locale), and the0and+flags with a minimum width on%C %F %G %Y. Where POSIX leaves a choice, musl's answer is taken:%Yis at least four digits and a year past 9999 is written+12345,%yof a year before 0 is the last two digits of its magnitude, and a conversion POSIX does not define makesstrftimeanswer 0.%zistm_gmtoff,%Zistm_zone(UTCwhen null), and both are empty whentm_isdstis negative. Fields are read as they stand, not normalised; a weekday or month out of range has the name?. A result that does not fit, NUL included, answers 0 withERANGE.time,clockandtimespec_getreadclock_gettime(CLOCK_REALTIME, andCLOCK_PROCESS_CPUTIME_IDforclock, in microseconds), and so exist only on a freestanding target, where cstd's Linux half or a board defines it; elsewhere the host libc's are used.
- The algorithms are musl's (1.2.6), ported into sysl with their structure, constants and tables
kept so that each file can be read beside the C it came from: Arm's optimized-routines for
exp,exp2,log,log2andpow; fdlibm (FreeBSD's msun) for the trigonometric, inverse trigonometric, error and gamma functions,expm1,log10,log1pandcbrt; musl's own for the rest. Their notices are inLICENSE. - Where musl rounds an intermediate and lands past 1 ulp, the intermediate is carried in
double-double (
math_dd.sysl: two-sum, Dekker's product, and exp, expm1 and log built from the tables above without rounding their tails away), and only the answer is rounded. That issinh,cosh,tanh,asinh,acosh,atanh,atan2,erf,erfc,lgammaandtgamma; musl's forms measure between 1.2 and 10 ulp, and itstgamma(Lanczos) andacoshfor negative arguments are not used at all. - Nothing calls a C library.
sqrtis AArch64'sfsqrtor x86-64'ssqrtsdthroughllvm.sqrt, and elsewhere musl's integer square root;fmaandfmafare the machine's fused instruction throughllvm.fmawhere it has one at that width (#if fma_dp,#if fma), and elsewhere musl's 128-bit integerfmaand afmafrounded to odd; the roundings are integer operations on the bits. A test checks the archive's undefined symbols on the host, on 32-bit Arm and on AArch64. floatcomputes indoubleand rounds once, except where a function of its own is needed to be exact:fmafrounds the double sum to odd before narrowing, which is correct even into float's subnormals.sqrtf,fmodf,remainderf,remquof, the roundings and the scalings are exact throughdouble; the others are correctly rounded on every input the tests sample (some 70 000 each), exceptatan2f, which a tie between two floats can cost half an ulp and a hair (the test file says why).long doubleisdoubleon arm64 macOS and 32-bit Arm, and there eachlfunction is its double counterpart under thelname. Where it is binary128 (AArch64 Linux, RISC-V) they are not offered, andmath.hdoes not declare them;nexttowardtakes its direction at the type's width on both.- Errors go to
errnoonly:math_errhandlingisMATH_ERRNO. A domain error setsEDOMand answers NaN; a pole error or an overflow setsERANGEand answers ±infinity; an underflow answers the subnormal or zero and sets nothing, which POSIX permits. A NaN argument is never an error. The exception flags are whatever the arithmetic raises, and nothing promises which. - C Annex F's special values hold throughout:
pow(-1, ±inf)andpow(x, ±0)are 1,atan2of signed zeros answers ±0 or ±pi,hypot(inf, NaN)is inf, every zero keeps its sign. - The rounding mode is assumed to be to nearest, as musl assumes it.
The largest error measured against MPFR, in units in the last place of the exact answer, over the inputs the tests run (between 20 000 and 75 000 per function and form):
| function | double |
float |
|---|---|---|
sqrt fma fmod remainder remquo floor ceil trunc round rint nearbyint lrint llrint lround llround frexp ldexp scalbn scalbln modf ilogb logb nextafter nexttoward fabs copysign fdim fmax fmin |
0 (exact) | 0 (exact) |
exp exp2 |
0.503 | 0.500 |
expm1 |
0.737 | 0.500 |
log |
0.503 | 0.500 |
log2 |
0.526 | 0.500 |
log10 |
0.612 | 0.500 |
log1p |
0.787 | 0.500 |
pow |
0.505 | 0.500 |
cbrt |
0.665 | 0.500 |
hypot |
0.939 | 0.500 |
sin cos tan |
0.740 0.730 0.798 | 0.500 |
asin acos atan |
0.799 0.815 0.766 | 0.500 |
atan2 |
0.803 | 0.500 |
sinh cosh tanh |
0.647 0.580 0.639 | 0.500 |
asinh acosh atanh |
0.500 0.501 0.500 | 0.500 |
erf erfc |
0.869 0.746 | 0.500 |
tgamma |
0.820 | 0.500 |
lgamma |
0.614 for x > 0; 0.998 for x < 0, except next to its zeros | 0.500 |
The tests hold every elementary function to 1 ulp and the exact ones to the bit. lgamma below zero is the one exception: lgamma(x) = log(pi / |x sin(pi x)|) - lgamma(-x) subtracts two nearly equal numbers wherever lgamma(x) is close to one of its zeros (two in each unit interval from -2 down), and there the answer is held to an absolute error, measured at most 7.6 × 10^-18, rather than to ulps.
A C program for keel, or a static Linux aarch64 program, needs a runtime under it as well:
linux/ is a second project (cstd_linux, module sh.sysl.cstd_linux) depending on this one by
path, so its archive holds both halves. It is a project of its own because everything in it is a
claim about the machine underneath — a board has no svc to make, and a hosted test links the host's
own write and malloc, which these would replace.
| header | functions |
|---|---|
| (crt0) | _start: reads Linux's initial stack, sets environ, calls sysl_init_modules and main(argc, argv, envp), then exit |
unistd.h |
read write close lseek _exit getpid getppid brk sbrk dup dup2 pipe unlink rmdir chdir getcwd, environ |
fcntl.h |
open (variadic, the mode read only under O_CREAT/O_TMPFILE) openat, arm64's flag values |
sys/stat.h |
stat fstat mkdir, the 128-byte asm-generic struct stat |
time.h / signal.h |
nanosleep clock_gettime clock_getres clock_settime clock_nanosleep timer_create timer_delete timer_getoverrun timer_gettime timer_settime / kill |
stdlib.h |
malloc calloc realloc free exit _Exit atexit (32 handlers, last first) abort (SIGABRT) |
Each call is one svc #0 (x8 the number, x0–x5 the arguments); an answer from -4095 to -1 sets
errno and answers -1. errno's numbers are Linux's.
malloc is sh.sysl.cstd's BreakHeap (malloc.sysl), the same allocator a board's defaults
are, over this half's sbrk; its bookkeeping is Heap (heap.sysl, tested on the host with an
array standing in for the break). The break moves 64 KiB at a time where the kernel allows it, and
by exactly what is needed where it does not. First fit from an address-ordered free list, freed neighbours merged at once,
16-byte aligned payloads, realloc in place where the block can be cut, can take its free
neighbour, or is the last before the break. It is not thread-safe: one heap, no lock, until
pthreads arrive. A program that moves the break itself after its first malloc gets ENOMEM from
a malloc that needs to grow.
sysl build-c linux --target aarch64-freestanding -o libcstd.a
clang --target=aarch64-linux-gnu -ffreestanding -nostdinc -isystem "$(clang -print-resource-dir)/include" \
-I <cstd>/include -static -fno-pic -O2 -c prog.c
ld.lld -static -e _start -o prog prog.o libcstd.a
On any other freestanding target the calls of the unistd.h, fcntl.h, sys/stat.h, time.h and
signal.h rows above but _exit, and sigprocmask, which sigsetjmp reaches, are weak defaults in
the core (stubs.sysl): each sets errno to ENOSYS and answers its failure value (-1, a null
getcwd, (void *)-1 from sbrk). A board overrides any one by defining it strongly, in its sysl
(@export("write")) or its C (ssize_t write(int, const void *, size_t)), and the link keeps the
board's with no duplicate-symbol error. clock_nanosleep answers ENOSYS itself, as it answers every
error, and time, clock and timespec_get read a board's clock_gettime once it defines one. A
static linker does not pull an archive member in to replace
a weak definition it already has, so a definition in a board's C is kept where something else in that
file is linked too — its startup code, or a function the board calls. A hosted target has none of
the defaults: its calls are the host libc's.
The stdlib.h row is defaulted too, so a board program links with nothing of its own — sysl's
runtime reaches malloc, free and abort for any sysl code that allocates or traps:
| function | the default |
|---|---|
malloc calloc realloc free |
the same Heap as the Linux half, growing through sbrk (malloc.sysl). With cstd's own sbrk every allocation is null with ENOMEM; a board that defines sbrk over its heap region has a working allocator with nothing else written. The heap grows 4 KiB at a time where the region has room, and by exactly what it needs where it does not |
atexit exit |
the Linux half's 32-slot table, which lives in the core and serves both (exit.sysl); exit runs the handlers last first and then calls _Exit |
_Exit _exit abort |
trap: sysl's trap(), the processor's trap instruction (udf #254 on Arm, unimp on RISC-V), so a debugger stops there and the board's fault handler sees it, rather than a spin nothing reports. A board that can end a run — semihosting, a reset — defines _Exit and _exit, and exit ends through them |
The four allocation functions are one allocator: a board with its own replaces all four, since cstd's
realloc and free only understand blocks cstd's malloc handed out.
sysl build-c . --target aarch64-freestanding -o libcstd.a
clang --target=aarch64-none-elf -ffreestanding -nostdinc \
-isystem "$(clang -print-resource-dir)/include" -I <cstd>/include -c prog.c
-nostdinc drops every system header. -isystem puts back clang's own freestanding ones
(stddef.h, stdint.h, limits.h, stdbool.h), and include/ supplies the rest.
sysl test .
The tests are C programs. Each case is a C snippet passed to c_case(snippet, expected_stdout)
(sh/sysl/cstd/c_case_tests.sysl). The snippet becomes the body of main, compiled
-nostdinc -fno-builtin -O0 against include/ and linked with the archive sysl build-c writes
(built once per run, in .sysl/c-tests/). The program is run and its standard output compared
exactly. A case prints through the say_* helpers in tests/say.h, which use nothing from the
host's libc except write. Expected values are written in the test, never taken from the host's
libc.
A function that writes memory is checked on the bytes it wrote. The whole buffer is printed, with a guard byte on each side, NULs included. The cases cover:
- the empty string, and bytes ≥ 0x80 (compared as
unsigned char) - not-found answers
- overlapping
memmovein both directions strncpy's padding and its missing terminatorn = 0, exact-fit and one-short buffers forstrlcpy,strlcat,stpncpy,strxfrmandstrerror_r, anderrnoleft alone where the function promises itstrdup/strndupagainst amallocthe case supplies in its prelude: the size asked for, andENOMEMfrom a refusalmemmemwith an empty needle, a needle longer than the haystack, and a match at the very end- every
<ctype.h>function over EOF and 0–255, and each_lvariant agreeing with its plain twin there, given a locale object and givenLC_GLOBAL_LOCALE - the names
setlocaleandnewlocaleaccept and refuse,newlocale'sENOENTandEINVAL, everylocaleconvfield, anduselocalehanding back the locale it replaced - every
<stdbit.h>function, through the function and the type-generic macro, over all 256unsigned charvalues and a spread of patterns at each wider width, against a bit-by-bit reference written in the test, plus hand-worked tables of the edge values (0, all ones, the top bit alone,bit_ceilpast the top) <endian.h>as the bytes memory holds, and its reversal rule under both host orders- every base from 2 to 36
EINVALfor a bad base or no digits- overflow in each
strto*withERANGE endptrpositions
Under AddressSanitizer:
SYSL_EXTRA_CFLAGS="-fsanitize=address -g" sysl test .
The variable reaches the sysl build-c the suite runs, and c_case hands the same flags to each
case's clang, so the archive and every program are instrumented together. Two tests run only in
this mode:
nm -uof the archive must show__asan_report_load1and__asan_report_store1.strlenover a buffer with no NUL must be reported as astack-buffer-overflowinstrlen.
And one ordinary case earns its keep here: strnlen and strndup over an unterminated array within
their n must not read past it, which only ASan can see.
The mathematics is judged by MPFR, which computes every function correctly rounded at any
precision (sh/sysl/cstd/math_oracle.sysl; the suite needs Homebrew's mpfr and gmp under
/opt/homebrew/opt). A case is C over tests/math_gen.h: it calls a cstd function on the special
values (zeros, infinities, NaNs, the ends of the subnormal and normal ranges, one and its
neighbours), on a fixed-seed spread of arbitrary bit patterns, and on the places its algorithm has
edges -- arguments next to multiples of pi/2 and past 2^20 pi/2 for the trigonometric functions, the
overflow and underflow thresholds, the neighbourhood of 1 for a logarithm, perfect squares and cubes,
halves for the roundings, cancellation for fma, each fit's interval boundaries -- and prints the
bits. A C program built once per run against MPFR reads those lines and checks each answer against
the correctly rounded one (to the bit, for the exact functions) or against the exact one to within the
function's bound in ulps, and checks errno on every line. It appends the largest error it saw to
.sysl/c-tests/ulp-report.txt, which is where the table above comes from. The math_c_tests.sysl
cases pin the header's macros and constants and the errno and Annex F behaviour by name.
The freestanding builds are checked with:
sysl build-lib . --target thumb-freestanding-softfp
sysl build-lib . --target thumb-freestanding
sysl build-lib . --target thumbv7em-freestanding
sysl build-lib . --target thumbv6m-freestanding
sysl build-lib . --target riscv32-freestanding
sysl build-lib . --target aarch64-freestanding
cstd as a package's C library is checked by libc_probe_tests.sysl over tests/libc_probe, a
package that vendors a C file including <string.h>, <ctype.h>, <inttypes.h> and <math.h> and
takes cstd with if = "!libc". Built with sysl build-c for thumbv7em-freestanding and
riscv32-freestanding, its archive must define strlen, toupper, strtoimax and sqrt; built for
the host, where the real libc answers, it must define nothing but the probe's own symbols.
The setjmp cases run on the host, which is aarch64: a jump across frames, 0 becoming 1, volatile
locals, x19–x28 and d8–d15 overwritten by the skipped frames and put back, nested buffers, a
hundred thousand jumps with the stack where it was, and sigsetjmp's mask through the host's
sigprocmask. The thumb and riscv32 arms run on QEMU (microbit, a Cortex-M0; mps2-an385, a
Cortex-M3; virt, RV32; mps2-an386, a Cortex-M4F, where s16–s31 are overwritten by the skipped frames and
must come back): tests/qemu/setjmp.c is linked against cstd built for the target by
tests/qemu/archive and reports through semihosting. Those three cases need qemu-system-arm,
qemu-system-riscv32, ld.lld and Homebrew's LLVM clang, skip where any is missing, and skip
under ASan, whose flags would reach the bare-metal build. Under ASan a C caller of longjmp calls
__asan_handle_no_return itself, because the prototype is noreturn, so the skipped frames'
shadow is cleared without cstd doing anything.
The operating-system defaults are checked by stubs_tests.sysl: built for
thumbv7em-freestanding, cstd's archive lists every defaulted call as W; built for
aarch64-freestanding, the Linux half's lists each as T with no W beside it; and on QEMU's
mps2-an386, tests/qemu/stubs.c linked against tests/board_probe — a package whose C supplies a
strong write over semihosting — prints through the board's write and sees every other call answer
its failure value with errno ENOSYS. Making the default write strong turns that link into
duplicate symbol: write.
The allocator and exit defaults are checked by board_defaults_tests.sysl, the same way: W on
thumbv7em and T alone in the Linux half for all nine; on mps2-an386, tests/qemu/heap.c with the
board's sbrk over an 8 KiB array (tests/board_probe/c/board_heap.c) writes and reads back,
sees calloc zero a reused block, realloc keep the bytes as it moves, free then malloc reuse
the block, ENOMEM past the region and from an overflowing calloc, and 32 atexit handlers (a 33rd
refused) run last first by exit before the board's _Exit; tests/qemu/nosbrk.c, which leaves the
board's sbrk out of the link, sees malloc, calloc and realloc answer null with ENOMEM; and
tests/qemu/sysl_alloc.c links tests/alloc_probe — sysl code filling a growable buffer — into a
whole image with no malloc, free or abort of its own and gets the right sum.
- Allocation and
exitin the portable half. Where memory comes from and how a process ends are the platform's:linux/answers both for Linux's ABI; a board's arena is still to come. FILEand the rest of stdio. Buffered streams are not written yet.long doublebeyond binary64:strtold,%Lf, and thelfunctions of<math.h>wherelong doubleis binary128. cstd's floats aredoubleandfloat; wherelong doubleis adoublethe<math.h>lfunctions are offered as theirdoublecounterparts, and where it is binary128 a quad-precision argument reduction, polynomials and tables are still to be written. Adoubleanswer widened would be wrong in its last 60 bits, so nothing is offered there.- Locales other than C. Only the C locale exists: every byte from 0x80 up is in no class,
setlocaleandnewlocaleaccept only "C", "POSIX" and "" (which is the C locale here), and the_lfunctions answer as the C locale whateverlocale_tthey are given. A locale's data would have to come from somewhere, and nothing cstd runs on has it. The current localeuselocaleinstalls is one per program.
ISC. See LICENSE, which also carries the notices of musl, Arm and Sun's fdlibm for the
mathematics.