diff options
author | Felix Fietkau <nbd@openwrt.org> | 2015-07-24 15:35:55 +0000 |
---|---|---|
committer | Felix Fietkau <nbd@openwrt.org> | 2015-07-24 15:35:55 +0000 |
commit | 16c32e7ce64e09c4a8ac37de45a67600e9db7f09 (patch) | |
tree | 2463a254f0c05d471bd491f5d949d96c9d042252 /toolchain/musl/patches/001-git-2015-07-22.patch | |
parent | 7d4eb63409e1a6dad56da2a12d207734afe014b1 (diff) | |
download | master-187ad058-16c32e7ce64e09c4a8ac37de45a67600e9db7f09.tar.gz master-187ad058-16c32e7ce64e09c4a8ac37de45a67600e9db7f09.tar.bz2 master-187ad058-16c32e7ce64e09c4a8ac37de45a67600e9db7f09.zip |
musl: update to latest git version
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@46481 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'toolchain/musl/patches/001-git-2015-07-22.patch')
-rw-r--r-- | toolchain/musl/patches/001-git-2015-07-22.patch | 3146 |
1 files changed, 3146 insertions, 0 deletions
diff --git a/toolchain/musl/patches/001-git-2015-07-22.patch b/toolchain/musl/patches/001-git-2015-07-22.patch new file mode 100644 index 0000000000..939de6bcd6 --- /dev/null +++ b/toolchain/musl/patches/001-git-2015-07-22.patch @@ -0,0 +1,3146 @@ +commit 3975577922aedab7d60788dd320a2c8e4e94bc6e +Author: Roman Yeryomin <roman@ubnt.com> +Date: Thu Jul 2 12:29:00 2015 +0300 + + socket.h: cleanup/reorder mips and powerpc bits/socket.h + + ....to be somewhat consistent and easily comparable with asm/socket.h + + Signed-off-by: Roman Yeryomin <roman@ubnt.com> + +commit 29ec7677a73a5227badbb1064205be09e707e466 +Author: Roman Yeryomin <roman@ubnt.com> +Date: Thu Jul 2 12:28:41 2015 +0300 + + socket.h: fix SO_* for mips + + Signed-off-by: Roman Yeryomin <roman@ubnt.com> + +commit 3fffa7a658aa925b8f95d36aef7531c1827dbf28 +Author: Felix Fietkau <nbd@openwrt.org> +Date: Tue Jul 21 15:01:25 2015 +0200 + + mips: fix mcontext_t register array field name + + glibc and uclibc use gregs instead of regs + + Signed-off-by: Felix Fietkau <nbd@openwrt.org> + +commit 0f9c2666aca95eb98eb0ef4f4d8d1473c8ce3fa0 +Author: Rich Felker <dalias@aerifal.cx> +Date: Thu Jul 9 18:36:02 2015 +0000 + + handle loss of syslog socket connection + + when traditional syslogd implementations are restarted, the old server + socket ceases to exist and a new unix socket with the same pathname is + created. when this happens, the default destination address associated + with the client socket via connect is no longer valid, and attempts to + send produce errors. this happens despite the socket being datagram + type, and is in contrast to the behavior that would be seen with an IP + datagram (UDP) socket. + + in order to avoid a situation where the application is unable to send + further syslog messages without calling closelog, this patch makes + syslog attempt to reconnect the socket when send returns an error + indicating a lost connection. + + additionally, initial failure to connect the socket no longer results + in the socket being closed. this ensures that an application which + calls openlog to reserve the socket file descriptor will not run into + a situation where transient connection failure (e.g. due to syslogd + restart) prevents fd reservation. however, applications which may be + unable to connect the socket later (e.g. due to chroot, restricted + permissions, seccomp, etc.) will still fail to log if the syslog + socket cannot be connected at openlog time or if it has to be + reconnected later. + +commit 11894f6d3a80be950a490dc7dfab349f057a545f +Author: Rich Felker <dalias@aerifal.cx> +Date: Thu Jul 9 17:07:35 2015 +0000 + + fix incorrect void return type for syncfs function + + being nonstandard, the closest thing to a specification for this + function is its man page, which documents it as returning int. it can + fail with EBADF if the file descriptor passed is invalid. + +commit e8cbe0bad4284906230a53af4c91ad2b9713d03b +Author: Rich Felker <dalias@aerifal.cx> +Date: Wed Jul 8 02:46:45 2015 +0000 + + fix negated return value of ns_skiprr, breakage in related functions + + due to a reversed pointer difference computation, ns_skiprr always + returned a negative value, which functions using it would interpret as + an error. + + patch by Yu Lu. + +commit fb58545f8d1c5fa32122244caeaf3625c12ddc01 +Author: Shiz <hi@shiz.me> +Date: Sun Jun 28 23:08:21 2015 +0200 + + add musl-clang, a wrapper for system clang installs + + musl-clang allows the user to compile musl-powered programs using their + already existent clang install, without the need of a special cross compiler. + it achieves this by wrapping around both the system clang install and the + linker and passing them special flags to re-target musl at runtime. + it does only affect invocations done through the special musl-clang wrapper + script, so that the user setup remains fully intact otherwise. + + the clang wrapper consists of the compiler frontend wrapper script, + musl-clang, and the linker wrapper script, ld.musl-clang. + musl-clang makes sure clang invokes ld.musl-clang to link objects; neither + script needs to be in PATH for the wrapper to work. + +commit f8db6f74b2c74a50c4dec7e30be5215f0e2c37a6 +Author: Shiz <hi@shiz.me> +Date: Sun Jun 28 23:08:20 2015 +0200 + + build: fix musl-targeting toolchain test + + the old test was broken in that it would never fail on a toolchains built + without dynamic linking support, leading to the wrapper script possibly being + installed on compilers that do not support it. in addition, the new test is + portable across compilers: the old test only worked on GCC. + + the new test works by testing whether the toolchain libc defines __GLIBC__: + most non-musl Linux libc's do define this for compatibility even when they + are not glibc, so this is a safe bet to check for musl. in addition, the + compiler runtime would need to have a somewhat glibc-compatible ABI in the + first place, so any non-glibc compatible libc's compiler runtime might not + work. it is safer to disable these cases by default and have the user enable + the wrappers manually there using --enable-wrapper if they certain it works. + +commit b3cd7d13fe630ba1847326242525298e361018c1 +Author: Shiz <hi@shiz.me> +Date: Sun Jun 28 23:08:19 2015 +0200 + + build: overhaul wrapper script system for multiple wrapper support + + this overhauls part of the build system in order to support multiple + toolchain wrapper scripts, as opposed to solely the musl-gcc wrapper as + before. it thereby replaces --enable-gcc-wrapper with --enable-wrapper=..., + which has the options 'auto' (the default, detect whether to use wrappers), + 'all' (build and install all wrappers), 'no' (don't build any) and finally + the options named after the individual compiler scripts (currently only + 'gcc' is available) to build and install only that wrapper. + the old --enable-gcc-wrapper is removed from --help, but still available. + + it also modifies the wrappers to use the C compiler specified to the build + system as 'inner' compiler, when applicable. as wrapper detection works by + probing this compiler, it may not work with any other. + +commit 2a780aa3050b86d888489361f04220bfb58890a1 +Author: Rich Felker <dalias@aerifal.cx> +Date: Mon Jul 6 22:13:11 2015 +0000 + + treat empty TZ environment variable as GMT rather than default + + this improves compatibility with the behavior of other systems and + with some applications which set an empty TZ var to disable use of + local time by mktime, etc. + +commit 8f08a58c635bea5cdfae6bc0e323c80aa9ff82a7 +Author: Alexander Monakov <amonakov@ispras.ru> +Date: Sun Jun 28 02:48:33 2015 +0300 + + dynlink.c: pass gnu-hash table pointer to gnu_lookup + + The callers need to check the value of the pointer anyway, so make + them pass the pointer to gnu_lookup instead of reloading it there. + + Reorder gnu_lookup arguments so that always-used ones are listed + first. GCC can choose a calling convention with arguments in registers + (e.g. up to 3 arguments in eax, ecx, edx on x86), but cannot reorder + the arguments for static functions. + +commit 5b4286e12cd6baac343b10a41dc17ac578832089 +Author: Alexander Monakov <amonakov@ispras.ru> +Date: Sun Jun 28 02:48:32 2015 +0300 + + dynlink.c: slim down gnu_lookup + + Do not reference dso->syms and dso->strings until point of use. + Check 'h1 == (h2|1)', the simplest condition, before the others. + +commit 84389c64562e2b2ba43225b5b7a9df7d974479b1 +Author: Alexander Monakov <amonakov@ispras.ru> +Date: Sun Jun 28 02:48:31 2015 +0300 + + dynlink.c: use bloom filter in gnu hash lookup + + Introduce gnu_lookup_filtered and use it to speed up symbol lookups in + find_sym (do_dlsym is left as is, based on an expectation that + frequently dlsym queries will use a dlopen handle rather than + RTLD_NEXT or RTLD_DEFAULT, and will not need to look at more than one + DSO). + +commit 66d45787c865a1807ae397a89a14699394ed4fa4 +Author: Alexander Monakov <amonakov@ispras.ru> +Date: Sun Jun 28 02:48:30 2015 +0300 + + dynlink.c: use a faster expression in gnu_hash + + With -Os, GCC uses a multiply rather than a shift and addition for 'h*33'. + Use a more efficient expression explicitely. + +commit 6ba5517a460c6c438f64d69464fdfc3269a4c91a +Author: Rich Felker <dalias@aerifal.cx> +Date: Thu Jun 25 22:22:00 2015 +0000 + + fix local-dynamic model TLS on mips and powerpc + + the TLS ABI spec for mips, powerpc, and some other (presently + unsupported) RISC archs has the return value of __tls_get_addr offset + by +0x8000 and the result of DTPOFF relocations offset by -0x8000. I + had previously assumed this part of the ABI was actually just an + implementation detail, since the adjustments cancel out. however, when + the local dynamic model is used for accessing TLS that's known to be + in the same DSO, either of the following may happen: + + 1. the -0x8000 offset may already be applied to the argument structure + passed to __tls_get_addr at ld time, without any opportunity for + runtime relocations. + + 2. __tls_get_addr may be used with a zero offset argument to obtain a + base address for the module's TLS, to which the caller then applies + immediate offsets for individual objects accessed using the local + dynamic model. since the immediate offsets have the -0x8000 adjustment + applied to them, the base address they use needs to include the + +0x8000 offset. + + it would be possible, but more complex, to store the pointers in the + dtv[] array with the +0x8000 offset pre-applied, to avoid the runtime + cost of adding 0x8000 on each call to __tls_get_addr. this change + could be made later if measurements show that it would help. + +commit ce337daa00e42d4f2d9a4d9ae0ed51b20249d924 +Author: Rich Felker <dalias@aerifal.cx> +Date: Tue Jun 23 04:03:42 2015 +0000 + + make dynamic linker work around MAP_FAILED mmap failure on nommu kernels + + previously, loading of additional libraries beyond libc/ldso did not + work on nommu kernels, nor did loading programs via invocation of the + dynamic linker as a command. + +commit a59341420fdedb288d9ff80e73609ae44e9cf258 +Author: Rich Felker <dalias@aerifal.cx> +Date: Tue Jun 23 00:12:25 2015 +0000 + + reimplement strverscmp to fix corner cases + + this interface is non-standardized and is a GNU invention, and as + such, our implementation should match the behavior of the GNU + function. one peculiarity the old implementation got wrong was the + handling of all-zero digit sequences: they are supposed to compare + greater than digit sequences of which they are a proper prefix, as in + 009 < 00. + + in addition, high bytes were treated with char signedness rather than + as unsigned. this was wrong regardless of what the GNU function does + since the resulting order relation varied by arch. + + the new strverscmp implementation makes explicit the cases where the + order differs from what strcmp would produce, of which there are only + two. + +commit 153e952e1a688859d7095345b17e6c1df74a295c +Author: Rich Felker <dalias@aerifal.cx> +Date: Mon Jun 22 20:33:28 2015 +0000 + + fix regression/typo that disabled __simple_malloc when calloc is used + + commit ba819787ee93ceae94efd274f7849e317c1bff58 introduced this + regression. since the __malloc0 weak alias was not properly provided + by __simple_malloc, use of calloc forced the full malloc to be linked. + +commit ba819787ee93ceae94efd274f7849e317c1bff58 +Author: Rich Felker <dalias@aerifal.cx> +Date: Mon Jun 22 18:50:09 2015 +0000 + + fix calloc when __simple_malloc implementation is used + + previously, calloc's implementation encoded assumptions about the + implementation of malloc, accessing a size_t word just prior to the + allocated memory to determine if it was obtained by mmap to optimize + out the zero-filling. when __simple_malloc is used (static linking a + program with no realloc/free), it doesn't matter if the result of this + check is wrong, since all allocations are zero-initialized anyway. but + the access could be invalid if it crosses a page boundary or if the + pointer is not sufficiently aligned, which can happen for very small + allocations. + + this patch fixes the issue by moving the zero-fill logic into malloc.c + with the full malloc, as a new function named __malloc0, which is + provided by a weak alias to __simple_malloc (which always gives + zero-filled memory) when the full malloc is not in use. + +commit 55d061f031085f24d138664c897791aebe9a2fab +Author: Rich Felker <dalias@aerifal.cx> +Date: Sat Jun 20 03:01:07 2015 +0000 + + provide __stack_chk_fail_local in libc.a + + this symbol is needed only on archs where the PLT call ABI is klunky, + and only for position-independent code compiled with stack protector. + thus references usually only appear in shared libraries or PIE + executables, but they can also appear when linking statically if some + of the object files being linked were built as PIC/PIE. + + normally libssp_nonshared.a from the compiler toolchain should provide + __stack_chk_fail_local, but reportedly it appears prior to -lc in the + link order, thus failing to satisfy references from libc itself (which + arise only if libc.a was built as PIC/PIE with stack protector + enabled). + +commit ce3688eca920aa77549323f84e21f33522397115 +Author: Rich Felker <dalias@aerifal.cx> +Date: Sat Jun 20 02:54:30 2015 +0000 + + work around mips detached thread exit breakage due to kernel regression + + linux kernel commit 46e12c07b3b9603c60fc1d421ff18618241cb081 caused + the mips syscall mechanism to fail with EFAULT when the userspace + stack pointer is invalid, breaking __unmapself used for detached + thread exit. the workaround is to set $sp to a known-valid, readable + address, and the simplest one to obtain is the address of the current + function, which is available (per o32 calling convention) in $25. + +commit 75eceb3ae824d54e865686c0c538551aeebf3372 +Author: Rich Felker <dalias@aerifal.cx> +Date: Wed Jun 17 17:21:46 2015 +0000 + + ignore ENOSYS error from mprotect in pthread_create and dynamic linker + + this error simply indicated a system without memory protection (NOMMU) + and should not cause failure in the caller. + +commit 10d0268ccfab9152250eeeed3952ce3fed44131a +Author: Rich Felker <dalias@aerifal.cx> +Date: Tue Jun 16 15:25:02 2015 +0000 + + switch to using trap number 31 for syscalls on sh + + nominally the low bits of the trap number on sh are the number of + syscall arguments, but they have never been used by the kernel, and + some code making syscalls does not even know the number of arguments + and needs to pass an arbitrary high number anyway. + + sh3/sh4 traditionally used the trap range 16-31 for syscalls, but part + of this range overlapped with hardware exceptions/interrupts on sh2 + hardware, so an incompatible range 32-47 was chosen for sh2. + + using trap number 31 everywhere, since it's in the existing sh3/sh4 + range and does not conflict with sh2 hardware, is a proposed + unification of the kernel syscall convention that will allow binaries + to be shared between sh2 and sh3/sh4. if this is not accepted into the + kernel, we can refit the sh2 target with runtime selection mechanisms + for the trap number, but doing so would be invasive and would entail + non-trivial overhead. + +commit 3366a99b17847b58f2d8cc52cbb5d65deb824f8a +Author: Rich Felker <dalias@aerifal.cx> +Date: Tue Jun 16 14:55:06 2015 +0000 + + switch sh port's __unmapself to generic version when running on sh2/nommu + + due to the way the interrupt and syscall trap mechanism works, + userspace on sh2 must never set the stack pointer to an invalid value. + thus, the approach used on most archs, where __unmapself executes with + no stack for the interval between SYS_munmap and SYS_exit, is not + viable on sh2. + + in order not to pessimize sh3/sh4, the sh asm version of __unmapself + is not removed. instead it's renamed and redirected through code that + calls either the generic (safe) __unmapself or the sh3/sh4 asm, + depending on compile-time and run-time conditions. + +commit f9d84554bae0fa17c9a1d724549c4408022228a5 +Author: Rich Felker <dalias@aerifal.cx> +Date: Tue Jun 16 14:28:30 2015 +0000 + + add support for sh2 interrupt-masking-based atomics to sh port + + the sh2 target is being considered an ISA subset of sh3/sh4, in the + sense that binaries built for sh2 are intended to be usable on later + cpu models/kernels with mmu support. so rather than hard-coding + sh2-specific atomics, the runtime atomic selection mechanisms that was + already in place has been extended to add sh2 atomics. + + at this time, the sh2 atomics are not SMP-compatible; since the ISA + lacks actual atomic operations, the new code instead masks interrupts + for the duration of the atomic operation, producing an atomic result + on single-core. this is only possible because the kernel/hardware does + not impose protections against userspace doing so. additional changes + will be needed to support future SMP systems. + + care has been taken to avoid producing significant additional code + size in the case where it's known at compile-time that the target is + not sh2 and does not need sh2-specific code. + +commit 1b0cdc8700d29ef018bf226d74b2b58b23bce91c +Author: Rich Felker <dalias@aerifal.cx> +Date: Tue Jun 16 07:11:19 2015 +0000 + + refactor stdio open file list handling, move it out of global libc struct + + functions which open in-memory FILE stream variants all shared a tail + with __fdopen, adding the FILE structure to stdio's open file list. + replacing this common tail with a function call reduces code size and + duplication of logic. the list is also partially encapsulated now. + + function signatures were chosen to facilitate tail call optimization + and reduce the need for additional accessor functions. + + with these changes, static linked programs that do not use stdio no + longer have an open file list at all. + +commit f22a9edaf8a6f2ca1d314d18b3785558279a5c03 +Author: Rich Felker <dalias@aerifal.cx> +Date: Tue Jun 16 06:18:00 2015 +0000 + + byte-based C locale, phase 3: make MB_CUR_MAX variable to activate code + + this patch activates the new byte-based C locale (high bytes treated + as abstract code unit "characters" rather than decoded as multibyte + characters) by making the value of MB_CUR_MAX depend on the active + locale. for the C locale, the LC_CTYPE category pointer is null, + yielding a value of 1. all other locales yield a value of 4. + +commit 16f18d036d9a7bf590ee6eb86785c0a9658220b6 +Author: Rich Felker <dalias@aerifal.cx> +Date: Tue Jun 16 05:35:31 2015 +0000 + + byte-based C locale, phase 2: stdio and iconv (multibyte callers) + + this patch adjusts libc components which use the multibyte functions + internally, and which depend on them operating in a particular + encoding, to make the appropriate locale changes before calling them + and restore the calling thread's locale afterwards. activating the + byte-based C locale without these changes would cause regressions in + stdio and iconv. + + in the case of iconv, the current implementation was simply using the + multibyte functions as UTF-8 conversions. setting a multibyte UTF-8 + locale for the duration of the iconv operation allows the code to + continue working. + + in the case of stdio, POSIX requires that FILE streams have an + encoding rule bound at the time of setting wide orientation. as long + as all locales, including the C locale, used the same encoding, + treating high bytes as UTF-8, there was no need to store an encoding + rule as part of the stream's state. + + a new locale field in the FILE structure points to the locale that + should be made active during fgetwc/fputwc/ungetwc on the stream. it + cannot point to the locale active at the time the stream becomes + oriented, because this locale could be mutable (the global locale) or + could be destroyed (locale_t objects produced by newlocale) before the + stream is closed. instead, a pointer to the static C or C.UTF-8 locale + object added in commit commit aeeac9ca5490d7d90fe061ab72da446c01ddf746 + is used. this is valid since categories other than LC_CTYPE will not + affect these functions. + +commit 1507ebf837334e9e07cfab1ca1c2e88449069a80 +Author: Rich Felker <dalias@aerifal.cx> +Date: Tue Jun 16 04:44:17 2015 +0000 + + byte-based C locale, phase 1: multibyte character handling functions + + this patch makes the functions which work directly on multibyte + characters treat the high bytes as individual abstract code units + rather than as multibyte sequences when MB_CUR_MAX is 1. since + MB_CUR_MAX is presently defined as a constant 4, all of the new code + added is dead code, and optimizing compilers' code generation should + not be affected at all. a future commit will activate the new code. + + as abstract code units, bytes 0x80 to 0xff are represented by wchar_t + values 0xdf80 to 0xdfff, at the end of the surrogates range. this + ensures that they will never be misinterpreted as Unicode characters, + and that all wctype functions return false for these "characters" + without needing locale-specific logic. a high range outside of Unicode + such as 0x7fffff80 to 0x7fffffff was also considered, but since C11's + char16_t also needs to be able to represent conversions of these + bytes, the surrogate range was the natural choice. + +commit 38e2f727237230300fea6aff68802db04625fd23 +Author: Rich Felker <dalias@aerifal.cx> +Date: Tue Jun 16 04:21:38 2015 +0000 + + fix btowc corner case + + btowc is required to interpret its argument by conversion to unsigned + char, unless the argument is equal to EOF. since the conversion to + produces a non-character value anyway, we can just unconditionally + convert, for now. + +commit ee59c296d56bf26f49f354d6eb32b4b6d4190188 +Author: Szabolcs Nagy <nsz@port70.net> +Date: Wed Jun 3 10:32:14 2015 +0100 + + arm: add vdso support + + vdso will be available on arm in linux v4.2, the user-space code + for it is in kernel commit 8512287a8165592466cb9cb347ba94892e9c56a5 + +commit e3bc22f1eff87b8f029a6ab31f1a269d69e4b053 +Author: Rich Felker <dalias@aerifal.cx> +Date: Sun Jun 14 01:59:02 2015 +0000 + + refactor malloc's expand_heap to share with __simple_malloc + + this extends the brk/stack collision protection added to full malloc + in commit 276904c2f6bde3a31a24ebfa201482601d18b4f9 to also protect the + __simple_malloc function used in static-linked programs that don't + reference the free function. + + it also extends support for using mmap when brk fails, which full + malloc got in commit 5446303328adf4b4e36d9fba21848e6feb55fab4, to + __simple_malloc. + + since __simple_malloc may expand the heap by arbitrarily large + increments, the stack collision detection is enhanced to detect + interval overlap rather than just proximity of a single address to the + stack. code size is increased a bit, but this is partly offset by the + sharing of code between the two malloc implementations, which due to + linking semantics, both get linked in a program that needs the full + malloc with realloc/free support. + +commit 4ef9b828c1f39553a69e0635ac91f0fcadd6e8c6 +Author: Rich Felker <dalias@aerifal.cx> +Date: Sat Jun 13 20:53:02 2015 +0000 + + remove cancellation points in stdio + + commit 58165923890865a6ac042fafce13f440ee986fd9 added these optional + cancellation points on the basis that cancellable stdio could be + useful, to unblock threads stuck on stdio operations that will never + complete. however, the only way to ensure that cancellation can + achieve this is to violate the rules for side effects when + cancellation is acted upon, discarding knowledge of any partial data + transfer already completed. our implementation exhibited this behavior + and was thus non-conforming. + + in addition to improving correctness, removing these cancellation + points moderately reduces code size, and should significantly improve + performance on i386, where sysenter/syscall instructions can be used + instead of "int $128" for non-cancellable syscalls. + +commit 536c6d5a4205e2a3f161f2983ce1e0ac3082187d +Author: Rich Felker <dalias@aerifal.cx> +Date: Sat Jun 13 05:17:16 2015 +0000 + + fix idiom for setting stdio stream orientation to wide + + the old idiom, f->mode |= f->mode+1, was adapted from the idiom for + setting byte orientation, f->mode |= f->mode-1, but the adaptation was + incorrect. unless the stream was alreasdy set byte-oriented, this code + incremented f->mode each time it was executed, which would eventually + lead to overflow. it could be fixed by changing it to f->mode |= 1, + but upcoming changes will require slightly more work at the time of + wide orientation, so it makes sense to just call fwide. as an + optimization in the single-character functions, fwide is only called + if the stream is not already wide-oriented. + +commit f8f565df467c13248104223f99abf7f37cef7584 +Author: Rich Felker <dalias@aerifal.cx> +Date: Sat Jun 13 04:42:38 2015 +0000 + + add printing of null %s arguments as "(null)" in wide printf + + this is undefined, but supported in our implementation of the normal + printf, so for consistency the wide variant should support it too. + +commit f9e25d813860d53cd1e9b6145cc63375d2fe2529 +Author: Rich Felker <dalias@aerifal.cx> +Date: Sat Jun 13 04:37:27 2015 +0000 + + add %m support to wide printf + +commit ec634aad91f57479ef17525e33ed446c780a61f4 +Author: Rich Felker <dalias@aerifal.cx> +Date: Thu Jun 11 05:01:04 2015 +0000 + + add sh asm for vfork + +commit c30cbcb0a646b1f13a22c645616dce624465b883 +Author: Rich Felker <dalias@aerifal.cx> +Date: Wed Jun 10 02:27:40 2015 +0000 + + implement arch-generic version of __unmapself + + this can be used to put off writing an asm version of __unmapself for + new archs, or as a permanent solution on archs where it's not + practical or even possible to run momentarily with no stack. + + the concept here is simple: the caller takes a lock on a global shared + stack and uses it to make the munmap and exit syscalls. the only trick + is unlocking, which must be done after the thread exits, and this is + achieved by using the set_tid_address syscall to have the kernel zero + and futex-wake the lock word as part of the exit syscall. + +commit 276904c2f6bde3a31a24ebfa201482601d18b4f9 +Author: Rich Felker <dalias@aerifal.cx> +Date: Tue Jun 9 20:30:35 2015 +0000 + + in malloc, refuse to use brk if it grows into stack + + the linux/nommu fdpic ELF loader sets up the brk range to overlap + entirely with the main thread's stack (but growing from opposite + ends), so that the resulting failure mode for malloc is not to return + a null pointer but to start returning pointers to memory that overlaps + with the caller's stack. needless to say this extremely dangerous and + makes brk unusable. + + since it's non-trivial to detect execution environments that might be + affected by this kernel bug, and since the severity of the bug makes + any sort of detection that might yield false-negatives unsafe, we + instead check the proximity of the brk to the stack pointer each time + the brk is to be expanded. both the main thread's stack (where the + real known risk lies) and the calling thread's stack are checked. an + arbitrary gap distance of 8 MB is imposed, chosen to be larger than + linux default main-thread stack reservation sizes and larger than any + reasonable stack configuration on nommu. + + the effeciveness of this patch relies on an assumption that the amount + by which the brk is being grown is smaller than the gap limit, which + is always true for malloc's use of brk. reliance on this assumption is + why the check is being done in malloc-specific code and not in __brk. + +commit bd1eaceaa3975bd2a2a34e211cff896affaecadf +Author: Rich Felker <dalias@aerifal.cx> +Date: Tue Jun 9 20:09:27 2015 +0000 + + fix spurious errors from pwd/grp functions when nscd backend is absent + + for several pwd/grp functions, the only way the caller can distinguish + between a successful negative result ("no such user/group") and an + internal error is by clearing errno before the call and checking errno + afterwards. the nscd backend support code correctly simulated a + not-found response on systems where such a backend is not running, but + failed to restore errno. + + this commit also fixed an outdated/incorrect comment. + +commit 75ce4503950621b11fcc7f1fd1187dbcf3cde312 +Author: Rich Felker <dalias@aerifal.cx> +Date: Sun Jun 7 20:55:23 2015 +0000 + + fix regression in pre-v7 arm on kernels with kuser helper removed + + the arm atomics/TLS runtime selection code is called from + __set_thread_area and depends on having libc.auxv and __hwcap + available. commit 71f099cb7db821c51d8f39dfac622c61e54d794c moved the + first call to __set_thread_area to the top of dynamic linking stage 3, + before this data is made available, causing the runtime detection code + to always see __hwcap as zero and thereby select the atomics/TLS + implementations based on kuser helper. + + upcoming work on superh will use similar runtime detection. + + ideally this early-init code should be cleanly refactored and shared + between the dynamic linker and static-linked startup. + +commit 32f3c4f70633488550c29a2444f819aafdf345ff +Author: Rich Felker <dalias@aerifal.cx> +Date: Sun Jun 7 03:09:16 2015 +0000 + + add multiple inclusion guard to locale_impl.h + +commit 04b8360adbb6487f61aa0c00e53ec3a90a5a0d29 +Author: Rich Felker <dalias@aerifal.cx> +Date: Sun Jun 7 02:59:49 2015 +0000 + + remove redefinition of MB_CUR_MAX in locale_impl.h + + unless/until the byte-based C locale is implemented, defining + MB_CUR_MAX to 1 in the C locale is wrong. no internal code currently + uses the MB_CUR_MAX macro, but having it defined inconsistently is + error-prone. applications get the value from stdlib.h and were + unaffected. + +commit 16bf466532d7328e971012b0731ad493b017ad29 +Author: Rich Felker <dalias@aerifal.cx> +Date: Sat Jun 6 18:53:02 2015 +0000 + + make static C and C.UTF-8 locales available outside of newlocale + +commit 312eea2ea4f4363fb01b73660c08bfcf43dd3bb4 +Author: Rich Felker <dalias@aerifal.cx> +Date: Sat Jun 6 18:20:30 2015 +0000 + + remove another invalid skip of locking in ungetwc + +commit 3d7e32d28dc9962e9efc1c317c5b44b5b2df3008 +Author: Rich Felker <dalias@aerifal.cx> +Date: Sat Jun 6 18:16:22 2015 +0000 + + add macro version of ctype.h isascii function + + presumably internal code (ungetwc and fputwc) was written assuming a + macro implementation existed; otherwise use of isascii is just a + pessimization. + +commit 7e816a6487932cbb3cb71d94b609e50e81f4e5bf +Author: Rich Felker <dalias@aerifal.cx> +Date: Sat Jun 6 18:11:17 2015 +0000 + + remove invalid skip of locking in ungetwc + + aside from being invalid, the early check only optimized the error + case, and likely pessimized the common case by separating the + two branches on isascii(c) at opposite ends of the function. + +commit 63f4b9f18f3674124d8bcb119739fec85e6da005 +Author: Timo Teräs <timo.teras@iki.fi> +Date: Fri Jun 5 10:39:42 2015 +0300 + + fix uselocale((locale_t)0) not to modify locale + + commit 68630b55c0c7219fe9df70dc28ffbf9efc8021d8 made the new locale to + be assigned unconditonally resulting in crashes later on. + +--- a/.gitignore ++++ b/.gitignore +@@ -7,5 +7,7 @@ arch/*/bits/alltypes.h + config.mak + include/bits + tools/musl-gcc ++tools/musl-clang ++tools/ld.musl-clang + lib/musl-gcc.specs + src/internal/version.h +--- a/Makefile ++++ b/Makefile +@@ -51,6 +51,9 @@ TOOL_LIBS = lib/musl-gcc.specs + ALL_LIBS = $(CRT_LIBS) $(STATIC_LIBS) $(SHARED_LIBS) $(EMPTY_LIBS) $(TOOL_LIBS) + ALL_TOOLS = tools/musl-gcc + ++WRAPCC_GCC = gcc ++WRAPCC_CLANG = clang ++ + LDSO_PATHNAME = $(syslibdir)/ld-musl-$(ARCH)$(SUBARCH).so.1 + + -include config.mak +@@ -155,7 +158,11 @@ lib/musl-gcc.specs: tools/musl-gcc.specs + sh $< "$(includedir)" "$(libdir)" "$(LDSO_PATHNAME)" > $@ + + tools/musl-gcc: config.mak +- printf '#!/bin/sh\nexec "$${REALGCC:-gcc}" "$$@" -specs "%s/musl-gcc.specs"\n' "$(libdir)" > $@ ++ printf '#!/bin/sh\nexec "$${REALGCC:-$(WRAPCC_GCC)}" "$$@" -specs "%s/musl-gcc.specs"\n' "$(libdir)" > $@ ++ chmod +x $@ ++ ++tools/%-clang: tools/%-clang.in config.mak ++ sed -e 's!@CC@!$(WRAPCC_CLANG)!g' -e 's!@PREFIX@!$(prefix)!g' -e 's!@INCDIR@!$(includedir)!g' -e 's!@LIBDIR@!$(libdir)!g' -e 's!@LDSO@!$(LDSO_PATHNAME)!g' $< > $@ + chmod +x $@ + + $(DESTDIR)$(bindir)/%: tools/% +--- a/arch/arm/syscall_arch.h ++++ b/arch/arm/syscall_arch.h +@@ -72,3 +72,7 @@ static inline long __syscall6(long n, lo + register long r5 __asm__("r5") = f; + __asm_syscall("r"(r7), "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5)); + } ++ ++#define VDSO_USEFUL ++#define VDSO_CGT_SYM "__vdso_clock_gettime" ++#define VDSO_CGT_VER "LINUX_2.6" +--- a/arch/mips/bits/signal.h ++++ b/arch/mips/bits/signal.h +@@ -28,7 +28,7 @@ struct sigcontext + typedef struct + { + unsigned regmask, status; +- unsigned long long pc, regs[32], fpregs[32]; ++ unsigned long long pc, gregs[32], fpregs[32]; + unsigned ownedfp, fpc_csr, fpc_eir, used_math, dsp; + unsigned long long mdhi, mdlo; + unsigned long hi1, lo1, hi2, lo2, hi3, lo3; +--- a/arch/mips/bits/socket.h ++++ b/arch/mips/bits/socket.h +@@ -22,26 +22,31 @@ struct cmsghdr + #define SOL_SOCKET 65535 + + #define SO_DEBUG 1 +-#define SO_REUSEADDR 4 +-#define SO_TYPE 0x1008 +-#define SO_ERROR 0x1007 +-#define SO_DONTROUTE 16 +-#define SO_BROADCAST 32 ++ ++#define SO_REUSEADDR 0x0004 ++#define SO_KEEPALIVE 0x0008 ++#define SO_DONTROUTE 0x0010 ++#define SO_BROADCAST 0x0020 ++#define SO_LINGER 0x0080 ++#define SO_OOBINLINE 0x0100 ++#define SO_REUSEPORT 0x0200 + #define SO_SNDBUF 0x1001 + #define SO_RCVBUF 0x1002 +-#define SO_KEEPALIVE 8 +-#define SO_OOBINLINE 256 ++#define SO_SNDLOWAT 0x1003 ++#define SO_RCVLOWAT 0x1004 ++#define SO_RCVTIMEO 0x1006 ++#define SO_SNDTIMEO 0x1005 ++#define SO_ERROR 0x1007 ++#define SO_TYPE 0x1008 ++#define SO_ACCEPTCONN 0x1009 ++#define SO_PROTOCOL 0x1028 ++#define SO_DOMAIN 0x1029 ++ + #define SO_NO_CHECK 11 + #define SO_PRIORITY 12 +-#define SO_LINGER 128 + #define SO_BSDCOMPAT 14 +-#define SO_REUSEPORT 512 + #define SO_PASSCRED 17 + #define SO_PEERCRED 18 +-#define SO_RCVLOWAT 0x1004 +-#define SO_SNDLOWAT 0x1003 +-#define SO_RCVTIMEO 0x1006 +-#define SO_SNDTIMEO 0x1005 + #define SO_SNDBUFFORCE 31 + #define SO_RCVBUFFORCE 33 + +--- a/arch/mips/pthread_arch.h ++++ b/arch/mips/pthread_arch.h +@@ -13,4 +13,6 @@ static inline struct pthread *__pthread_ + #define TLS_ABOVE_TP + #define TP_ADJ(p) ((char *)(p) + sizeof(struct pthread) + 0x7000) + ++#define DTP_OFFSET 0x8000 ++ + #define CANCEL_REG_IP (3-(union {int __i; char __b;}){1}.__b) +--- a/arch/powerpc/bits/socket.h ++++ b/arch/powerpc/bits/socket.h +@@ -24,8 +24,6 @@ struct cmsghdr + #define SO_BROADCAST 6 + #define SO_SNDBUF 7 + #define SO_RCVBUF 8 +-#define SO_SNDBUFFORCE 32 +-#define SO_RCVBUFFORCE 33 + #define SO_KEEPALIVE 9 + #define SO_OOBINLINE 10 + #define SO_NO_CHECK 11 +@@ -39,4 +37,8 @@ struct cmsghdr + #define SO_SNDTIMEO 19 + #define SO_PASSCRED 20 + #define SO_PEERCRED 21 +- ++#define SO_ACCEPTCONN 30 ++#define SO_SNDBUFFORCE 32 ++#define SO_RCVBUFFORCE 33 ++#define SO_PROTOCOL 38 ++#define SO_DOMAIN 39 +--- a/arch/powerpc/pthread_arch.h ++++ b/arch/powerpc/pthread_arch.h +@@ -12,6 +12,8 @@ static inline struct pthread *__pthread_ + #define TLS_ABOVE_TP + #define TP_ADJ(p) ((char *)(p) + sizeof(struct pthread) + 0x7000) + ++#define DTP_OFFSET 0x8000 ++ + // offset of the PC register in mcontext_t, divided by the system wordsize + // the kernel calls the ip "nip", it's the first saved value after the 32 + // GPRs. +--- /dev/null ++++ b/arch/sh/src/__set_thread_area.c +@@ -0,0 +1,34 @@ ++#include "pthread_impl.h" ++#include "libc.h" ++#include "sh_atomic.h" ++#include <elf.h> ++ ++/* Also perform sh-specific init */ ++ ++#define CPU_HAS_LLSC 0x0040 ++ ++__attribute__((__visibility__("hidden"))) unsigned __sh_atomic_model, __sh_nommu; ++ ++int __set_thread_area(void *p) ++{ ++ size_t *aux; ++ __asm__ __volatile__ ( "ldc %0, gbr" : : "r"(p) : "memory" ); ++#ifndef __SH4A__ ++ if (__hwcap & CPU_HAS_LLSC) { ++ __sh_atomic_model = SH_A_LLSC; ++ return 0; ++ } ++#if !defined(__SH3__) && !defined(__SH4__) ++ for (aux=libc.auxv; *aux; aux+=2) { ++ if (*aux != AT_PLATFORM) continue; ++ const char *s = (void *)aux[1]; ++ if (s[0]!='s' || s[1]!='h' || s[2]!='2' || s[3]-'0'<10u) break; ++ __sh_atomic_model = SH_A_IMASK; ++ __sh_nommu = 1; ++ return 0; ++ } ++#endif ++ /* __sh_atomic_model = SH_A_GUSA; */ /* 0, default */ ++#endif ++ return 0; ++} +--- /dev/null ++++ b/arch/sh/src/__unmapself.c +@@ -0,0 +1,19 @@ ++#include "pthread_impl.h" ++ ++void __unmapself_sh_mmu(void *, size_t); ++void __unmapself_sh_nommu(void *, size_t); ++ ++#if !defined(__SH3__) && !defined(__SH4__) ++#define __unmapself __unmapself_sh_nommu ++#include "../../../src/thread/__unmapself.c" ++#undef __unmapself ++extern __attribute__((__visibility__("hidden"))) unsigned __sh_nommu; ++#else ++#define __sh_nommu 0 ++#endif ++ ++void __unmapself(void *base, size_t size) ++{ ++ if (__sh_nommu) __unmapself_sh_nommu(base, size); ++ else __unmapself_sh_mmu(base, size); ++} +--- a/arch/sh/src/atomic.c ++++ b/arch/sh/src/atomic.c +@@ -1,8 +1,26 @@ + #ifndef __SH4A__ + ++#include "sh_atomic.h" + #include "atomic.h" + #include "libc.h" + ++static inline unsigned mask() ++{ ++ unsigned sr; ++ __asm__ __volatile__ ( "\n" ++ " stc sr,r0 \n" ++ " mov r0,%0 \n" ++ " or #0xf0,r0 \n" ++ " ldc r0,sr \n" ++ : "=&r"(sr) : : "memory", "r0" ); ++ return sr; ++} ++ ++static inline void unmask(unsigned sr) ++{ ++ __asm__ __volatile__ ( "ldc %0,sr" : : "r"(sr) : "memory" ); ++} ++ + /* gusa is a hack in the kernel which lets you create a sequence of instructions + * which will be restarted if the process is preempted in the middle of the + * sequence. It will do for implementing atomics on non-smp systems. ABI is: +@@ -25,11 +43,17 @@ + " mov.l " new ", @" mem "\n" \ + "1: mov r1, r15\n" + +-#define CPU_HAS_LLSC 0x0040 +- + int __sh_cas(volatile int *p, int t, int s) + { +- if (__hwcap & CPU_HAS_LLSC) return __sh_cas_llsc(p, t, s); ++ if (__sh_atomic_model == SH_A_LLSC) return __sh_cas_llsc(p, t, s); ++ ++ if (__sh_atomic_model == SH_A_IMASK) { ++ unsigned sr = mask(); ++ int old = *p; ++ if (old==t) *p = s; ++ unmask(sr); ++ return old; ++ } + + int old; + __asm__ __volatile__( +@@ -43,7 +67,15 @@ int __sh_cas(volatile int *p, int t, int + + int __sh_swap(volatile int *x, int v) + { +- if (__hwcap & CPU_HAS_LLSC) return __sh_swap_llsc(x, v); ++ if (__sh_atomic_model == SH_A_LLSC) return __sh_swap_llsc(x, v); ++ ++ if (__sh_atomic_model == SH_A_IMASK) { ++ unsigned sr = mask(); ++ int old = *x; ++ *x = v; ++ unmask(sr); ++ return old; ++ } + + int old; + __asm__ __volatile__( +@@ -55,7 +87,15 @@ int __sh_swap(volatile int *x, int v) + + int __sh_fetch_add(volatile int *x, int v) + { +- if (__hwcap & CPU_HAS_LLSC) return __sh_fetch_add_llsc(x, v); ++ if (__sh_atomic_model == SH_A_LLSC) return __sh_fetch_add_llsc(x, v); ++ ++ if (__sh_atomic_model == SH_A_IMASK) { ++ unsigned sr = mask(); ++ int old = *x; ++ *x = old + v; ++ unmask(sr); ++ return old; ++ } + + int old, dummy; + __asm__ __volatile__( +@@ -69,7 +109,7 @@ int __sh_fetch_add(volatile int *x, int + + void __sh_store(volatile int *p, int x) + { +- if (__hwcap & CPU_HAS_LLSC) return __sh_store_llsc(p, x); ++ if (__sh_atomic_model == SH_A_LLSC) return __sh_store_llsc(p, x); + __asm__ __volatile__( + " mov.l %1, @%0\n" + : : "r"(p), "r"(x) : "memory"); +@@ -77,7 +117,15 @@ void __sh_store(volatile int *p, int x) + + void __sh_and(volatile int *x, int v) + { +- if (__hwcap & CPU_HAS_LLSC) return __sh_and_llsc(x, v); ++ if (__sh_atomic_model == SH_A_LLSC) return __sh_and_llsc(x, v); ++ ++ if (__sh_atomic_model == SH_A_IMASK) { ++ unsigned sr = mask(); ++ int old = *x; ++ *x = old & v; ++ unmask(sr); ++ return; ++ } + + int dummy; + __asm__ __volatile__( +@@ -89,7 +137,15 @@ void __sh_and(volatile int *x, int v) + + void __sh_or(volatile int *x, int v) + { +- if (__hwcap & CPU_HAS_LLSC) return __sh_or_llsc(x, v); ++ if (__sh_atomic_model == SH_A_LLSC) return __sh_or_llsc(x, v); ++ ++ if (__sh_atomic_model == SH_A_IMASK) { ++ unsigned sr = mask(); ++ int old = *x; ++ *x = old | v; ++ unmask(sr); ++ return; ++ } + + int dummy; + __asm__ __volatile__( +--- /dev/null ++++ b/arch/sh/src/sh_atomic.h +@@ -0,0 +1,15 @@ ++#ifndef _SH_ATOMIC_H ++#define _SH_ATOMIC_H ++ ++#define SH_A_GUSA 0 ++#define SH_A_LLSC 1 ++#define SH_A_CAS 2 ++#if !defined(__SH3__) && !defined(__SH4__) ++#define SH_A_IMASK 3 ++#else ++#define SH_A_IMASK -1LL /* unmatchable by unsigned int */ ++#endif ++ ++extern __attribute__((__visibility__("hidden"))) unsigned __sh_atomic_model; ++ ++#endif +--- a/arch/sh/syscall_arch.h ++++ b/arch/sh/syscall_arch.h +@@ -8,7 +8,7 @@ + */ + #define __asm_syscall(trapno, ...) do { \ + __asm__ __volatile__ ( \ +- "trapa #" #trapno "\n" \ ++ "trapa #31\n" \ + "or r0, r0\n" \ + "or r0, r0\n" \ + "or r0, r0\n" \ +--- a/configure ++++ b/configure +@@ -28,7 +28,7 @@ Optional features: + --enable-debug build with debugging information [disabled] + --enable-warnings build with recommended warnings flags [disabled] + --enable-visibility use global visibility options to optimize PIC [auto] +- --enable-gcc-wrapper build musl-gcc toolchain wrapper [auto] ++ --enable-wrapper=... build given musl toolchain wrapper [auto] + --disable-shared inhibit building shared library [enabled] + --disable-static inhibit building static library [enabled] + +@@ -123,6 +123,8 @@ bindir='$(exec_prefix)/bin' + libdir='$(prefix)/lib' + includedir='$(prefix)/include' + syslibdir='/lib' ++tools= ++tool_libs= + target= + optimize=auto + debug=no +@@ -131,6 +133,8 @@ visibility=auto + shared=auto + static=yes + wrapper=auto ++gcc_wrapper=no ++clang_wrapper=no + + for arg ; do + case "$arg" in +@@ -154,7 +158,12 @@ case "$arg" in + --disable-warnings|--enable-warnings=no) warnings=no ;; + --enable-visibility|--enable-visibility=yes) visibility=yes ;; + --disable-visibility|--enable-visibility=no) visibility=no ;; +---enable-gcc-wrapper|--enable-gcc-wrapper=yes) wrapper=yes ;; ++--enable-wrapper|--enable-wrapper=yes) wrapper=detect ;; ++--enable-wrapper=all) wrapper=yes ; gcc_wrapper=yes ; clang_wrapper=yes ;; ++--enable-wrapper=gcc) wrapper=yes ; gcc_wrapper=yes ;; ++--enable-wrapper=clang) wrapper=yes ; clang_wrapper=yes ;; ++--disable-wrapper|--enable-wrapper=no) wrapper=no ;; ++--enable-gcc-wrapper|--enable-gcc-wrapper=yes) wrapper=yes ; gcc_wrapper=yes ;; + --disable-gcc-wrapper|--enable-gcc-wrapper=no) wrapper=no ;; + --enable-*|--disable-*|--with-*|--without-*|--*dir=*|--build=*) ;; + --host=*|--target=*) target=${arg#*=} ;; +@@ -215,36 +224,51 @@ tryldflag LDFLAGS_TRY -Werror=unknown-wa + tryldflag LDFLAGS_TRY -Werror=unused-command-line-argument + + # +-# Need to know if the compiler is gcc to decide whether to build the +-# musl-gcc wrapper, and for critical bug detection in some gcc versions. ++# Need to know if the compiler is gcc or clang to decide which toolchain ++# wrappers to build. + # +-printf "checking whether compiler is gcc... " +-if fnmatch '*gcc\ version*' "$(LC_ALL=C $CC -v 2>&1)" ; then +-cc_is_gcc=yes ++printf "checking for C compiler family... " ++cc_ver="$(LC_ALL=C $CC -v 2>&1)" ++cc_family=unknown ++if fnmatch '*gcc\ version*' "$cc_ver" ; then ++cc_family=gcc ++elif fnmatch '*clang\ version*' "$cc_ver" ; then ++cc_family=clang ++fi ++echo "$cc_family" ++ ++# ++# Figure out toolchain wrapper to build ++# ++if test "$wrapper" = auto -o "$wrapper" = detect ; then ++echo "#include <stdlib.h>" > "$tmpc" ++echo "#if ! __GLIBC__" >> "$tmpc" ++echo "#error no" >> "$tmpc" ++echo "#endif" >> "$tmpc" ++printf "checking for toolchain wrapper to build... " ++if test "$wrapper" = auto && ! $CC -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then ++echo "none" ++elif test "$cc_family" = gcc ; then ++gcc_wrapper=yes ++echo "gcc" ++elif test "$cc_family" = clang ; then ++clang_wrapper=yes ++echo "clang" + else +-cc_is_gcc=no ++echo "none" ++if test "$wrapper" = detect ; then ++fail "$0: could not find an appropriate toolchain wrapper" + fi +-echo "$cc_is_gcc" +- +-# +-# Only build musl-gcc wrapper if toolchain does not already target musl +-# +-if test "$wrapper" = auto ; then +-printf "checking whether to build musl-gcc wrapper... " +-if test "$cc_is_gcc" = yes ; then +-wrapper=yes +-while read line ; do +-case "$line" in */ld-musl-*) wrapper=no ;; esac +-done <<EOF +-$($CC -dumpspecs) +-EOF +-else +-wrapper=no + fi +-echo "$wrapper" + fi + +- ++if test "$gcc_wrapper" = yes ; then ++tools="$tools tools/musl-gcc" ++tool_libs="$tool_libs lib/musl-gcc.specs" ++fi ++if test "$clang_wrapper" = yes ; then ++tools="$tools tools/musl-clang tools/ld.musl-clang" ++fi + + # + # Find the target architecture +@@ -580,11 +604,13 @@ LDFLAGS = $LDFLAGS_AUTO $LDFLAGS + CROSS_COMPILE = $CROSS_COMPILE + LIBCC = $LIBCC + OPTIMIZE_GLOBS = $OPTIMIZE_GLOBS ++ALL_TOOLS = $tools ++TOOL_LIBS = $tool_libs + EOF + test "x$static" = xno && echo "STATIC_LIBS =" + test "x$shared" = xno && echo "SHARED_LIBS =" +-test "x$wrapper" = xno && echo "ALL_TOOLS =" +-test "x$wrapper" = xno && echo "TOOL_LIBS =" ++test "x$cc_family" = xgcc && echo 'WRAPCC_GCC = $(CC)' ++test "x$cc_family" = xclang && echo 'WRAPCC_CLANG = $(CC)' + exec 1>&3 3>&- + + printf "done\n" +--- a/include/ctype.h ++++ b/include/ctype.h +@@ -64,6 +64,7 @@ int isascii(int); + int toascii(int); + #define _tolower(a) ((a)|0x20) + #define _toupper(a) ((a)&0x5f) ++#define isascii(a) (0 ? isascii(a) : (unsigned)(a) < 128) + + #endif + +--- a/include/stdlib.h ++++ b/include/stdlib.h +@@ -76,7 +76,8 @@ size_t wcstombs (char *__restrict, const + #define EXIT_FAILURE 1 + #define EXIT_SUCCESS 0 + +-#define MB_CUR_MAX ((size_t)+4) ++size_t __ctype_get_mb_cur_max(void); ++#define MB_CUR_MAX (__ctype_get_mb_cur_max()) + + #define RAND_MAX (0x7fffffff) + +--- a/include/sys/socket.h ++++ b/include/sys/socket.h +@@ -177,8 +177,11 @@ struct linger + #define SO_SNDLOWAT 19 + #define SO_RCVTIMEO 20 + #define SO_SNDTIMEO 21 ++#define SO_ACCEPTCONN 30 + #define SO_SNDBUFFORCE 32 + #define SO_RCVBUFFORCE 33 ++#define SO_PROTOCOL 38 ++#define SO_DOMAIN 39 + #endif + + #define SO_SECURITY_AUTHENTICATION 22 +@@ -195,7 +198,6 @@ struct linger + #define SO_TIMESTAMP 29 + #define SCM_TIMESTAMP SO_TIMESTAMP + +-#define SO_ACCEPTCONN 30 + #define SO_PEERSEC 31 + #define SO_PASSSEC 34 + #define SO_TIMESTAMPNS 35 +@@ -203,8 +205,6 @@ struct linger + #define SO_MARK 36 + #define SO_TIMESTAMPING 37 + #define SCM_TIMESTAMPING SO_TIMESTAMPING +-#define SO_PROTOCOL 38 +-#define SO_DOMAIN 39 + #define SO_RXQ_OVFL 40 + #define SO_WIFI_STATUS 41 + #define SCM_WIFI_STATUS SO_WIFI_STATUS +--- a/include/unistd.h ++++ b/include/unistd.h +@@ -185,7 +185,7 @@ int setresgid(gid_t, gid_t, gid_t); + int getresuid(uid_t *, uid_t *, uid_t *); + int getresgid(gid_t *, gid_t *, gid_t *); + char *get_current_dir_name(void); +-void syncfs(int); ++int syncfs(int); + int euidaccess(const char *, int); + int eaccess(const char *, int); + #endif +--- a/src/ctype/__ctype_get_mb_cur_max.c ++++ b/src/ctype/__ctype_get_mb_cur_max.c +@@ -1,6 +1,7 @@ +-#include <stddef.h> ++#include <stdlib.h> ++#include "locale_impl.h" + + size_t __ctype_get_mb_cur_max() + { +- return 4; ++ return MB_CUR_MAX; + } +--- a/src/ctype/isascii.c ++++ b/src/ctype/isascii.c +@@ -1,4 +1,5 @@ + #include <ctype.h> ++#undef isascii + + int isascii(int c) + { +--- a/src/env/__stack_chk_fail.c ++++ b/src/env/__stack_chk_fail.c +@@ -25,4 +25,8 @@ void __stack_chk_fail_local(void) + a_crash(); + } + ++#else ++ ++weak_alias(__stack_chk_fail, __stack_chk_fail_local); ++ + #endif +--- a/src/internal/libc.h ++++ b/src/internal/libc.h +@@ -17,8 +17,6 @@ struct __libc { + int secure; + volatile int threads_minus_1; + size_t *auxv; +- FILE *ofl_head; +- volatile int ofl_lock[2]; + size_t tls_size; + size_t page_size; + struct __locale_struct global_locale; +--- a/src/internal/locale_impl.h ++++ b/src/internal/locale_impl.h +@@ -1,3 +1,6 @@ ++#ifndef _LOCALE_IMPL_H ++#define _LOCALE_IMPL_H ++ + #include <locale.h> + #include <stdlib.h> + #include "libc.h" +@@ -12,6 +15,10 @@ struct __locale_map { + const struct __locale_map *next; + }; + ++extern const struct __locale_map __c_dot_utf8; ++extern const struct __locale_struct __c_locale; ++extern const struct __locale_struct __c_dot_utf8_locale; ++ + const struct __locale_map *__get_locale(int, const char *); + const char *__mo_lookup(const void *, size_t, const char *); + const char *__lctrans(const char *, const struct __locale_map *); +@@ -20,9 +27,14 @@ const char *__lctrans_cur(const char *); + #define LCTRANS(msg, lc, loc) __lctrans(msg, (loc)->cat[(lc)]) + #define LCTRANS_CUR(msg) __lctrans_cur(msg) + ++#define C_LOCALE ((locale_t)&__c_locale) ++#define UTF8_LOCALE ((locale_t)&__c_dot_utf8_locale) ++ + #define CURRENT_LOCALE (__pthread_self()->locale) + + #define CURRENT_UTF8 (!!__pthread_self()->locale->cat[LC_CTYPE]) + + #undef MB_CUR_MAX + #define MB_CUR_MAX (CURRENT_UTF8 ? 4 : 1) ++ ++#endif +--- a/src/internal/pthread_impl.h ++++ b/src/internal/pthread_impl.h +@@ -94,6 +94,10 @@ struct __timer { + #define CANARY canary + #endif + ++#ifndef DTP_OFFSET ++#define DTP_OFFSET 0 ++#endif ++ + #define SIGTIMER 32 + #define SIGCANCEL 33 + #define SIGSYNCCALL 34 +--- a/src/internal/sh/syscall.s ++++ b/src/internal/sh/syscall.s +@@ -13,7 +13,7 @@ __syscall: + mov.l @r15, r7 + mov.l @(4,r15), r0 + mov.l @(8,r15), r1 +- trapa #22 ++ trapa #31 + or r0, r0 + or r0, r0 + or r0, r0 +--- a/src/internal/stdio_impl.h ++++ b/src/internal/stdio_impl.h +@@ -47,6 +47,7 @@ struct _IO_FILE { + unsigned char *shend; + off_t shlim, shcnt; + FILE *prev_locked, *next_locked; ++ struct __locale_struct *locale; + }; + + size_t __stdio_read(FILE *, unsigned char *, size_t); +@@ -75,8 +76,9 @@ int __putc_unlocked(int, FILE *); + FILE *__fdopen(int, const char *); + int __fmodeflags(const char *); + +-#define OFLLOCK() LOCK(libc.ofl_lock) +-#define OFLUNLOCK() UNLOCK(libc.ofl_lock) ++FILE *__ofl_add(FILE *f); ++FILE **__ofl_lock(void); ++void __ofl_unlock(void); + + #define feof(f) ((f)->flags & F_EOF) + #define ferror(f) ((f)->flags & F_ERR) +--- a/src/ldso/dynlink.c ++++ b/src/ldso/dynlink.c +@@ -156,7 +156,7 @@ static uint32_t gnu_hash(const char *s0) + const unsigned char *s = (void *)s0; + uint_fast32_t h = 5381; + for (; *s; s++) +- h = h*33 + *s; ++ h += h*32 + *s; + return h; + } + +@@ -174,32 +174,39 @@ static Sym *sysv_lookup(const char *s, u + return 0; + } + +-static Sym *gnu_lookup(const char *s, uint32_t h1, struct dso *dso) ++static Sym *gnu_lookup(uint32_t h1, uint32_t *hashtab, struct dso *dso, const char *s) + { +- Sym *syms = dso->syms; +- char *strings = dso->strings; +- uint32_t *hashtab = dso->ghashtab; + uint32_t nbuckets = hashtab[0]; + uint32_t *buckets = hashtab + 4 + hashtab[2]*(sizeof(size_t)/4); +- uint32_t h2; +- uint32_t *hashval; + uint32_t i = buckets[h1 % nbuckets]; + + if (!i) return 0; + +- hashval = buckets + nbuckets + (i - hashtab[1]); ++ uint32_t *hashval = buckets + nbuckets + (i - hashtab[1]); + + for (h1 |= 1; ; i++) { +- h2 = *hashval++; +- if ((!dso->versym || dso->versym[i] >= 0) +- && (h1 == (h2|1)) && !strcmp(s, strings + syms[i].st_name)) +- return syms+i; ++ uint32_t h2 = *hashval++; ++ if ((h1 == (h2|1)) && (!dso->versym || dso->versym[i] >= 0) ++ && !strcmp(s, dso->strings + dso->syms[i].st_name)) ++ return dso->syms+i; + if (h2 & 1) break; + } + + return 0; + } + ++static Sym *gnu_lookup_filtered(uint32_t h1, uint32_t *hashtab, struct dso *dso, const char *s, uint32_t fofs, size_t fmask) ++{ ++ const size_t *bloomwords = (const void *)(hashtab+4); ++ size_t f = bloomwords[fofs & (hashtab[2]-1)]; ++ if (!(f & fmask)) return 0; ++ ++ f >>= (h1 >> hashtab[3]) % (8 * sizeof f); ++ if (!(f & 1)) return 0; ++ ++ return gnu_lookup(h1, hashtab, dso, s); ++} ++ + #define OK_TYPES (1<<STT_NOTYPE | 1<<STT_OBJECT | 1<<STT_FUNC | 1<<STT_COMMON | 1<<STT_TLS) + #define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK | 1<<STB_GNU_UNIQUE) + +@@ -209,14 +216,20 @@ static Sym *gnu_lookup(const char *s, ui + + static struct symdef find_sym(struct dso *dso, const char *s, int need_def) + { +- uint32_t h = 0, gh = 0; ++ uint32_t h = 0, gh, gho, *ght; ++ size_t ghm = 0; + struct symdef def = {0}; + for (; dso; dso=dso->next) { + Sym *sym; + if (!dso->global) continue; +- if (dso->ghashtab) { +- if (!gh) gh = gnu_hash(s); +- sym = gnu_lookup(s, gh, dso); ++ if ((ght = dso->ghashtab)) { ++ if (!ghm) { ++ gh = gnu_hash(s); ++ int maskbits = 8 * sizeof ghm; ++ gho = gh / maskbits; ++ ghm = 1ul << gh % maskbits; ++ } ++ sym = gnu_lookup_filtered(gh, ght, dso, s, gho, ghm); + } else { + if (!h) h = sysv_hash(s); + sym = sysv_lookup(s, h, dso); +@@ -337,7 +350,7 @@ static void do_relocs(struct dso *dso, s + *reloc_addr = def.dso->tls_id; + break; + case REL_DTPOFF: +- *reloc_addr = tls_val + addend; ++ *reloc_addr = tls_val + addend - DTP_OFFSET; + break; + #ifdef TLS_ABOVE_TP + case REL_TPOFF: +@@ -423,6 +436,28 @@ static void reclaim_gaps(struct dso *dso + } + } + ++static void *mmap_fixed(void *p, size_t n, int prot, int flags, int fd, off_t off) ++{ ++ char *q = mmap(p, n, prot, flags, fd, off); ++ if (q != MAP_FAILED || errno != EINVAL) return q; ++ /* Fallbacks for MAP_FIXED failure on NOMMU kernels. */ ++ if (flags & MAP_ANONYMOUS) { ++ memset(p, 0, n); ++ return p; ++ } ++ ssize_t r; ++ if (lseek(fd, off, SEEK_SET) < 0) return MAP_FAILED; ++ for (q=p; n; q+=r, off+=r, n-=r) { ++ r = read(fd, q, n); ++ if (r < 0 && errno != EINTR) return MAP_FAILED; ++ if (!r) { ++ memset(q, 0, n); ++ break; ++ } ++ } ++ return p; ++} ++ + static void *map_library(int fd, struct dso *dso) + { + Ehdr buf[(896+sizeof(Ehdr))/sizeof(Ehdr)]; +@@ -524,19 +559,20 @@ static void *map_library(int fd, struct + prot = (((ph->p_flags&PF_R) ? PROT_READ : 0) | + ((ph->p_flags&PF_W) ? PROT_WRITE: 0) | + ((ph->p_flags&PF_X) ? PROT_EXEC : 0)); +- if (mmap(base+this_min, this_max-this_min, prot, MAP_PRIVATE|MAP_FIXED, fd, off_start) == MAP_FAILED) ++ if (mmap_fixed(base+this_min, this_max-this_min, prot, MAP_PRIVATE|MAP_FIXED, fd, off_start) == MAP_FAILED) + goto error; + if (ph->p_memsz > ph->p_filesz) { + size_t brk = (size_t)base+ph->p_vaddr+ph->p_filesz; + size_t pgbrk = brk+PAGE_SIZE-1 & -PAGE_SIZE; + memset((void *)brk, 0, pgbrk-brk & PAGE_SIZE-1); +- if (pgbrk-(size_t)base < this_max && mmap((void *)pgbrk, (size_t)base+this_max-pgbrk, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) == MAP_FAILED) ++ if (pgbrk-(size_t)base < this_max && mmap_fixed((void *)pgbrk, (size_t)base+this_max-pgbrk, prot, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) == MAP_FAILED) + goto error; + } + } + for (i=0; ((size_t *)(base+dyn))[i]; i+=2) + if (((size_t *)(base+dyn))[i]==DT_TEXTREL) { +- if (mprotect(map, map_len, PROT_READ|PROT_WRITE|PROT_EXEC) < 0) ++ if (mprotect(map, map_len, PROT_READ|PROT_WRITE|PROT_EXEC) ++ && errno != ENOSYS) + goto error; + break; + } +@@ -927,7 +963,8 @@ static void reloc_all(struct dso *p) + do_relocs(p, (void *)(p->base+dyn[DT_RELA]), dyn[DT_RELASZ], 3); + + if (head != &ldso && p->relro_start != p->relro_end && +- mprotect(p->base+p->relro_start, p->relro_end-p->relro_start, PROT_READ) < 0) { ++ mprotect(p->base+p->relro_start, p->relro_end-p->relro_start, PROT_READ) ++ && errno != ENOSYS) { + error("Error relocating %s: RELRO protection failed: %m", + p->name); + if (runtime) longjmp(*rtld_fail, 1); +@@ -1078,7 +1115,7 @@ void *__tls_get_new(size_t *v) + __block_all_sigs(&set); + if (v[0]<=(size_t)self->dtv[0]) { + __restore_sigs(&set); +- return (char *)self->dtv[v[0]]+v[1]; ++ return (char *)self->dtv[v[0]]+v[1]+DTP_OFFSET; + } + + /* This is safe without any locks held because, if the caller +@@ -1111,7 +1148,7 @@ void *__tls_get_new(size_t *v) + if (p->tls_id == v[0]) break; + } + __restore_sigs(&set); +- return mem + v[1]; ++ return mem + v[1] + DTP_OFFSET; + } + + static void update_tls_size() +@@ -1192,6 +1229,17 @@ _Noreturn void __dls3(size_t *sp) + char **argv_orig = argv; + char **envp = argv+argc+1; + ++ /* Find aux vector just past environ[] and use it to initialize ++ * global data that may be needed before we can make syscalls. */ ++ __environ = envp; ++ for (i=argc+1; argv[i]; i++); ++ libc.auxv = auxv = (void *)(argv+i+1); ++ decode_vec(auxv, aux, AUX_CNT); ++ __hwcap = aux[AT_HWCAP]; ++ libc.page_size = aux[AT_PAGESZ]; ++ libc.secure = ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID] ++ || aux[AT_GID]!=aux[AT_EGID] || aux[AT_SECURE]); ++ + /* Setup early thread pointer in builtin_tls for ldso/libc itself to + * use during dynamic linking. If possible it will also serve as the + * thread pointer at runtime. */ +@@ -1200,25 +1248,11 @@ _Noreturn void __dls3(size_t *sp) + a_crash(); + } + +- /* Find aux vector just past environ[] */ +- for (i=argc+1; argv[i]; i++) +- if (!memcmp(argv[i], "LD_LIBRARY_PATH=", 16)) +- env_path = argv[i]+16; +- else if (!memcmp(argv[i], "LD_PRELOAD=", 11)) +- env_preload = argv[i]+11; +- auxv = (void *)(argv+i+1); +- +- decode_vec(auxv, aux, AUX_CNT); +- + /* Only trust user/env if kernel says we're not suid/sgid */ +- if ((aux[0]&0x7800)!=0x7800 || aux[AT_UID]!=aux[AT_EUID] +- || aux[AT_GID]!=aux[AT_EGID] || aux[AT_SECURE]) { +- env_path = 0; +- env_preload = 0; +- libc.secure = 1; ++ if (!libc.secure) { ++ env_path = getenv("LD_LIBRARY_PATH"); ++ env_preload = getenv("LD_PRELOAD"); + } +- libc.page_size = aux[AT_PAGESZ]; +- libc.auxv = auxv; + + /* If the main program was already loaded by the kernel, + * AT_PHDR will point to some location other than the dynamic +@@ -1523,7 +1557,7 @@ void *__tls_get_addr(size_t *); + static void *do_dlsym(struct dso *p, const char *s, void *ra) + { + size_t i; +- uint32_t h = 0, gh = 0; ++ uint32_t h = 0, gh = 0, *ght; + Sym *sym; + if (p == head || p == RTLD_DEFAULT || p == RTLD_NEXT) { + if (p == RTLD_DEFAULT) { +@@ -1541,9 +1575,9 @@ static void *do_dlsym(struct dso *p, con + } + if (invalid_dso_handle(p)) + return 0; +- if (p->ghashtab) { ++ if ((ght = p->ghashtab)) { + gh = gnu_hash(s); +- sym = gnu_lookup(s, gh, p); ++ sym = gnu_lookup(gh, ght, p, s); + } else { + h = sysv_hash(s); + sym = sysv_lookup(s, h, p); +@@ -1553,9 +1587,9 @@ static void *do_dlsym(struct dso *p, con + if (sym && sym->st_value && (1<<(sym->st_info&0xf) & OK_TYPES)) + return p->base + sym->st_value; + if (p->deps) for (i=0; p->deps[i]; i++) { +- if (p->deps[i]->ghashtab) { ++ if ((ght = p->deps[i]->ghashtab)) { + if (!gh) gh = gnu_hash(s); +- sym = gnu_lookup(s, gh, p->deps[i]); ++ sym = gnu_lookup(gh, ght, p->deps[i], s); + } else { + if (!h) h = sysv_hash(s); + sym = sysv_lookup(s, h, p->deps[i]); +--- a/src/linux/syncfs.c ++++ b/src/linux/syncfs.c +@@ -2,7 +2,7 @@ + #include <unistd.h> + #include "syscall.h" + +-void syncfs(int fd) ++int syncfs(int fd) + { +- __syscall(SYS_syncfs, fd); ++ return syscall(SYS_syncfs, fd); + } +--- /dev/null ++++ b/src/locale/c_locale.c +@@ -0,0 +1,15 @@ ++#include "locale_impl.h" ++#include <stdint.h> ++ ++static const uint32_t empty_mo[] = { 0x950412de, 0, -1, -1, -1 }; ++ ++const struct __locale_map __c_dot_utf8 = { ++ .map = empty_mo, ++ .map_size = sizeof empty_mo, ++ .name = "C.UTF-8" ++}; ++ ++const struct __locale_struct __c_locale = { 0 }; ++const struct __locale_struct __c_dot_utf8_locale = { ++ .cat[LC_CTYPE] = &__c_dot_utf8 ++}; +--- a/src/locale/iconv.c ++++ b/src/locale/iconv.c +@@ -5,6 +5,7 @@ + #include <stdlib.h> + #include <limits.h> + #include <stdint.h> ++#include "locale_impl.h" + + #define UTF_32BE 0300 + #define UTF_16LE 0301 +@@ -165,9 +166,12 @@ size_t iconv(iconv_t cd0, char **restric + int err; + unsigned char type = map[-1]; + unsigned char totype = tomap[-1]; ++ locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; + + if (!in || !*in || !*inb) return 0; + ++ *ploc = UTF8_LOCALE; ++ + for (; *inb; *in+=l, *inb-=l) { + c = *(unsigned char *)*in; + l = 1; +@@ -431,6 +435,7 @@ size_t iconv(iconv_t cd0, char **restric + break; + } + } ++ *ploc = loc; + return x; + ilseq: + err = EILSEQ; +@@ -445,5 +450,6 @@ starved: + x = -1; + end: + errno = err; ++ *ploc = loc; + return x; + } +--- a/src/locale/langinfo.c ++++ b/src/locale/langinfo.c +@@ -33,7 +33,8 @@ char *__nl_langinfo_l(nl_item item, loca + int idx = item & 65535; + const char *str; + +- if (item == CODESET) return "UTF-8"; ++ if (item == CODESET) ++ return MB_CUR_MAX==1 ? "UTF-8-CODE-UNITS" : "UTF-8"; + + switch (cat) { + case LC_NUMERIC: +--- a/src/locale/locale_map.c ++++ b/src/locale/locale_map.c +@@ -24,14 +24,6 @@ static const char envvars[][12] = { + "LC_MESSAGES", + }; + +-static const uint32_t empty_mo[] = { 0x950412de, 0, -1, -1, -1 }; +- +-const struct __locale_map __c_dot_utf8 = { +- .map = empty_mo, +- .map_size = sizeof empty_mo, +- .name = "C.UTF-8" +-}; +- + const struct __locale_map *__get_locale(int cat, const char *val) + { + static int lock[2]; +@@ -107,8 +99,8 @@ const struct __locale_map *__get_locale( + * sake of being able to do message translations at the + * application level. */ + if (!new && (new = malloc(sizeof *new))) { +- new->map = empty_mo; +- new->map_size = sizeof empty_mo; ++ new->map = __c_dot_utf8.map; ++ new->map_size = __c_dot_utf8.map_size; + memcpy(new->name, val, n); + new->name[n] = 0; + new->next = loc_head; +--- a/src/locale/newlocale.c ++++ b/src/locale/newlocale.c +@@ -3,16 +3,9 @@ + #include "locale_impl.h" + #include "libc.h" + +-extern const struct __locale_map __c_dot_utf8; +- +-static const struct __locale_struct c_locale = { 0 }; +-static const struct __locale_struct c_dot_utf8_locale = { +- .cat[LC_CTYPE] = &__c_dot_utf8 +-}; +- + int __loc_is_allocated(locale_t loc) + { +- return loc && loc != &c_locale && loc != &c_dot_utf8_locale; ++ return loc && loc != C_LOCALE && loc != UTF8_LOCALE; + } + + locale_t __newlocale(int mask, const char *name, locale_t loc) +@@ -44,9 +37,9 @@ locale_t __newlocale(int mask, const cha + } + + if (!j) +- return (locale_t)&c_locale; +- if (j==1 && tmp.cat[LC_CTYPE]==c_dot_utf8_locale.cat[LC_CTYPE]) +- return (locale_t)&c_dot_utf8_locale; ++ return C_LOCALE; ++ if (j==1 && tmp.cat[LC_CTYPE]==&__c_dot_utf8) ++ return UTF8_LOCALE; + + if ((loc = malloc(sizeof *loc))) *loc = tmp; + +--- a/src/locale/uselocale.c ++++ b/src/locale/uselocale.c +@@ -8,9 +8,7 @@ locale_t __uselocale(locale_t new) + locale_t old = self->locale; + locale_t global = &libc.global_locale; + +- if (new == LC_GLOBAL_LOCALE) new = global; +- +- self->locale = new; ++ if (new) self->locale = new == LC_GLOBAL_LOCALE ? global : new; + + return old == global ? LC_GLOBAL_LOCALE : old; + } +--- a/src/malloc/calloc.c ++++ b/src/malloc/calloc.c +@@ -1,22 +1,13 @@ + #include <stdlib.h> + #include <errno.h> + ++void *__malloc0(size_t); ++ + void *calloc(size_t m, size_t n) + { +- void *p; +- size_t *z; + if (n && m > (size_t)-1/n) { + errno = ENOMEM; + return 0; + } +- n *= m; +- p = malloc(n); +- if (!p) return 0; +- /* Only do this for non-mmapped chunks */ +- if (((size_t *)p)[-1] & 7) { +- /* Only write words that are not already zero */ +- m = (n + sizeof *z - 1)/sizeof *z; +- for (z=p; m; m--, z++) if (*z) *z=0; +- } +- return p; ++ return __malloc0(n * m); + } +--- /dev/null ++++ b/src/malloc/expand_heap.c +@@ -0,0 +1,72 @@ ++#include <limits.h> ++#include <stdint.h> ++#include <errno.h> ++#include <sys/mman.h> ++#include "libc.h" ++#include "syscall.h" ++ ++/* This function returns true if the interval [old,new] ++ * intersects the 'len'-sized interval below &libc.auxv ++ * (interpreted as the main-thread stack) or below &b ++ * (the current stack). It is used to defend against ++ * buggy brk implementations that can cross the stack. */ ++ ++static int traverses_stack_p(uintptr_t old, uintptr_t new) ++{ ++ const uintptr_t len = 8<<20; ++ uintptr_t a, b; ++ ++ b = (uintptr_t)libc.auxv; ++ a = b > len ? b-len : 0; ++ if (new>a && old<b) return 1; ++ ++ b = (uintptr_t)&b; ++ a = b > len ? b-len : 0; ++ if (new>a && old<b) return 1; ++ ++ return 0; ++} ++ ++void *__mmap(void *, size_t, int, int, int, off_t); ++ ++/* Expand the heap in-place if brk can be used, or otherwise via mmap, ++ * using an exponential lower bound on growth by mmap to make ++ * fragmentation asymptotically irrelevant. The size argument is both ++ * an input and an output, since the caller needs to know the size ++ * allocated, which will be larger than requested due to page alignment ++ * and mmap minimum size rules. The caller is responsible for locking ++ * to prevent concurrent calls. */ ++ ++void *__expand_heap(size_t *pn) ++{ ++ static uintptr_t brk; ++ static unsigned mmap_step; ++ size_t n = *pn; ++ ++ if (n > SIZE_MAX/2 - PAGE_SIZE) { ++ errno = ENOMEM; ++ return 0; ++ } ++ n += -n & PAGE_SIZE-1; ++ ++ if (!brk) { ++ brk = __syscall(SYS_brk, 0); ++ brk += -brk & PAGE_SIZE-1; ++ } ++ ++ if (n < SIZE_MAX-brk && !traverses_stack_p(brk, brk+n) ++ && __syscall(SYS_brk, brk+n)==brk+n) { ++ *pn = n; ++ brk += n; ++ return (void *)(brk-n); ++ } ++ ++ size_t min = (size_t)PAGE_SIZE << mmap_step/2; ++ if (n < min) n = min; ++ void *area = __mmap(0, n, PROT_READ|PROT_WRITE, ++ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); ++ if (area == MAP_FAILED) return 0; ++ *pn = n; ++ mmap_step++; ++ return area; ++} +--- a/src/malloc/lite_malloc.c ++++ b/src/malloc/lite_malloc.c +@@ -4,43 +4,47 @@ + #include <errno.h> + #include "libc.h" + +-uintptr_t __brk(uintptr_t); +- + #define ALIGN 16 + ++void *__expand_heap(size_t *); ++ + void *__simple_malloc(size_t n) + { +- static uintptr_t cur, brk; +- uintptr_t base, new; ++ static char *cur, *end; + static volatile int lock[2]; +- size_t align=1; ++ size_t align=1, pad; ++ void *p; + + if (!n) n++; +- if (n > SIZE_MAX/2) goto toobig; +- + while (align<n && align<ALIGN) + align += align; +- n = n + align - 1 & -align; + + LOCK(lock); +- if (!cur) cur = brk = __brk(0)+16; +- base = cur + align-1 & -align; +- if (n > SIZE_MAX - PAGE_SIZE - base) goto fail; +- if (base+n > brk) { +- new = base+n + PAGE_SIZE-1 & -PAGE_SIZE; +- if (__brk(new) != new) goto fail; +- brk = new; +- } +- cur = base+n; +- UNLOCK(lock); + +- return (void *)base; ++ pad = -(uintptr_t)cur & align-1; ++ ++ if (n <= SIZE_MAX/2 + ALIGN) n += pad; ++ ++ if (n > end-cur) { ++ size_t m = n; ++ char *new = __expand_heap(&m); ++ if (!new) { ++ UNLOCK(lock); ++ return 0; ++ } ++ if (new != end) { ++ cur = new; ++ n -= pad; ++ pad = 0; ++ } ++ end = new + m; ++ } + +-fail: ++ p = cur + pad; ++ cur += n; + UNLOCK(lock); +-toobig: +- errno = ENOMEM; +- return 0; ++ return p; + } + + weak_alias(__simple_malloc, malloc); ++weak_alias(__simple_malloc, __malloc0); +--- a/src/malloc/malloc.c ++++ b/src/malloc/malloc.c +@@ -13,7 +13,6 @@ + #define inline inline __attribute__((always_inline)) + #endif + +-uintptr_t __brk(uintptr_t); + void *__mmap(void *, size_t, int, int, int, off_t); + int __munmap(void *, size_t); + void *__mremap(void *, size_t, size_t, int, ...); +@@ -31,13 +30,9 @@ struct bin { + }; + + static struct { +- uintptr_t brk; +- size_t *heap; + volatile uint64_t binmap; + struct bin bins[64]; +- volatile int brk_lock[2]; + volatile int free_lock[2]; +- unsigned mmap_step; + } mal; + + +@@ -152,69 +147,52 @@ void __dump_heap(int x) + } + #endif + ++void *__expand_heap(size_t *); ++ + static struct chunk *expand_heap(size_t n) + { +- static int init; ++ static int heap_lock[2]; ++ static void *end; ++ void *p; + struct chunk *w; +- uintptr_t new; +- +- lock(mal.brk_lock); +- +- if (!init) { +- mal.brk = __brk(0); +-#ifdef SHARED +- mal.brk = mal.brk + PAGE_SIZE-1 & -PAGE_SIZE; +-#endif +- mal.brk = mal.brk + 2*SIZE_ALIGN-1 & -SIZE_ALIGN; +- mal.heap = (void *)mal.brk; +- init = 1; +- } +- +- if (n > SIZE_MAX - mal.brk - 2*PAGE_SIZE) goto fail; +- new = mal.brk + n + SIZE_ALIGN + PAGE_SIZE - 1 & -PAGE_SIZE; +- n = new - mal.brk; +- +- if (__brk(new) != new) { +- size_t min = (size_t)PAGE_SIZE << mal.mmap_step/2; +- n += -n & PAGE_SIZE-1; +- if (n < min) n = min; +- void *area = __mmap(0, n, PROT_READ|PROT_WRITE, +- MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); +- if (area == MAP_FAILED) goto fail; + +- mal.mmap_step++; +- area = (char *)area + SIZE_ALIGN - OVERHEAD; +- w = area; ++ /* The argument n already accounts for the caller's chunk ++ * overhead needs, but if the heap can't be extended in-place, ++ * we need room for an extra zero-sized sentinel chunk. */ ++ n += SIZE_ALIGN; ++ ++ lock(heap_lock); ++ ++ p = __expand_heap(&n); ++ if (!p) { ++ unlock(heap_lock); ++ return 0; ++ } ++ ++ /* If not just expanding existing space, we need to make a ++ * new sentinel chunk below the allocated space. */ ++ if (p != end) { ++ /* Valid/safe because of the prologue increment. */ + n -= SIZE_ALIGN; ++ p = (char *)p + SIZE_ALIGN; ++ w = MEM_TO_CHUNK(p); + w->psize = 0 | C_INUSE; +- w->csize = n | C_INUSE; +- w = NEXT_CHUNK(w); +- w->psize = n | C_INUSE; +- w->csize = 0 | C_INUSE; +- +- unlock(mal.brk_lock); +- +- return area; + } + +- w = MEM_TO_CHUNK(mal.heap); +- w->psize = 0 | C_INUSE; +- +- w = MEM_TO_CHUNK(new); ++ /* Record new heap end and fill in footer. */ ++ end = (char *)p + n; ++ w = MEM_TO_CHUNK(end); + w->psize = n | C_INUSE; + w->csize = 0 | C_INUSE; + +- w = MEM_TO_CHUNK(mal.brk); ++ /* Fill in header, which may be new or may be replacing a ++ * zero-size sentinel header at the old end-of-heap. */ ++ w = MEM_TO_CHUNK(p); + w->csize = n | C_INUSE; +- mal.brk = new; +- +- unlock(mal.brk_lock); ++ ++ unlock(heap_lock); + + return w; +-fail: +- unlock(mal.brk_lock); +- errno = ENOMEM; +- return 0; + } + + static int adjust_size(size_t *n) +@@ -378,6 +356,17 @@ void *malloc(size_t n) + return CHUNK_TO_MEM(c); + } + ++void *__malloc0(size_t n) ++{ ++ void *p = malloc(n); ++ if (p && !IS_MMAPPED(MEM_TO_CHUNK(p))) { ++ size_t *z; ++ n = (n + sizeof *z - 1)/sizeof *z; ++ for (z=p; n; n--, z++) if (*z) *z=0; ++ } ++ return p; ++} ++ + void *realloc(void *p, size_t n) + { + struct chunk *self, *next; +--- a/src/misc/syslog.c ++++ b/src/misc/syslog.c +@@ -48,12 +48,8 @@ void closelog(void) + + static void __openlog() + { +- int fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); +- if (fd < 0) return; +- if (connect(fd, (void *)&log_addr, sizeof log_addr) < 0) +- close(fd); +- else +- log_fd = fd; ++ log_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); ++ if (log_fd >= 0) connect(log_fd, (void *)&log_addr, sizeof log_addr); + } + + void openlog(const char *ident, int opt, int facility) +@@ -78,6 +74,11 @@ void openlog(const char *ident, int opt, + pthread_setcancelstate(cs, 0); + } + ++static int is_lost_conn(int e) ++{ ++ return e==ECONNREFUSED || e==ECONNRESET || e==ENOTCONN || e==EPIPE; ++} ++ + static void _vsyslog(int priority, const char *message, va_list ap) + { + char timebuf[16]; +@@ -107,7 +108,10 @@ static void _vsyslog(int priority, const + if (l2 >= sizeof buf - l) l = sizeof buf - 1; + else l += l2; + if (buf[l-1] != '\n') buf[l++] = '\n'; +- if (send(log_fd, buf, l, 0) < 0 && (log_opt & LOG_CONS)) { ++ if (send(log_fd, buf, l, 0) < 0 && (!is_lost_conn(errno) ++ || connect(log_fd, (void *)&log_addr, sizeof log_addr) < 0 ++ || send(log_fd, buf, l, 0) < 0) ++ && (log_opt & LOG_CONS)) { + fd = open("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if (fd >= 0) { + dprintf(fd, "%.*s", l-hlen, buf+hlen); +--- a/src/multibyte/btowc.c ++++ b/src/multibyte/btowc.c +@@ -1,7 +1,10 @@ + #include <stdio.h> + #include <wchar.h> ++#include <stdlib.h> ++#include "internal.h" + + wint_t btowc(int c) + { +- return c<128U ? c : EOF; ++ int b = (unsigned char)c; ++ return b<128U ? b : (MB_CUR_MAX==1 && c!=EOF) ? CODEUNIT(c) : WEOF; + } +--- a/src/multibyte/internal.h ++++ b/src/multibyte/internal.h +@@ -23,3 +23,10 @@ extern const uint32_t bittab[]; + + #define SA 0xc2u + #define SB 0xf4u ++ ++/* Arbitrary encoding for representing code units instead of characters. */ ++#define CODEUNIT(c) (0xdfff & (signed char)(c)) ++#define IS_CODEUNIT(c) ((unsigned)(c)-0xdf80 < 0x80) ++ ++/* Get inline definition of MB_CUR_MAX. */ ++#include "locale_impl.h" +--- a/src/multibyte/mbrtowc.c ++++ b/src/multibyte/mbrtowc.c +@@ -4,6 +4,7 @@ + * unnecessary. + */ + ++#include <stdlib.h> + #include <wchar.h> + #include <errno.h> + #include "internal.h" +@@ -27,6 +28,7 @@ size_t mbrtowc(wchar_t *restrict wc, con + if (!n) return -2; + if (!c) { + if (*s < 0x80) return !!(*wc = *s); ++ if (MB_CUR_MAX==1) return (*wc = CODEUNIT(*s)), 1; + if (*s-SA > SB-SA) goto ilseq; + c = bittab[*s++-SA]; n--; + } +--- a/src/multibyte/mbsrtowcs.c ++++ b/src/multibyte/mbsrtowcs.c +@@ -7,6 +7,8 @@ + #include <stdint.h> + #include <wchar.h> + #include <errno.h> ++#include <string.h> ++#include <stdlib.h> + #include "internal.h" + + size_t mbsrtowcs(wchar_t *restrict ws, const char **restrict src, size_t wn, mbstate_t *restrict st) +@@ -24,6 +26,23 @@ size_t mbsrtowcs(wchar_t *restrict ws, c + } + } + ++ if (MB_CUR_MAX==1) { ++ if (!ws) return strlen((const char *)s); ++ for (;;) { ++ if (!wn) { ++ *src = (const void *)s; ++ return wn0; ++ } ++ if (!*s) break; ++ c = *s++; ++ *ws++ = CODEUNIT(c); ++ wn--; ++ } ++ *ws = 0; ++ *src = 0; ++ return wn0-wn; ++ } ++ + if (!ws) for (;;) { + if (*s-1u < 0x7f && (uintptr_t)s%4 == 0) { + while (!(( *(uint32_t*)s | *(uint32_t*)s-0x01010101) & 0x80808080)) { +--- a/src/multibyte/mbtowc.c ++++ b/src/multibyte/mbtowc.c +@@ -4,6 +4,7 @@ + * unnecessary. + */ + ++#include <stdlib.h> + #include <wchar.h> + #include <errno.h> + #include "internal.h" +@@ -19,6 +20,7 @@ int mbtowc(wchar_t *restrict wc, const c + if (!wc) wc = &dummy; + + if (*s < 0x80) return !!(*wc = *s); ++ if (MB_CUR_MAX==1) return (*wc = CODEUNIT(*s)), 1; + if (*s-SA > SB-SA) goto ilseq; + c = bittab[*s++-SA]; + +--- a/src/multibyte/wcrtomb.c ++++ b/src/multibyte/wcrtomb.c +@@ -4,8 +4,10 @@ + * unnecessary. + */ + ++#include <stdlib.h> + #include <wchar.h> + #include <errno.h> ++#include "internal.h" + + size_t wcrtomb(char *restrict s, wchar_t wc, mbstate_t *restrict st) + { +@@ -13,6 +15,13 @@ size_t wcrtomb(char *restrict s, wchar_t + if ((unsigned)wc < 0x80) { + *s = wc; + return 1; ++ } else if (MB_CUR_MAX == 1) { ++ if (!IS_CODEUNIT(wc)) { ++ errno = EILSEQ; ++ return -1; ++ } ++ *s = wc; ++ return 1; + } else if ((unsigned)wc < 0x800) { + *s++ = 0xc0 | (wc>>6); + *s = 0x80 | (wc&0x3f); +--- a/src/multibyte/wctob.c ++++ b/src/multibyte/wctob.c +@@ -1,8 +1,10 @@ +-#include <stdio.h> + #include <wchar.h> ++#include <stdlib.h> ++#include "internal.h" + + int wctob(wint_t c) + { + if (c < 128U) return c; ++ if (MB_CUR_MAX==1 && IS_CODEUNIT(c)) return (unsigned char)c; + return EOF; + } +--- a/src/network/ns_parse.c ++++ b/src/network/ns_parse.c +@@ -95,7 +95,7 @@ int ns_skiprr(const unsigned char *ptr, + p += r; + } + } +- return ptr - p; ++ return p - ptr; + bad: + errno = EMSGSIZE; + return -1; +--- a/src/passwd/nscd_query.c ++++ b/src/passwd/nscd_query.c +@@ -32,6 +32,7 @@ FILE *__nscd_query(int32_t req, const ch + }, + .msg_iovlen = 2 + }; ++ int errno_save = errno; + + *swap = 0; + retry: +@@ -50,11 +51,14 @@ retry: + return f; + + if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { +- /* If there isn't a running nscd we return -1 to indicate that +- * that is precisely what happened +- */ +- if (errno == EACCES || errno == ECONNREFUSED || errno == ENOENT) ++ /* If there isn't a running nscd we simulate a "not found" ++ * result and the caller is responsible for calling ++ * fclose on the (unconnected) socket. The value of ++ * errno must be left unchanged in this case. */ ++ if (errno == EACCES || errno == ECONNREFUSED || errno == ENOENT) { ++ errno = errno_save; + return f; ++ } + goto error; + } + +--- /dev/null ++++ b/src/process/sh/vfork.s +@@ -0,0 +1,23 @@ ++.global __vfork ++.weak vfork ++.type __vfork,@function ++.type vfork,@function ++__vfork: ++vfork: ++ mov #95, r3 ++ add r3, r3 ++ ++ trapa #31 ++ or r0, r0 ++ or r0, r0 ++ or r0, r0 ++ or r0, r0 ++ or r0, r0 ++ ++ mov r0, r4 ++ mov.l 1f, r0 ++2: braf r0 ++ nop ++ .align 2 ++ .hidden __syscall_ret ++1: .long __syscall_ret@PLT-(2b+4-.) +--- a/src/regex/fnmatch.c ++++ b/src/regex/fnmatch.c +@@ -18,6 +18,7 @@ + #include <stdlib.h> + #include <wchar.h> + #include <wctype.h> ++#include "locale_impl.h" + + #define END 0 + #define UNMATCHABLE -2 +@@ -229,7 +230,7 @@ static int fnmatch_internal(const char * + * On illegal sequences we may get it wrong, but in that case + * we necessarily have a matching failure anyway. */ + for (s=endstr; s>str && tailcnt; tailcnt--) { +- if (s[-1] < 128U) s--; ++ if (s[-1] < 128U || MB_CUR_MAX==1) s--; + else while ((unsigned char)*--s-0x80U<0x40 && s>str); + } + if (tailcnt) return FNM_NOMATCH; +--- a/src/signal/sh/restore.s ++++ b/src/signal/sh/restore.s +@@ -2,7 +2,7 @@ + .type __restore, @function + __restore: + mov #119, r3 !__NR_sigreturn +- trapa #16 ++ trapa #31 + + or r0, r0 + or r0, r0 +@@ -15,7 +15,7 @@ __restore: + __restore_rt: + mov #100, r3 !__NR_rt_sigreturn + add #73, r3 +- trapa #16 ++ trapa #31 + + or r0, r0 + or r0, r0 +--- a/src/stdio/__fdopen.c ++++ b/src/stdio/__fdopen.c +@@ -54,13 +54,7 @@ FILE *__fdopen(int fd, const char *mode) + if (!libc.threaded) f->lock = -1; + + /* Add new FILE to open file list */ +- OFLLOCK(); +- f->next = libc.ofl_head; +- if (libc.ofl_head) libc.ofl_head->prev = f; +- libc.ofl_head = f; +- OFLUNLOCK(); +- +- return f; ++ return __ofl_add(f); + } + + weak_alias(__fdopen, fdopen); +--- a/src/stdio/__stdio_exit.c ++++ b/src/stdio/__stdio_exit.c +@@ -16,8 +16,7 @@ static void close_file(FILE *f) + void __stdio_exit(void) + { + FILE *f; +- OFLLOCK(); +- for (f=libc.ofl_head; f; f=f->next) close_file(f); ++ for (f=*__ofl_lock(); f; f=f->next) close_file(f); + close_file(__stdin_used); + close_file(__stdout_used); + } +--- a/src/stdio/__stdio_read.c ++++ b/src/stdio/__stdio_read.c +@@ -1,12 +1,5 @@ + #include "stdio_impl.h" + #include <sys/uio.h> +-#include <pthread.h> +- +-static void cleanup(void *p) +-{ +- FILE *f = p; +- if (!f->lockcount) __unlockfile(f); +-} + + size_t __stdio_read(FILE *f, unsigned char *buf, size_t len) + { +@@ -16,9 +9,7 @@ size_t __stdio_read(FILE *f, unsigned ch + }; + ssize_t cnt; + +- pthread_cleanup_push(cleanup, f); +- cnt = syscall_cp(SYS_readv, f->fd, iov, 2); +- pthread_cleanup_pop(0); ++ cnt = syscall(SYS_readv, f->fd, iov, 2); + if (cnt <= 0) { + f->flags |= F_EOF ^ ((F_ERR^F_EOF) & cnt); + return cnt; +--- a/src/stdio/__stdio_write.c ++++ b/src/stdio/__stdio_write.c +@@ -1,12 +1,5 @@ + #include "stdio_impl.h" + #include <sys/uio.h> +-#include <pthread.h> +- +-static void cleanup(void *p) +-{ +- FILE *f = p; +- if (!f->lockcount) __unlockfile(f); +-} + + size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len) + { +@@ -19,9 +12,7 @@ size_t __stdio_write(FILE *f, const unsi + int iovcnt = 2; + ssize_t cnt; + for (;;) { +- pthread_cleanup_push(cleanup, f); +- cnt = syscall_cp(SYS_writev, f->fd, iov, iovcnt); +- pthread_cleanup_pop(0); ++ cnt = syscall(SYS_writev, f->fd, iov, iovcnt); + if (cnt == rem) { + f->wend = f->buf + f->buf_size; + f->wpos = f->wbase = f->buf; +@@ -34,11 +25,8 @@ size_t __stdio_write(FILE *f, const unsi + } + rem -= cnt; + if (cnt > iov[0].iov_len) { +- f->wpos = f->wbase = f->buf; + cnt -= iov[0].iov_len; + iov++; iovcnt--; +- } else if (iovcnt == 2) { +- f->wbase += cnt; + } + iov[0].iov_base = (char *)iov[0].iov_base + cnt; + iov[0].iov_len -= cnt; +--- a/src/stdio/fclose.c ++++ b/src/stdio/fclose.c +@@ -14,11 +14,11 @@ int fclose(FILE *f) + __unlist_locked_file(f); + + if (!(perm = f->flags & F_PERM)) { +- OFLLOCK(); ++ FILE **head = __ofl_lock(); + if (f->prev) f->prev->next = f->next; + if (f->next) f->next->prev = f->prev; +- if (libc.ofl_head == f) libc.ofl_head = f->next; +- OFLUNLOCK(); ++ if (*head == f) *head = f->next; ++ __ofl_unlock(); + } + + r = fflush(f); +--- a/src/stdio/fflush.c ++++ b/src/stdio/fflush.c +@@ -35,13 +35,12 @@ int fflush(FILE *f) + + r = __stdout_used ? fflush(__stdout_used) : 0; + +- OFLLOCK(); +- for (f=libc.ofl_head; f; f=f->next) { ++ for (f=*__ofl_lock(); f; f=f->next) { + FLOCK(f); + if (f->wpos > f->wbase) r |= __fflush_unlocked(f); + FUNLOCK(f); + } +- OFLUNLOCK(); ++ __ofl_unlock(); + + return r; + } +--- a/src/stdio/fgetwc.c ++++ b/src/stdio/fgetwc.c +@@ -1,8 +1,9 @@ + #include "stdio_impl.h" ++#include "locale_impl.h" + #include <wchar.h> + #include <errno.h> + +-wint_t __fgetwc_unlocked(FILE *f) ++static wint_t __fgetwc_unlocked_internal(FILE *f) + { + mbstate_t st = { 0 }; + wchar_t wc; +@@ -10,8 +11,6 @@ wint_t __fgetwc_unlocked(FILE *f) + unsigned char b; + size_t l; + +- f->mode |= f->mode+1; +- + /* Convert character from buffer if possible */ + if (f->rpos < f->rend) { + l = mbrtowc(&wc, (void *)f->rpos, f->rend - f->rpos, &st); +@@ -39,6 +38,16 @@ wint_t __fgetwc_unlocked(FILE *f) + return wc; + } + ++wint_t __fgetwc_unlocked(FILE *f) ++{ ++ locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; ++ if (f->mode <= 0) fwide(f, 1); ++ *ploc = f->locale; ++ wchar_t wc = __fgetwc_unlocked_internal(f); ++ *ploc = loc; ++ return wc; ++} ++ + wint_t fgetwc(FILE *f) + { + wint_t c; +--- a/src/stdio/fmemopen.c ++++ b/src/stdio/fmemopen.c +@@ -110,11 +110,5 @@ FILE *fmemopen(void *restrict buf, size_ + + if (!libc.threaded) f->lock = -1; + +- OFLLOCK(); +- f->next = libc.ofl_head; +- if (libc.ofl_head) libc.ofl_head->prev = f; +- libc.ofl_head = f; +- OFLUNLOCK(); +- +- return f; ++ return __ofl_add(f); + } +--- a/src/stdio/fopen.c ++++ b/src/stdio/fopen.c +@@ -18,7 +18,7 @@ FILE *fopen(const char *restrict filenam + /* Compute the flags to pass to open() */ + flags = __fmodeflags(mode); + +- fd = sys_open_cp(filename, flags, 0666); ++ fd = sys_open(filename, flags, 0666); + if (fd < 0) return 0; + if (flags & O_CLOEXEC) + __syscall(SYS_fcntl, fd, F_SETFD, FD_CLOEXEC); +--- a/src/stdio/fputwc.c ++++ b/src/stdio/fputwc.c +@@ -1,4 +1,5 @@ + #include "stdio_impl.h" ++#include "locale_impl.h" + #include <wchar.h> + #include <limits.h> + #include <ctype.h> +@@ -7,8 +8,10 @@ wint_t __fputwc_unlocked(wchar_t c, FILE + { + char mbc[MB_LEN_MAX]; + int l; ++ locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; + +- f->mode |= f->mode+1; ++ if (f->mode <= 0) fwide(f, 1); ++ *ploc = f->locale; + + if (isascii(c)) { + c = putc_unlocked(c, f); +@@ -20,6 +23,8 @@ wint_t __fputwc_unlocked(wchar_t c, FILE + l = wctomb(mbc, c); + if (l < 0 || __fwritex((void *)mbc, l, f) < l) c = WEOF; + } ++ if (c==WEOF) f->flags |= F_ERR; ++ *ploc = loc; + return c; + } + +--- a/src/stdio/fputws.c ++++ b/src/stdio/fputws.c +@@ -1,23 +1,28 @@ + #include "stdio_impl.h" ++#include "locale_impl.h" + #include <wchar.h> + + int fputws(const wchar_t *restrict ws, FILE *restrict f) + { + unsigned char buf[BUFSIZ]; + size_t l=0; ++ locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; + + FLOCK(f); + +- f->mode |= f->mode+1; ++ fwide(f, 1); ++ *ploc = f->locale; + + while (ws && (l = wcsrtombs((void *)buf, (void*)&ws, sizeof buf, 0))+1 > 1) + if (__fwritex(buf, l, f) < l) { + FUNLOCK(f); ++ *ploc = loc; + return -1; + } + + FUNLOCK(f); + ++ *ploc = loc; + return l; /* 0 or -1 */ + } + +--- a/src/stdio/fwide.c ++++ b/src/stdio/fwide.c +@@ -1,13 +1,14 @@ +-#include <wchar.h> + #include "stdio_impl.h" +- +-#define SH (8*sizeof(int)-1) +-#define NORMALIZE(x) ((x)>>SH | -((-(x))>>SH)) ++#include "locale_impl.h" + + int fwide(FILE *f, int mode) + { + FLOCK(f); +- if (!f->mode) f->mode = NORMALIZE(mode); ++ if (mode) { ++ if (!f->locale) f->locale = MB_CUR_MAX==1 ++ ? C_LOCALE : UTF8_LOCALE; ++ if (!f->mode) f->mode = mode>0 ? 1 : -1; ++ } + mode = f->mode; + FUNLOCK(f); + return mode; +--- /dev/null ++++ b/src/stdio/ofl.c +@@ -0,0 +1,16 @@ ++#include "stdio_impl.h" ++#include "libc.h" ++ ++static FILE *ofl_head; ++static volatile int ofl_lock[2]; ++ ++FILE **__ofl_lock() ++{ ++ LOCK(ofl_lock); ++ return &ofl_head; ++} ++ ++void __ofl_unlock() ++{ ++ UNLOCK(ofl_lock); ++} +--- /dev/null ++++ b/src/stdio/ofl_add.c +@@ -0,0 +1,11 @@ ++#include "stdio_impl.h" ++ ++FILE *__ofl_add(FILE *f) ++{ ++ FILE **head = __ofl_lock(); ++ f->next = *head; ++ if (*head) (*head)->prev = f; ++ *head = f; ++ __ofl_unlock(); ++ return f; ++} +--- a/src/stdio/open_memstream.c ++++ b/src/stdio/open_memstream.c +@@ -79,11 +79,5 @@ FILE *open_memstream(char **bufp, size_t + + if (!libc.threaded) f->lock = -1; + +- OFLLOCK(); +- f->next = libc.ofl_head; +- if (libc.ofl_head) libc.ofl_head->prev = f; +- libc.ofl_head = f; +- OFLUNLOCK(); +- +- return f; ++ return __ofl_add(f); + } +--- a/src/stdio/open_wmemstream.c ++++ b/src/stdio/open_wmemstream.c +@@ -81,11 +81,5 @@ FILE *open_wmemstream(wchar_t **bufp, si + + if (!libc.threaded) f->lock = -1; + +- OFLLOCK(); +- f->next = libc.ofl_head; +- if (libc.ofl_head) libc.ofl_head->prev = f; +- libc.ofl_head = f; +- OFLUNLOCK(); +- +- return f; ++ return __ofl_add(f); + } +--- a/src/stdio/ungetwc.c ++++ b/src/stdio/ungetwc.c +@@ -1,4 +1,5 @@ + #include "stdio_impl.h" ++#include "locale_impl.h" + #include <wchar.h> + #include <limits.h> + #include <ctype.h> +@@ -8,21 +9,19 @@ wint_t ungetwc(wint_t c, FILE *f) + { + unsigned char mbc[MB_LEN_MAX]; + int l=1; +- +- if (c == WEOF) return c; +- +- /* Try conversion early so we can fail without locking if invalid */ +- if (!isascii(c) && (l = wctomb((void *)mbc, c)) < 0) +- return WEOF; ++ locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; + + FLOCK(f); + +- f->mode |= f->mode+1; ++ if (f->mode <= 0) fwide(f, 1); ++ *ploc = f->locale; + + if (!f->rpos) __toread(f); +- if (!f->rpos || f->rpos < f->buf - UNGET + l) { ++ if (!f->rpos || f->rpos < f->buf - UNGET + l || c == WEOF || ++ (!isascii(c) && (l = wctomb((void *)mbc, c)) < 0)) { + FUNLOCK(f); +- return EOF; ++ *ploc = loc; ++ return WEOF; + } + + if (isascii(c)) *--f->rpos = c; +@@ -31,5 +30,6 @@ wint_t ungetwc(wint_t c, FILE *f) + f->flags &= ~F_EOF; + + FUNLOCK(f); ++ *ploc = loc; + return c; + } +--- a/src/stdio/vfwprintf.c ++++ b/src/stdio/vfwprintf.c +@@ -293,7 +293,10 @@ static int wprintf_core(FILE *f, const w + if ((fl&LEFT_ADJ)) fprintf(f, "%.*s", w-p, ""); + l=w; + continue; ++ case 'm': ++ arg.p = strerror(errno); + case 's': ++ if (!arg.p) arg.p = "(null)"; + bs = arg.p; + if (p<0) p = INT_MAX; + for (i=l=0; l<p && (i=mbtowc(&wc, bs, MB_LEN_MAX))>0; bs+=i, l++); +@@ -356,7 +359,7 @@ int vfwprintf(FILE *restrict f, const wc + } + + FLOCK(f); +- f->mode |= f->mode+1; ++ fwide(f, 1); + olderr = f->flags & F_ERR; + f->flags &= ~F_ERR; + ret = wprintf_core(f, fmt, &ap2, nl_arg, nl_type); +--- a/src/stdio/vfwscanf.c ++++ b/src/stdio/vfwscanf.c +@@ -104,7 +104,7 @@ int vfwscanf(FILE *restrict f, const wch + + FLOCK(f); + +- f->mode |= f->mode+1; ++ fwide(f, 1); + + for (p=fmt; *p; p++) { + +--- a/src/string/strverscmp.c ++++ b/src/string/strverscmp.c +@@ -2,40 +2,33 @@ + #include <ctype.h> + #include <string.h> + +-int strverscmp(const char *l, const char *r) ++int strverscmp(const char *l0, const char *r0) + { +- int haszero=1; +- while (*l==*r) { +- if (!*l) return 0; ++ const unsigned char *l = (const void *)l0; ++ const unsigned char *r = (const void *)r0; ++ size_t i, dp, j; ++ int z = 1; + +- if (*l=='0') { +- if (haszero==1) { +- haszero=0; +- } +- } else if (isdigit(*l)) { +- if (haszero==1) { +- haszero=2; +- } +- } else { +- haszero=1; +- } +- l++; r++; ++ /* Find maximal matching prefix and track its maximal digit ++ * suffix and whether those digits are all zeros. */ ++ for (dp=i=0; l[i]==r[i]; i++) { ++ int c = l[i]; ++ if (!c) return 0; ++ if (!isdigit(c)) dp=i+1, z=1; ++ else if (c!='0') z=0; + } +- if (haszero==1 && (*l=='0' || *r=='0')) { +- haszero=0; +- } +- if ((isdigit(*l) && isdigit(*r) ) && haszero) { +- size_t lenl=0, lenr=0; +- while (isdigit(l[lenl]) ) lenl++; +- while (isdigit(r[lenr]) ) lenr++; +- if (lenl==lenr) { +- return (*l - *r); +- } else if (lenl>lenr) { +- return 1; +- } else { +- return -1; +- } +- } else { +- return (*l - *r); ++ ++ if (l[dp]!='0' && r[dp]!='0') { ++ /* If we're not looking at a digit sequence that began ++ * with a zero, longest digit string is greater. */ ++ for (j=i; isdigit(l[j]); j++) ++ if (!isdigit(r[j])) return 1; ++ if (isdigit(r[j])) return -1; ++ } else if (z && dp<i && (isdigit(l[i]) || isdigit(r[i]))) { ++ /* Otherwise, if common prefix of digit sequence is ++ * all zeros, digits order less than non-digits. */ ++ return (unsigned char)(l[i]-'0') - (unsigned char)(r[i]-'0'); + } ++ ++ return l[i] - r[i]; + } +--- a/src/thread/__tls_get_addr.c ++++ b/src/thread/__tls_get_addr.c +@@ -8,9 +8,9 @@ void *__tls_get_addr(size_t *v) + __attribute__((__visibility__("hidden"))) + void *__tls_get_new(size_t *); + if (v[0]<=(size_t)self->dtv[0]) +- return (char *)self->dtv[v[0]]+v[1]; ++ return (char *)self->dtv[v[0]]+v[1]+DTP_OFFSET; + return __tls_get_new(v); + #else +- return (char *)self->dtv[1]+v[1]; ++ return (char *)self->dtv[1]+v[1]+DTP_OFFSET; + #endif + } +--- /dev/null ++++ b/src/thread/__unmapself.c +@@ -0,0 +1,29 @@ ++#include "pthread_impl.h" ++#include "atomic.h" ++#include "syscall.h" ++/* cheat and reuse CRTJMP macro from dynlink code */ ++#include "dynlink.h" ++ ++static volatile int lock; ++static void *unmap_base; ++static size_t unmap_size; ++static char shared_stack[256]; ++ ++static void do_unmap() ++{ ++ __syscall(SYS_munmap, unmap_base, unmap_size); ++ __syscall(SYS_exit); ++} ++ ++void __unmapself(void *base, size_t size) ++{ ++ int tid=__pthread_self()->tid; ++ char *stack = shared_stack + sizeof shared_stack; ++ stack -= (uintptr_t)stack % 16; ++ while (lock || a_cas(&lock, 0, tid)) ++ a_spin(); ++ __syscall(SYS_set_tid_address, &lock); ++ unmap_base = base; ++ unmap_size = size; ++ CRTJMP(do_unmap, stack); ++} +--- a/src/thread/mips/__unmapself.s ++++ b/src/thread/mips/__unmapself.s +@@ -2,6 +2,7 @@ + .global __unmapself + .type __unmapself,@function + __unmapself: ++ move $sp, $25 + li $2, 4091 + syscall + li $4, 0 +--- a/src/thread/pthread_create.c ++++ b/src/thread/pthread_create.c +@@ -191,8 +191,9 @@ int __pthread_create(pthread_t *restrict + if (!libc.can_do_threads) return ENOSYS; + self = __pthread_self(); + if (!libc.threaded) { +- for (FILE *f=libc.ofl_head; f; f=f->next) ++ for (FILE *f=*__ofl_lock(); f; f=f->next) + init_file_lock(f); ++ __ofl_unlock(); + init_file_lock(__stdin_used); + init_file_lock(__stdout_used); + init_file_lock(__stderr_used); +@@ -231,7 +232,8 @@ int __pthread_create(pthread_t *restrict + if (guard) { + map = __mmap(0, size, PROT_NONE, MAP_PRIVATE|MAP_ANON, -1, 0); + if (map == MAP_FAILED) goto fail; +- if (__mprotect(map+guard, size-guard, PROT_READ|PROT_WRITE)) { ++ if (__mprotect(map+guard, size-guard, PROT_READ|PROT_WRITE) ++ && errno != ENOSYS) { + __munmap(map, size); + goto fail; + } +--- a/src/thread/sh/__set_thread_area.s ++++ b/src/thread/sh/__set_thread_area.s +@@ -1,6 +0,0 @@ +-.global __set_thread_area +-.type __set_thread_area, @function +-__set_thread_area: +- ldc r4, gbr +- rts +- mov #0, r0 +--- a/src/thread/sh/__unmapself.s ++++ b/src/thread/sh/__unmapself.s +@@ -1,9 +1,9 @@ + .text +-.global __unmapself +-.type __unmapself, @function +-__unmapself: ++.global __unmapself_sh_mmu ++.type __unmapself_sh_mmu, @function ++__unmapself_sh_mmu: + mov #91, r3 ! SYS_munmap +- trapa #18 ++ trapa #31 + + or r0, r0 + or r0, r0 +@@ -13,7 +13,7 @@ __unmapself: + + mov #1, r3 ! SYS_exit + mov #0, r4 +- trapa #17 ++ trapa #31 + + or r0, r0 + or r0, r0 +--- a/src/thread/sh/clone.s ++++ b/src/thread/sh/clone.s +@@ -17,7 +17,7 @@ __clone: + mov.l @r15, r6 ! r6 = ptid + mov.l @(8,r15), r7 ! r7 = ctid + mov.l @(4,r15), r0 ! r0 = tls +- trapa #21 ++ trapa #31 + + or r0, r0 + or r0, r0 +@@ -38,7 +38,7 @@ __clone: + + mov #1, r3 ! __NR_exit + mov r0, r4 +- trapa #17 ++ trapa #31 + + or r0, r0 + or r0, r0 +--- a/src/thread/sh/syscall_cp.s ++++ b/src/thread/sh/syscall_cp.s +@@ -31,7 +31,7 @@ L1: .long __cancel@PLT-(1b-.) + mov.l @(4,r15), r7 + mov.l @(8,r15), r0 + mov.l @(12,r15), r1 +- trapa #22 ++ trapa #31 + + __cp_end: + ! work around hardware bug +--- a/src/time/__tz.c ++++ b/src/time/__tz.c +@@ -125,7 +125,8 @@ static void do_tzset() + "/usr/share/zoneinfo/\0/share/zoneinfo/\0/etc/zoneinfo/\0"; + + s = getenv("TZ"); +- if (!s || !*s) s = "/etc/localtime"; ++ if (!s) s = "/etc/localtime"; ++ if (!*s) s = __gmt; + + if (old_tz && !strcmp(s, old_tz)) return; + +--- a/src/unistd/sh/pipe.s ++++ b/src/unistd/sh/pipe.s +@@ -2,7 +2,7 @@ + .type pipe, @function + pipe: + mov #42, r3 +- trapa #17 ++ trapa #31 + + ! work around hardware bug + or r0, r0 +--- /dev/null ++++ b/tools/ld.musl-clang.in +@@ -0,0 +1,51 @@ ++#!/bin/sh ++cc="@CC@" ++libc_lib="@LIBDIR@" ++ldso="@LDSO@" ++cleared= ++shared= ++userlinkdir= ++userlink= ++ ++for x ; do ++ test "$cleared" || set -- ; cleared=1 ++ ++ case "$x" in ++ -L-user-start) ++ userlinkdir=1 ++ ;; ++ -L-user-end) ++ userlinkdir= ++ ;; ++ -L*) ++ test "$userlinkdir" && set -- "$@" "$x" ++ ;; ++ -l-user-start) ++ userlink=1 ++ ;; ++ -l-user-end) ++ userlink= ++ ;; ++ crtbegin*.o|crtend*.o) ++ set -- "$@" $($cc -print-file-name=$x) ++ ;; ++ -lgcc|-lgcc_eh) ++ file=lib${x#-l}.a ++ set -- "$@" $($cc -print-file-name=$file) ++ ;; ++ -l*) ++ test "$userlink" && set -- "$@" "$x" ++ ;; ++ -shared) ++ shared=1 ++ set -- "$@" -shared ++ ;; ++ -sysroot=*|--sysroot=*) ++ ;; ++ *) ++ set -- "$@" "$x" ++ ;; ++ esac ++done ++ ++exec $($cc -print-prog-name=ld) -nostdlib "$@" -lc -dynamic-linker "$ldso" +--- /dev/null ++++ b/tools/musl-clang.in +@@ -0,0 +1,35 @@ ++#!/bin/sh ++cc="@CC@" ++libc="@PREFIX@" ++libc_inc="@INCDIR@" ++libc_lib="@LIBDIR@" ++thisdir="`cd "$(dirname "$0")"; pwd`" ++ ++# prevent clang from running the linker (and erroring) on no input. ++sflags= ++eflags= ++for x ; do ++ case "$x" in ++ -l*) input=1 ;; ++ *) input= ;; ++ esac ++ if test "$input" ; then ++ sflags="-l-user-start" ++ eflags="-l-user-end" ++ break ++ fi ++done ++ ++exec $cc \ ++ -B"$thisdir" \ ++ -fuse-ld=musl-clang \ ++ -static-libgcc \ ++ -nostdinc \ ++ --sysroot "$libc" \ ++ -isystem "$libc_inc" \ ++ -L-user-start \ ++ $sflags \ ++ "$@" \ ++ $eflags \ ++ -L"$libc_lib" \ ++ -L-user-end |