diff options
-rw-r--r-- | toolchain/musl/Config.version | 2 | ||||
-rw-r--r-- | toolchain/musl/common.mk | 2 | ||||
-rw-r--r-- | toolchain/musl/patches/001-git-2015-06-04.patch | 2015 | ||||
-rw-r--r-- | toolchain/musl/patches/001-git-2015-06-16.patch | 1578 | ||||
-rw-r--r-- | toolchain/musl/patches/900-iconv_size_hack.patch | 12 |
5 files changed, 1586 insertions, 2023 deletions
diff --git a/toolchain/musl/Config.version b/toolchain/musl/Config.version index c560c603b7..d325f19e33 100644 --- a/toolchain/musl/Config.version +++ b/toolchain/musl/Config.version @@ -3,6 +3,6 @@ if USE_MUSL config MUSL_VERSION string depends on USE_MUSL - default "1.1.9" + default "1.1.10" endif diff --git a/toolchain/musl/common.mk b/toolchain/musl/common.mk index f4a34e469e..88481d897d 100644 --- a/toolchain/musl/common.mk +++ b/toolchain/musl/common.mk @@ -11,7 +11,7 @@ PKG_NAME:=musl PKG_VERSION:=$(call qstrip,$(CONFIG_MUSL_VERSION)) PKG_RELEASE=1 -PKG_MD5SUM:=14e8c5ac74f887d53256b3dcaf9b4aaa +PKG_MD5SUM:=fc30892ee582c91920505bbd0021049f PKG_SOURCE_URL:=http://www.musl-libc.org/releases PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz diff --git a/toolchain/musl/patches/001-git-2015-06-04.patch b/toolchain/musl/patches/001-git-2015-06-04.patch deleted file mode 100644 index 0baea67670..0000000000 --- a/toolchain/musl/patches/001-git-2015-06-04.patch +++ /dev/null @@ -1,2015 +0,0 @@ -commit b6a6cd703ffefa6352249fb01f4da28d85d17306 -Author: Rich Felker <dalias@aerifal.cx> -Date: Thu Jun 4 11:45:17 2015 -0400 - - fix dynamic linker regression processing R_*_NONE type relocations - - commit f3ddd173806fd5c60b3f034528ca24542aecc5b9 inadvertently removed - the early check for "none" type relocations, causing the address - dso->base+0 to be dereferenced to obtain an addend. shared libraries, - (including libc.so) and PIE executables were unaffected, since their - base addresses are the actual address of their mappings and are - readable. non-PIE main executables, however, have a base address of 0 - because their load addresses are absolute and not offset at load time. - - in practice none-type relocations do not arise with toolchains that - are in use except on mips, and on mips it's moderately rare for a - non-PIE executable to have a relocation table, since the mips-specific - got processing serves in its place for most purposes. - -commit 585ba14df4799d50ec9682ce75825d2eafec2a6a -Author: Rich Felker <dalias@aerifal.cx> -Date: Wed Jun 3 02:00:44 2015 -0400 - - add additional Makefile dependency rules for rcrt1.o PIE start file - -commit 2b4fcfdacf93c3dfd6ac15e31790a9e154374679 -Author: Rich Felker <dalias@aerifal.cx> -Date: Thu May 28 23:08:12 2015 -0400 - - fix failure of ungetc and ungetwc to work on files in eof status - - these functions were written to handle clearing eof status, but failed - to account for the __toread function's handling of eof. with this - patch applied, __toread still returns EOF when the file is in eof - status, so that read operations will fail, but it also sets up valid - buffer pointers for read mode, which are set to the end of the buffer - rather than the beginning in order to make the whole buffer available - to ungetc/ungetwc. - - minor changes to __uflow were needed since it's now possible to have - non-zero buffer pointers while in eof status. as made, these changes - remove a 'fast path' bypassing the function call to __toread, which - could be reintroduced with slightly different logic, but since - ordinary files have a syscall in f->read, optimizing the code path - does not seem worthwhile. - - the __stdio_read function is also updated not to zero the read buffer - pointers on eof/error. while not necessary for correctness, this - change avoids the overhead of calling __toread in ungetc after - reaching eof, and it also reduces code size and increases consistency - with the fmemopen read operation which does not zero the pointers. - -commit b6e7c664677ab7c77f183b8c41105f2be519800c -Author: Rich Felker <dalias@aerifal.cx> -Date: Thu May 28 15:37:23 2015 -0400 - - add missing legacy LFS64 macros in sys/resource.h - - based on patch by Felix Janda, with RLIM64_SAVED_CUR and - RLIM64_SAVED_MAX added for completeness. - -commit fc431d3f76bb9bde34a89e4a3e4d0c27de959855 -Author: Shiz <hi@shiz.me> -Date: Thu May 28 05:52:22 2015 +0200 - - configure: work around compilers that merely warn for unknown options - - some compilers (such as clang) accept unknown options without error, - but then print warnings on each invocation, cluttering the build - output and burying meaningful warnings. this patch makes configure's - tryflag and tryldflag functions use additional options to turn the - unknown-option warnings into errors, if available, but only at check - time. these options are not output in config.mak to avoid the risk of - spurious build breakage; if they work, they will have already done - their job at configure time. - -commit aeeac9ca5490d7d90fe061ab72da446c01ddf746 -Author: Rich Felker <dalias@aerifal.cx> -Date: Wed May 27 15:54:47 2015 -0400 - - implement fail-safe static locales for newlocale - - this frees applications which need to make temporary use of the C - locale (via uselocale) from the possibility that newlocale might fail. - - the C.UTF-8 locale is also provided as a static locale. presently they - behave the same, but this may change in the future. - -commit 11858d31aa020df3e7e7dedf49f9870ce12f31cc -Author: Rich Felker <dalias@aerifal.cx> -Date: Wed May 27 03:32:46 2015 -0400 - - rename internal locale file handling locale maps - - since the __setlocalecat function was removed, the filename - __setlocalecat.c no longer made sense. - -commit 61a3364d246e72b903da8b76c2e27a225a51351e -Author: Rich Felker <dalias@aerifal.cx> -Date: Wed May 27 03:22:52 2015 -0400 - - overhaul locale internals to treat categories roughly uniformly - - previously, LC_MESSAGES was treated specially as the only category - which could be set to a locale name without a definition file, in - order to facilitate gettext message translations when no libc locale - was available. LC_NUMERIC was completely un-settable, and LC_CTYPE - stored a flag intended to be used for a possible future byte-based C - locale, instead of storing a __locale_map pointer like the other - categories use. - - this patch changes all categories to be represented by pointers to - __locale_map structures, and allows locale names without definition - files to be treated as valid locales with trivial definition when used - in any category. outwardly visible functional changes should be minor, - limited mainly to the strings read back from setlocale and the way - gettext handles translations in categories other than LC_MESSAGES. - - various internal refactoring has also been performed, and improvements - in const correctness have been made. - -commit 63c188ec42e76ff768e81f6b65b11c68fc43351e -Author: Rich Felker <dalias@aerifal.cx> -Date: Wed May 27 00:22:43 2015 -0400 - - replace atomics with locks in locale-setting code - - this is part of a general program of removing direct use of atomics - where they are not necessary to meet correctness or performance needs, - but in this case it's also an optimization. only the global locale - needs synchronization; allocated locales referenced with locale_t - handles are immutable during their lifetimes, and using atomics to - initialize them increases their cost of setup. - -commit dc031ee0b1ba11baa00cd7f0769e461a5f396c71 -Author: Rich Felker <dalias@aerifal.cx> -Date: Tue May 26 03:37:41 2015 -0400 - - add rcrt1 start file for fully static-linked PIE - - static-linked PIE files need startup code to relocate themselves, much - like the dynamic linker does. rcrt1.c reuses the code in dlstart.c, - stage 1 of the dynamic linker, which in turn reuses crt_arch.h, to - achieve static PIE with no new code. only relative relocations are - supported. - - existing toolchains that don't yet support static PIE directly can be - repurposed by passing "-shared -Wl,-Bstatic -Wl,-Bsymbolic" instead of - "-static -pie" and substituting rcrt1.o in place of crt1.o. - - all libraries being linked must be built as PIC/PIE; TEXTRELs are not - supported at this time. - -commit ed0c8249825161036356a3616e8c5247c15d0927 -Author: Rich Felker <dalias@aerifal.cx> -Date: Tue May 26 02:31:04 2015 -0400 - - fix incorrect application of visibility to Scrt1.o - - commit de2b67f8d41e08caa56bf6540277f6561edb647f attempted to avoid - having vis.h affect crt files, but the Makefile variable used, - CRT_LIBS, refers to the final output copies in the lib directory, not - the copies in the crt build directory, and thus the -DCRT was not - applied. - - while unlikely to be noticed, this regression probably broke - production of PIE executables whose main functions are not in the - executable but rather a shared library. - -commit 9bbddf730f7837cf87f4c789fbb41a312e295d6c -Author: Rich Felker <dalias@aerifal.cx> -Date: Mon May 25 23:33:59 2015 -0400 - - reprocess all libc/ldso symbolic relocations in dynamic linking stage 3 - - commit f3ddd173806fd5c60b3f034528ca24542aecc5b9 introduced early - relocations and subsequent reprocessing as part of the dynamic linker - bootstrap overhaul, to allow use of arbitrary libc functions before - the main application and libraries are loaded, but only reprocessed - GOT/PLT relocation types. - - commit c093e2e8201524db0d638920e76bcb6b1d925f3a added reprocessing of - non-GOT/PLT relocations to fix an actual regression that was observed - on powerpc, but only for RELA format tables with out-of-line addends. - REL table (inline addends at the relocation address) reprocessing is - trickier because the first relocation pass clobbers the addends. - - this patch extends symbolic relocation reprocessing for libc/ldso to - support all relocation types, whether REL or RELA format tables are - used. it is believed not to alter behavior on any existing archs for - the current dynamic linker and libc code. the motivations for this - change are consistency and future-proofing. it ensures that behavior - does not differ depending on whether REL or RELA tables are used, - which could lead to undetected arch-specific bugs. it also ensures - that, if in the future code depending on additional relocation types - is added to libc.so, either at the source level or as part of the - compiler runtime that gets pulled in (for example, soft-float with TLS - for fenv), the new code will work properly. - - the implementation concept is simple: stage 2 of the dynamic linker - counts the number of symbolic relocations in the libc/ldso REL table - and allocates a VLA to save their addends into; stage 3 then uses the - saved addends in place of the inline ones which were clobbered. for - stack safety, a hard limit (currently 4k) is imposed on the number of - such addends; this should be a couple orders of magnitude larger than - the actual need. this number is not a runtime variable that could - break fail-safety; it is constant for a given libc.so build. - -commit 768b82c6de24e480267c4c251c440edfc71800e3 -Author: Rich Felker <dalias@aerifal.cx> -Date: Mon May 25 19:15:17 2015 -0400 - - move call to dynamic linker stage-3 into stage-2 function - - this move eliminates a duplicate "by-hand" symbol lookup loop from the - stage-1 code and replaces it with a call to find_sym, which can be - used once we're in stage 2. it reduces the size of the stage 1 code, - which is helpful because stage 1 will become the crt start file for - static-PIE executables, and it will allow stage 3 to access stage 2's - automatic storage, which will be important in an upcoming commit. - -commit 967bcbf67c3ffac587de4d79abc1e5e072d83e3e -Author: Rich Felker <dalias@aerifal.cx> -Date: Mon May 25 16:02:49 2015 -0400 - - mark mips crt code as code - - otherwise disassemblers treat it as data. - -commit 7b75c4877ddf22f219f944c61d939df1dee4f6d3 -Author: Rich Felker <dalias@aerifal.cx> -Date: Mon May 25 15:56:36 2015 -0400 - - mark mips cancellable syscall code as code - - otherwise disassemblers treat it as data. - -commit 0e0e49421f08cfd670975ecd3604f7f9015e1833 -Author: Rich Felker <dalias@aerifal.cx> -Date: Mon May 25 00:32:37 2015 -0400 - - simplify/shrink relocation processing in dynamic linker stage 1 - - the outer-loop approach made sense when we were also processing - DT_JMPREL, which might be in REL or RELA form, to avoid major code - duplication. commit 09db855b35709aa627d7055c57a98e1e471920ab removed - processing of DT_JMPREL, and in the remaining two tables, the format - (REL or RELA) is known by the name of the table. simply writing two - versions of the loop results in smaller and simpler code. - -commit 09db855b35709aa627d7055c57a98e1e471920ab -Author: Rich Felker <dalias@aerifal.cx> -Date: Mon May 25 00:25:56 2015 -0400 - - remove processing of DT_JMPREL from dynamic linker stage 1 bootstrap - - the DT_JMPREL relocation table necessarily consists entirely of - JMP_SLOT (REL_PLT in internal nomenclature) relocations, which are - symbolic; they cannot be resolved in stage 1, so there is no point in - processing them. - -commit 9f26ebded188ed78c3571a4ca1477dd6351bc647 -Author: Rich Felker <dalias@aerifal.cx> -Date: Sun May 24 23:03:47 2015 -0400 - - fix stack alignment code in mips crt_arch.h - - the instruction used to align the stack, "and $sp, $sp, -8", does not - actually exist; it's expanded to 2 instructions using the 'at' - (assembler temporary) register, and thus cannot be used in a branch - delay slot. since alignment mod 16 commutes with subtracting 8, simply - swapping these two operations fixes the problem. - - crt1.o was not affected because it's still being generated from a - dedicated asm source file. dlstart.lo was not affected because the - stack pointer it receives is already aligned by the kernel. but - Scrt1.o was affected in cases where the dynamic linker gave it a - misaligned stack pointer. - -commit 63caf1d207d143fe405bbe0cda9aac8deca1171a -Author: Rich Felker <dalias@aerifal.cx> -Date: Fri May 22 01:50:05 2015 -0400 - - add .text section directive to all crt_arch.h files missing it - - i386 and x86_64 versions already had the .text directive; other archs - did not. normally, top-level (file scope) __asm__ starts in the .text - section anyway, but problems were reported with some versions of - clang, and it seems preferable to set it explicitly anyway, at least - for the sake of consistency between archs. - -commit 3b0e83264d156f9e496ab32badd89e4447b807aa -Author: Rich Felker <dalias@aerifal.cx> -Date: Thu May 21 17:06:28 2015 -0400 - - remove outdated and misleading comment in iconv.c - - the comment claimed that EUC/GBK/Big5 are not implemented, which has - been incorrect since commit 19b4a0a20efc6b9df98b6a43536ecdd628ba4643. - -commit 39b8ce66f2ed9c17427ec3a48be9bda29b93b9d7 -Author: Rich Felker <dalias@aerifal.cx> -Date: Thu May 21 17:01:23 2015 -0400 - - in iconv_open, accept "CHAR" and "" as aliases for "UTF-8" - - while not a requirement, it's common convention in other iconv - implementations to accept "CHAR" as an alias for nl_langinfo(CODESET), - meaning the encoding used for char[] strings in the current locale, - and also "" as an alternate form. supporting this is not costly and - improves compatibility. - -commit c648cefb27984db60474ec1747cbfde83c2856d0 -Author: Rich Felker <dalias@aerifal.cx> -Date: Wed May 20 00:17:35 2015 -0400 - - fix inconsistency in a_and and a_or argument types on x86[_64] - - conceptually, and on other archs, these functions take a pointer to - int, but in the i386, x86_64, and x32 versions of atomic.h, they took - a pointer to void instead. - -commit 390f93ef69153bf2087fcf3baa1776ad9a6765ab -Author: Bobby Bingham <koorogi@koorogi.info> -Date: Sun May 17 13:46:38 2015 -0500 - - inline llsc atomics when building for sh4a - - If we're building for sh4a, the compiler is already free to use - instructions only available on sh4a, so we can do the same and inline the - llsc atomics. If we're building for an older processor, we still do the - same runtime atomics selection as before. - -commit c093e2e8201524db0d638920e76bcb6b1d925f3a -Author: Rich Felker <dalias@aerifal.cx> -Date: Mon May 18 16:51:54 2015 -0400 - - reprocess libc/ldso RELA relocations in stage 3 of dynamic linking - - this fixes a regression on powerpc that was introduced in commit - f3ddd173806fd5c60b3f034528ca24542aecc5b9. global data accesses on - powerpc seem to be using a translation-unit-local GOT filled via - R_PPC_ADDR32 relocations rather than R_PPC_GLOB_DAT. being a non-GOT - relocation type, these were not reprocessed after adding the main - application and its libraries to the chain, causing libc code not to - see copy relocations in the main program, and therefore to use the - pre-copy-relocation addresses for global data objects (like environ). - - the motivation for the dynamic linker only reprocessing GOT/PLT - relocation types in stage 3 is that these types always have a zero - addend, making them safe to process again even if the storage for the - addend has been clobbered. other relocation types which can be used - for address constants in initialized data objects may have non-zero - addends which will be clobbered during the first pass of relocation - processing if they're stored inline (REL form) rather than out-of-line - (RELA form). - - powerpc generally uses only RELA, so this patch is sufficient to fix - the regression in practice, but is not fully general, and would not - suffice if an alternate toolchain generated REL for powerpc. - -commit 43e9f652bf4b2195b04fc14c93db591b30a7b790 -Author: Rich Felker <dalias@aerifal.cx> -Date: Mon May 18 12:11:25 2015 -0400 - - fix null pointer dereference in dcngettext under specific conditions - - if setlocale has not been called, the current locale's messages_name - may be a null pointer. the code path where it's assumed to be non-null - was only reachable if bindtextdomain had already been called, which is - normally not done in programs which do not call setlocale, so the - omitted check went unnoticed. - - patch from Void Linux, with description rewritten. - -commit 68630b55c0c7219fe9df70dc28ffbf9efc8021d8 -Author: Rich Felker <dalias@aerifal.cx> -Date: Sat May 16 01:53:54 2015 -0400 - - eliminate costly tricks to avoid TLS access for current locale state - - the code being removed used atomics to track whether any threads might - be using a locale other than the current global locale, and whether - any threads might have abstract 8-bit (non-UTF-8) LC_CTYPE active, a - feature which was never committed (still pending). the motivations - were to support early execution prior to setup of the thread pointer, - to partially support systems (ancient kernels) where thread pointer - setup is not possible, and to avoid high performance cost on archs - where accessing the thread pointer may be very slow. - - since commit 19a1fe670acb3ab9ead0fe31859ca7d4fe40dd54, the thread - pointer is always available, so these hacks are no longer needed. - removing them greatly simplifies the affected code. - -commit 707d7c30f3379441de9b320536ddfd354f4c2143 -Author: Rich Felker <dalias@aerifal.cx> -Date: Sat May 16 01:15:40 2015 -0400 - - in i386 __set_thread_area, don't assume %gs register is initially zero - - commit f630df09b1fd954eda16e2f779da0b5ecc9d80d3 added logic to handle - the case where __set_thread_area is called more than once by reusing - the GDT slot already in the %gs register, and only setting up a new - GDT slot when %gs is zero. this created a hidden assumption that %gs - is zero when a new process image starts, which is true in practice on - Linux, but does not seem to be documented ABI, and fails to hold under - qemu app-level emulation. - - while it would in theory be possible to zero %gs in the entry point - code, this code is shared between static and dynamic binaries, and - dynamic binaries must not clobber the value of %gs already setup by - the dynamic linker. - - the alternative solution implemented in this commit simply uses global - data to store the GDT index that's selected. __set_thread_area should - only be called in the initial thread anyway (subsequent threads get - their thread pointer setup by __clone), but even if it were called by - another thread, it would simply read and write back the same GDT index - that was already assigned to the initial thread, and thus (in the x86 - memory model) there is no data race. - -commit c0f10cf06725bd0de37f3ced7954a653bf9f1049 -Author: Rich Felker <dalias@aerifal.cx> -Date: Thu May 14 18:51:27 2015 -0400 - - make arm reloc.h CRTJMP macro compatible with thumb - - compilers targeting armv7 may be configured to produce thumb2 code - instead of arm code by default, and in the future we may wish to - support targets where only the thumb instruction set is available. - - the instructions this patch omits in thumb mode are needed only for - non-thumb versions of armv4 or earlier, which are not supported by any - current compilers/toolchains and thus rather pointless to have. at - some point these compatibility return sequences may be removed from - all asm source files, and in that case it would make sense to remove - them here too and remove the ifdef. - -commit 83340c7a580e91b22f58321b7cf6d976af61084c -Author: Rich Felker <dalias@aerifal.cx> -Date: Thu May 14 18:26:16 2015 -0400 - - make arm crt_arch.h compatible with thumb code generation - - compilers targeting armv7 may be configured to produce thumb2 code - instead of arm code by default, and in the future we may wish to - support targets where only the thumb instruction set is available. - - the changes made here avoid operating directly on the sp register, - which is not possible in thumb code, and address an issue with the way - the address of _DYNAMIC is computed. - - previously, the relative address of _DYNAMIC was stored with an - additional offset of -8 versus the pc-relative add instruction, since - on arm the pc register evaluates to ".+8". in thumb code, it instead - evaluates to ".+4". both are two (normal-size) instructions beyond "." - in the current execution mode, so the numbered label 2 used in the - relative address expression is simply moved two instructions ahead to - be compatible with both instruction sets. - ---- a/Makefile -+++ b/Makefile -@@ -44,7 +44,7 @@ ALL_INCLUDES = $(sort $(wildcard include - - EMPTY_LIB_NAMES = m rt pthread crypt util xnet resolv dl - EMPTY_LIBS = $(EMPTY_LIB_NAMES:%=lib/lib%.a) --CRT_LIBS = lib/crt1.o lib/Scrt1.o lib/crti.o lib/crtn.o -+CRT_LIBS = lib/crt1.o lib/Scrt1.o lib/rcrt1.o lib/crti.o lib/crtn.o - STATIC_LIBS = lib/libc.a - SHARED_LIBS = lib/libc.so - TOOL_LIBS = lib/musl-gcc.specs -@@ -85,11 +85,13 @@ src/internal/version.h: $(wildcard VERSI - - src/internal/version.lo: src/internal/version.h - --src/ldso/dlstart.lo src/ldso/dynlink.lo: src/internal/dynlink.h arch/$(ARCH)/reloc.h -+crt/rcrt1.o src/ldso/dlstart.lo src/ldso/dynlink.lo: src/internal/dynlink.h arch/$(ARCH)/reloc.h - --crt/crt1.o crt/Scrt1.o src/ldso/dlstart.lo: $(wildcard arch/$(ARCH)/crt_arch.h) -+crt/crt1.o crt/Scrt1.o crt/rcrt1.o src/ldso/dlstart.lo: $(wildcard arch/$(ARCH)/crt_arch.h) - --crt/Scrt1.o: CFLAGS += -fPIC -+crt/rcrt1.o: src/ldso/dlstart.c -+ -+crt/Scrt1.o crt/rcrt1.o: CFLAGS += -fPIC - - OPTIMIZE_SRCS = $(wildcard $(OPTIMIZE_GLOBS:%=src/%)) - $(OPTIMIZE_SRCS:%.c=%.o) $(OPTIMIZE_SRCS:%.c=%.lo): CFLAGS += -O3 -@@ -104,7 +106,7 @@ NOSSP_SRCS = $(wildcard crt/*.c) \ - src/ldso/dlstart.c src/ldso/dynlink.c - $(NOSSP_SRCS:%.c=%.o) $(NOSSP_SRCS:%.c=%.lo): CFLAGS += $(CFLAGS_NOSSP) - --$(CRT_LIBS): CFLAGS += -DCRT -+$(CRT_LIBS:lib/%=crt/%): CFLAGS += -DCRT - - # This incantation ensures that changes to any subarch asm files will - # force the corresponding object file to be rebuilt, even if the implicit ---- a/arch/aarch64/crt_arch.h -+++ b/arch/aarch64/crt_arch.h -@@ -1,4 +1,5 @@ - __asm__( -+".text \n" - ".global " START "\n" - ".type " START ",%function\n" - START ":\n" ---- a/arch/arm/crt_arch.h -+++ b/arch/arm/crt_arch.h -@@ -1,15 +1,18 @@ - __asm__( -+".text \n" - ".global " START " \n" - ".type " START ",%function \n" - START ": \n" - " mov fp, #0 \n" - " mov lr, #0 \n" --" mov a1, sp \n" - " ldr a2, 1f \n" --"2: add a2, pc, a2 \n" --" and sp, sp, #-16 \n" -+" add a2, pc, a2 \n" -+" mov a1, sp \n" -+"2: and ip, a1, #-16 \n" -+" mov sp, ip \n" - " bl " START "_c \n" - ".weak _DYNAMIC \n" - ".hidden _DYNAMIC \n" --"1: .word _DYNAMIC-2b-8 \n" -+".align 2 \n" -+"1: .word _DYNAMIC-2b \n" - ); ---- a/arch/arm/reloc.h -+++ b/arch/arm/reloc.h -@@ -28,5 +28,10 @@ - #define REL_TPOFF R_ARM_TLS_TPOFF32 - //#define REL_TLSDESC R_ARM_TLS_DESC - -+#ifdef __thumb__ -+#define CRTJMP(pc,sp) __asm__ __volatile__( \ -+ "mov sp,%1 ; bx %0" : : "r"(pc), "r"(sp) : "memory" ) -+#else - #define CRTJMP(pc,sp) __asm__ __volatile__( \ - "mov sp,%1 ; tst %0,#1 ; moveq pc,%0 ; bx %0" : : "r"(pc), "r"(sp) : "memory" ) -+#endif ---- a/arch/i386/atomic.h -+++ b/arch/i386/atomic.h -@@ -50,16 +50,16 @@ static inline int a_cas(volatile int *p, - return t; - } - --static inline void a_or(volatile void *p, int v) -+static inline void a_or(volatile int *p, int v) - { - __asm__( "lock ; orl %1, %0" -- : "=m"(*(int *)p) : "r"(v) : "memory" ); -+ : "=m"(*p) : "r"(v) : "memory" ); - } - --static inline void a_and(volatile void *p, int v) -+static inline void a_and(volatile int *p, int v) - { - __asm__( "lock ; andl %1, %0" -- : "=m"(*(int *)p) : "r"(v) : "memory" ); -+ : "=m"(*p) : "r"(v) : "memory" ); - } - - static inline int a_swap(volatile int *x, int v) ---- a/arch/microblaze/crt_arch.h -+++ b/arch/microblaze/crt_arch.h -@@ -1,4 +1,5 @@ - __asm__( -+".text \n" - ".global " START " \n" - ".align 2 \n" - START ": \n" ---- a/arch/mips/crt_arch.h -+++ b/arch/mips/crt_arch.h -@@ -1,6 +1,7 @@ - __asm__( - ".set push\n" - ".set noreorder\n" -+".text \n" - ".global _" START "\n" - ".global " START "\n" - ".type _" START ", @function\n" -@@ -21,8 +22,8 @@ __asm__( - " addu $5, $5, $gp \n" - " lw $25, 4($ra) \n" - " addu $25, $25, $gp \n" --" subu $sp, $sp, 16 \n" -+" and $sp, $sp, -8 \n" - " jalr $25 \n" --" and $sp, $sp, -8 \n" -+" subu $sp, $sp, 16 \n" - ".set pop \n" - ); ---- a/arch/or1k/crt_arch.h -+++ b/arch/or1k/crt_arch.h -@@ -1,4 +1,5 @@ - __asm__( -+".text \n" - ".global " START " \n" - ".align 4 \n" - START ": \n" ---- a/arch/powerpc/crt_arch.h -+++ b/arch/powerpc/crt_arch.h -@@ -1,4 +1,5 @@ - __asm__( -+".text \n" - ".global " START " \n" - ".type " START ", %function \n" - START ": \n" ---- a/arch/sh/atomic.h -+++ b/arch/sh/atomic.h -@@ -22,6 +22,88 @@ static inline int a_ctz_64(uint64_t x) - return a_ctz_l(y); - } - -+#define LLSC_CLOBBERS "r0", "t", "memory" -+#define LLSC_START(mem) "synco\n" \ -+ "0: movli.l @" mem ", r0\n" -+#define LLSC_END(mem) \ -+ "1: movco.l r0, @" mem "\n" \ -+ " bf 0b\n" \ -+ " synco\n" -+ -+static inline int __sh_cas_llsc(volatile int *p, int t, int s) -+{ -+ int old; -+ __asm__ __volatile__( -+ LLSC_START("%1") -+ " mov r0, %0\n" -+ " cmp/eq %0, %2\n" -+ " bf 1f\n" -+ " mov %3, r0\n" -+ LLSC_END("%1") -+ : "=&r"(old) : "r"(p), "r"(t), "r"(s) : LLSC_CLOBBERS); -+ return old; -+} -+ -+static inline int __sh_swap_llsc(volatile int *x, int v) -+{ -+ int old; -+ __asm__ __volatile__( -+ LLSC_START("%1") -+ " mov r0, %0\n" -+ " mov %2, r0\n" -+ LLSC_END("%1") -+ : "=&r"(old) : "r"(x), "r"(v) : LLSC_CLOBBERS); -+ return old; -+} -+ -+static inline int __sh_fetch_add_llsc(volatile int *x, int v) -+{ -+ int old; -+ __asm__ __volatile__( -+ LLSC_START("%1") -+ " mov r0, %0\n" -+ " add %2, r0\n" -+ LLSC_END("%1") -+ : "=&r"(old) : "r"(x), "r"(v) : LLSC_CLOBBERS); -+ return old; -+} -+ -+static inline void __sh_store_llsc(volatile int *p, int x) -+{ -+ __asm__ __volatile__( -+ " synco\n" -+ " mov.l %1, @%0\n" -+ " synco\n" -+ : : "r"(p), "r"(x) : "memory"); -+} -+ -+static inline void __sh_and_llsc(volatile int *x, int v) -+{ -+ __asm__ __volatile__( -+ LLSC_START("%0") -+ " and %1, r0\n" -+ LLSC_END("%0") -+ : : "r"(x), "r"(v) : LLSC_CLOBBERS); -+} -+ -+static inline void __sh_or_llsc(volatile int *x, int v) -+{ -+ __asm__ __volatile__( -+ LLSC_START("%0") -+ " or %1, r0\n" -+ LLSC_END("%0") -+ : : "r"(x), "r"(v) : LLSC_CLOBBERS); -+} -+ -+#ifdef __SH4A__ -+#define a_cas(p,t,s) __sh_cas_llsc(p,t,s) -+#define a_swap(x,v) __sh_swap_llsc(x,v) -+#define a_fetch_add(x,v) __sh_fetch_add_llsc(x, v) -+#define a_store(x,v) __sh_store_llsc(x, v) -+#define a_and(x,v) __sh_and_llsc(x, v) -+#define a_or(x,v) __sh_or_llsc(x, v) -+#else -+ - int __sh_cas(volatile int *, int, int); - int __sh_swap(volatile int *, int); - int __sh_fetch_add(volatile int *, int); -@@ -35,6 +117,7 @@ void __sh_or(volatile int *, int); - #define a_store(x,v) __sh_store(x, v) - #define a_and(x,v) __sh_and(x, v) - #define a_or(x,v) __sh_or(x, v) -+#endif - - static inline void *a_cas_p(volatile void *p, void *t, void *s) - { ---- a/arch/sh/crt_arch.h -+++ b/arch/sh/crt_arch.h -@@ -1,4 +1,5 @@ - __asm__( -+".text \n" - ".global " START " \n" - START ": \n" - " mova 1f, r0 \n" ---- a/arch/sh/src/atomic.c -+++ b/arch/sh/src/atomic.c -@@ -1,12 +1,7 @@ --#include "libc.h" -+#ifndef __SH4A__ - --#define LLSC_CLOBBERS "r0", "t", "memory" --#define LLSC_START(mem) "synco\n" \ -- "0: movli.l @" mem ", r0\n" --#define LLSC_END(mem) \ -- "1: movco.l r0, @" mem "\n" \ -- " bf 0b\n" \ -- " synco\n" -+#include "atomic.h" -+#include "libc.h" - - /* 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 -@@ -34,114 +29,74 @@ - - int __sh_cas(volatile int *p, int t, int s) - { -+ if (__hwcap & CPU_HAS_LLSC) return __sh_cas_llsc(p, t, s); -+ - int old; -- if (__hwcap & CPU_HAS_LLSC) { -- __asm__ __volatile__( -- LLSC_START("%1") -- " mov r0, %0\n" -- " cmp/eq %0, %2\n" -- " bf 1f\n" -- " mov %3, r0\n" -- LLSC_END("%1") -- : "=&r"(old) : "r"(p), "r"(t), "r"(s) : LLSC_CLOBBERS); -- } else { -- __asm__ __volatile__( -- GUSA_START_EVEN("%1", "%0") -- " cmp/eq %0, %2\n" -- " bf 1f\n" -- GUSA_END("%1", "%3") -- : "=&r"(old) : "r"(p), "r"(t), "r"(s) : GUSA_CLOBBERS, "t"); -- } -+ __asm__ __volatile__( -+ GUSA_START_EVEN("%1", "%0") -+ " cmp/eq %0, %2\n" -+ " bf 1f\n" -+ GUSA_END("%1", "%3") -+ : "=&r"(old) : "r"(p), "r"(t), "r"(s) : GUSA_CLOBBERS, "t"); - return old; - } - - int __sh_swap(volatile int *x, int v) - { -+ if (__hwcap & CPU_HAS_LLSC) return __sh_swap_llsc(x, v); -+ - int old; -- if (__hwcap & CPU_HAS_LLSC) { -- __asm__ __volatile__( -- LLSC_START("%1") -- " mov r0, %0\n" -- " mov %2, r0\n" -- LLSC_END("%1") -- : "=&r"(old) : "r"(x), "r"(v) : LLSC_CLOBBERS); -- } else { -- __asm__ __volatile__( -- GUSA_START_EVEN("%1", "%0") -- GUSA_END("%1", "%2") -- : "=&r"(old) : "r"(x), "r"(v) : GUSA_CLOBBERS); -- } -+ __asm__ __volatile__( -+ GUSA_START_EVEN("%1", "%0") -+ GUSA_END("%1", "%2") -+ : "=&r"(old) : "r"(x), "r"(v) : GUSA_CLOBBERS); - return old; - } - - int __sh_fetch_add(volatile int *x, int v) - { -+ if (__hwcap & CPU_HAS_LLSC) return __sh_fetch_add_llsc(x, v); -+ - int old, dummy; -- if (__hwcap & CPU_HAS_LLSC) { -- __asm__ __volatile__( -- LLSC_START("%1") -- " mov r0, %0\n" -- " add %2, r0\n" -- LLSC_END("%1") -- : "=&r"(old) : "r"(x), "r"(v) : LLSC_CLOBBERS); -- } else { -- __asm__ __volatile__( -- GUSA_START_EVEN("%2", "%0") -- " mov %0, %1\n" -- " add %3, %1\n" -- GUSA_END("%2", "%1") -- : "=&r"(old), "=&r"(dummy) : "r"(x), "r"(v) : GUSA_CLOBBERS); -- } -+ __asm__ __volatile__( -+ GUSA_START_EVEN("%2", "%0") -+ " mov %0, %1\n" -+ " add %3, %1\n" -+ GUSA_END("%2", "%1") -+ : "=&r"(old), "=&r"(dummy) : "r"(x), "r"(v) : GUSA_CLOBBERS); - return old; - } - - void __sh_store(volatile int *p, int x) - { -- if (__hwcap & CPU_HAS_LLSC) { -- __asm__ __volatile__( -- " synco\n" -- " mov.l %1, @%0\n" -- " synco\n" -- : : "r"(p), "r"(x) : "memory"); -- } else { -- __asm__ __volatile__( -- " mov.l %1, @%0\n" -- : : "r"(p), "r"(x) : "memory"); -- } -+ if (__hwcap & CPU_HAS_LLSC) return __sh_store_llsc(p, x); -+ __asm__ __volatile__( -+ " mov.l %1, @%0\n" -+ : : "r"(p), "r"(x) : "memory"); - } - - void __sh_and(volatile int *x, int v) - { -+ if (__hwcap & CPU_HAS_LLSC) return __sh_and_llsc(x, v); -+ - int dummy; -- if (__hwcap & CPU_HAS_LLSC) { -- __asm__ __volatile__( -- LLSC_START("%0") -- " and %1, r0\n" -- LLSC_END("%0") -- : : "r"(x), "r"(v) : LLSC_CLOBBERS); -- } else { -- __asm__ __volatile__( -- GUSA_START_ODD("%1", "%0") -- " and %2, %0\n" -- GUSA_END("%1", "%0") -- : "=&r"(dummy) : "r"(x), "r"(v) : GUSA_CLOBBERS); -- } -+ __asm__ __volatile__( -+ GUSA_START_ODD("%1", "%0") -+ " and %2, %0\n" -+ GUSA_END("%1", "%0") -+ : "=&r"(dummy) : "r"(x), "r"(v) : GUSA_CLOBBERS); - } - - void __sh_or(volatile int *x, int v) - { -+ if (__hwcap & CPU_HAS_LLSC) return __sh_or_llsc(x, v); -+ - int dummy; -- if (__hwcap & CPU_HAS_LLSC) { -- __asm__ __volatile__( -- LLSC_START("%0") -- " or %1, r0\n" -- LLSC_END("%0") -- : : "r"(x), "r"(v) : LLSC_CLOBBERS); -- } else { -- __asm__ __volatile__( -- GUSA_START_ODD("%1", "%0") -- " or %2, %0\n" -- GUSA_END("%1", "%0") -- : "=&r"(dummy) : "r"(x), "r"(v) : GUSA_CLOBBERS); -- } -+ __asm__ __volatile__( -+ GUSA_START_ODD("%1", "%0") -+ " or %2, %0\n" -+ GUSA_END("%1", "%0") -+ : "=&r"(dummy) : "r"(x), "r"(v) : GUSA_CLOBBERS); - } -+ -+#endif ---- a/arch/x32/atomic.h -+++ b/arch/x32/atomic.h -@@ -47,16 +47,16 @@ static inline int a_cas(volatile int *p, - return t; - } - --static inline void a_or(volatile void *p, int v) -+static inline void a_or(volatile int *p, int v) - { - __asm__( "lock ; or %1, %0" -- : "=m"(*(int *)p) : "r"(v) : "memory" ); -+ : "=m"(*p) : "r"(v) : "memory" ); - } - --static inline void a_and(volatile void *p, int v) -+static inline void a_and(volatile int *p, int v) - { - __asm__( "lock ; and %1, %0" -- : "=m"(*(int *)p) : "r"(v) : "memory" ); -+ : "=m"(*p) : "r"(v) : "memory" ); - } - - static inline int a_swap(volatile int *x, int v) ---- a/arch/x86_64/atomic.h -+++ b/arch/x86_64/atomic.h -@@ -47,16 +47,16 @@ static inline int a_cas(volatile int *p, - return t; - } - --static inline void a_or(volatile void *p, int v) -+static inline void a_or(volatile int *p, int v) - { - __asm__( "lock ; or %1, %0" -- : "=m"(*(int *)p) : "r"(v) : "memory" ); -+ : "=m"(*p) : "r"(v) : "memory" ); - } - --static inline void a_and(volatile void *p, int v) -+static inline void a_and(volatile int *p, int v) - { - __asm__( "lock ; and %1, %0" -- : "=m"(*(int *)p) : "r"(v) : "memory" ); -+ : "=m"(*p) : "r"(v) : "memory" ); - } - - static inline int a_swap(volatile int *x, int v) ---- a/configure -+++ b/configure -@@ -80,7 +80,7 @@ fi - tryflag () { - printf "checking whether compiler accepts %s... " "$2" - echo "typedef int x;" > "$tmpc" --if $CC $2 -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then -+if $CC $CFLAGS_TRY $2 -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then - printf "yes\n" - eval "$1=\"\${$1} \$2\"" - eval "$1=\${$1# }" -@@ -94,7 +94,7 @@ fi - tryldflag () { - printf "checking whether linker accepts %s... " "$2" - echo "typedef int x;" > "$tmpc" --if $CC -nostdlib -shared "$2" -o /dev/null "$tmpc" >/dev/null 2>&1 ; then -+if $CC $LDFLAGS_TRY -nostdlib -shared "$2" -o /dev/null "$tmpc" >/dev/null 2>&1 ; then - printf "yes\n" - eval "$1=\"\${$1} \$2\"" - eval "$1=\${$1# }" -@@ -113,7 +113,9 @@ CFLAGS_C99FSE= - CFLAGS_AUTO= - CFLAGS_MEMOPS= - CFLAGS_NOSSP= -+CFLAGS_TRY= - LDFLAGS_AUTO= -+LDFLAGS_TRY= - OPTIMIZE_GLOBS= - prefix=/usr/local/musl - exec_prefix='$(prefix)' -@@ -205,6 +207,14 @@ exit 1 - fi - - # -+# Figure out options to force errors on unknown flags. -+# -+tryflag CFLAGS_TRY -Werror=unknown-warning-option -+tryflag CFLAGS_TRY -Werror=unused-command-line-argument -+tryldflag LDFLAGS_TRY -Werror=unknown-warning-option -+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. - # ---- a/crt/mips/crt1.s -+++ b/crt/mips/crt1.s -@@ -4,6 +4,8 @@ - .weak _fini - .global __start - .global _start -+.type __start,@function -+.type _start,@function - __start: - _start: - subu $fp, $fp, $fp # Zero the frame pointer. ---- a/crt/mips/crti.s -+++ b/crt/mips/crti.s -@@ -2,6 +2,7 @@ - - .section .init - .global _init -+.type _init,@function - .align 2 - _init: - subu $sp,$sp,32 -@@ -10,6 +11,7 @@ _init: - - .section .fini - .global _fini -+.type _fini,@function - .align 2 - _fini: - subu $sp,$sp,32 ---- /dev/null -+++ b/crt/rcrt1.c -@@ -0,0 +1,15 @@ -+#define SHARED -+#define START "_start" -+#define _dlstart_c _start_c -+#include "../src/ldso/dlstart.c" -+ -+int main(); -+void _init() __attribute__((weak)); -+void _fini() __attribute__((weak)); -+_Noreturn int __libc_start_main(int (*)(), int, char **, -+ void (*)(), void(*)(), void(*)()); -+ -+_Noreturn void __dls2(unsigned char *base, size_t *sp) -+{ -+ __libc_start_main(main, *sp, (void *)(sp+1), _init, _fini, 0); -+} ---- a/include/sys/resource.h -+++ b/include/sys/resource.h -@@ -96,6 +96,9 @@ int prlimit(pid_t, int, const struct rli - #define RLIM_NLIMITS RLIMIT_NLIMITS - - #if defined(_LARGEFILE64_SOURCE) || defined(_GNU_SOURCE) -+#define RLIM64_INFINITY RLIM_INFINITY -+#define RLIM64_SAVED_CUR RLIM_SAVED_CUR -+#define RLIM64_SAVED_MAX RLIM_SAVED_MAX - #define getrlimit64 getrlimit - #define setrlimit64 setrlimit - #define rlimit64 rlimit ---- a/src/internal/dynlink.h -+++ b/src/internal/dynlink.h -@@ -51,7 +51,7 @@ enum { - #define AUX_CNT 32 - #define DYN_CNT 32 - --typedef void (*stage2_func)(unsigned char *); -+typedef void (*stage2_func)(unsigned char *, size_t *); - typedef _Noreturn void (*stage3_func)(size_t *); - - #endif ---- a/src/internal/libc.h -+++ b/src/internal/libc.h -@@ -8,9 +8,7 @@ - struct __locale_map; - - struct __locale_struct { -- volatile int ctype_utf8; -- char *messages_name; -- struct __locale_map *volatile cat[4]; -+ const struct __locale_map *volatile cat[6]; - }; - - struct __libc { -@@ -23,8 +21,6 @@ struct __libc { - volatile int ofl_lock[2]; - size_t tls_size; - size_t page_size; -- volatile int uselocale_cnt; -- volatile int bytelocale_cnt_minus_1; - struct __locale_struct global_locale; - }; - ---- a/src/internal/locale_impl.h -+++ b/src/internal/locale_impl.h -@@ -9,22 +9,20 @@ struct __locale_map { - const void *map; - size_t map_size; - char name[LOCALE_NAME_MAX+1]; -- struct __locale_map *next; -+ const struct __locale_map *next; - }; - --int __setlocalecat(locale_t, int, const char *); -+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 *); - const char *__lctrans_cur(const char *); - --#define LCTRANS(msg, lc, loc) __lctrans(msg, (loc)->cat[(lc)-2]) -+#define LCTRANS(msg, lc, loc) __lctrans(msg, (loc)->cat[(lc)]) - #define LCTRANS_CUR(msg) __lctrans_cur(msg) - --#define CURRENT_LOCALE \ -- (libc.uselocale_cnt ? __pthread_self()->locale : &libc.global_locale) -+#define CURRENT_LOCALE (__pthread_self()->locale) - --#define CURRENT_UTF8 \ -- (libc.bytelocale_cnt_minus_1<0 || __pthread_self()->locale->ctype_utf8) -+#define CURRENT_UTF8 (!!__pthread_self()->locale->cat[LC_CTYPE]) - - #undef MB_CUR_MAX - #define MB_CUR_MAX (CURRENT_UTF8 ? 4 : 1) ---- a/src/ldso/dlstart.c -+++ b/src/ldso/dlstart.c -@@ -56,31 +56,22 @@ void _dlstart_c(size_t *sp, size_t *dynv - for (i=0; i<local_cnt; i++) got[i] += (size_t)base; - } - -- /* The use of the reloc_info structure and nested loops is a trick -- * to work around the fact that we can't necessarily make function -- * calls yet. Each struct in the array serves like the arguments -- * to a function call. */ -- struct { -- void *rel; -- size_t size; -- size_t stride; -- } reloc_info[] = { -- { base+dyn[DT_JMPREL], dyn[DT_PLTRELSZ], 2+(dyn[DT_PLTREL]==DT_RELA) }, -- { base+dyn[DT_REL], dyn[DT_RELSZ], 2 }, -- { base+dyn[DT_RELA], dyn[DT_RELASZ], 3 }, -- { 0, 0, 0 } -- }; -- -- for (i=0; reloc_info[i].stride; i++) { -- size_t *rel = reloc_info[i].rel; -- size_t rel_size = reloc_info[i].size; -- size_t stride = reloc_info[i].stride; -- for (; rel_size; rel+=stride, rel_size-=stride*sizeof(size_t)) { -- if (!IS_RELATIVE(rel[1])) continue; -- size_t *rel_addr = (void *)(base + rel[0]); -- size_t addend = stride==3 ? rel[2] : *rel_addr; -- *rel_addr = (size_t)base + addend; -- } -+ size_t *rel, rel_size; -+ -+ rel = (void *)(base+dyn[DT_REL]); -+ rel_size = dyn[DT_RELSZ]; -+ for (; rel_size; rel+=2, rel_size-=2*sizeof(size_t)) { -+ if (!IS_RELATIVE(rel[1])) continue; -+ size_t *rel_addr = (void *)(base + rel[0]); -+ *rel_addr += (size_t)base; -+ } -+ -+ rel = (void *)(base+dyn[DT_RELA]); -+ rel_size = dyn[DT_RELASZ]; -+ for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) { -+ if (!IS_RELATIVE(rel[1])) continue; -+ size_t *rel_addr = (void *)(base + rel[0]); -+ *rel_addr = (size_t)base + rel[2]; - } - - const char *strings = (void *)(base + dyn[DT_STRTAB]); -@@ -93,16 +84,7 @@ void _dlstart_c(size_t *sp, size_t *dynv - && s[3]=='l' && s[4]=='s' && s[5]=='2' && !s[6]) - break; - } -- ((stage2_func)(base + syms[i].st_value))(base); -- -- /* Call dynamic linker stage-3, __dls3 */ -- for (i=0; ;i++) { -- const char *s = strings + syms[i].st_name; -- if (s[0]=='_' && s[1]=='_' && s[2]=='d' -- && s[3]=='l' && s[4]=='s' && s[5]=='3' && !s[6]) -- break; -- } -- ((stage3_func)(base + syms[i].st_value))(sp); -+ ((stage2_func)(base + syms[i].st_value))(base, sp); - } - - #endif ---- a/src/ldso/dynlink.c -+++ b/src/ldso/dynlink.c -@@ -74,7 +74,6 @@ struct dso { - volatile int new_dtv_idx, new_tls_idx; - struct td_index *td_index; - struct dso *fini_next; -- int rel_early_relative, rel_update_got; - char *shortname; - char buf[]; - }; -@@ -96,6 +95,9 @@ static struct builtin_tls { - } builtin_tls[1]; - #define MIN_TLS_ALIGN offsetof(struct builtin_tls, pt) - -+#define ADDEND_LIMIT 4096 -+static size_t *saved_addends, *apply_addends_to; -+ - static struct dso ldso; - static struct dso *head, *tail, *fini_head; - static char *env_path, *sys_path; -@@ -256,10 +258,19 @@ static void do_relocs(struct dso *dso, s - size_t sym_val; - size_t tls_val; - size_t addend; -+ int skip_relative = 0, reuse_addends = 0, save_slot = 0; -+ -+ if (dso == &ldso) { -+ /* Only ldso's REL table needs addend saving/reuse. */ -+ if (rel == apply_addends_to) -+ reuse_addends = 1; -+ skip_relative = 1; -+ } - - for (; rel_size; rel+=stride, rel_size-=stride*sizeof(size_t)) { -- if (dso->rel_early_relative && IS_RELATIVE(rel[1])) continue; -+ if (skip_relative && IS_RELATIVE(rel[1])) continue; - type = R_TYPE(rel[1]); -+ if (type == REL_NONE) continue; - sym_index = R_SYM(rel[1]); - reloc_addr = (void *)(base + rel[0]); - if (sym_index) { -@@ -280,12 +291,20 @@ static void do_relocs(struct dso *dso, s - def.dso = dso; - } - -- int gotplt = (type == REL_GOT || type == REL_PLT); -- if (dso->rel_update_got && !gotplt) continue; -- -- addend = stride>2 ? rel[2] -- : gotplt || type==REL_COPY ? 0 -- : *reloc_addr; -+ if (stride > 2) { -+ addend = rel[2]; -+ } else if (type==REL_GOT || type==REL_PLT|| type==REL_COPY) { -+ addend = 0; -+ } else if (reuse_addends) { -+ /* Save original addend in stage 2 where the dso -+ * chain consists of just ldso; otherwise read back -+ * saved addend since the inline one was clobbered. */ -+ if (head==&ldso) -+ saved_addends[save_slot] = *reloc_addr; -+ addend = saved_addends[save_slot++]; -+ } else { -+ addend = *reloc_addr; -+ } - - sym_val = def.sym ? (size_t)def.dso->base+def.sym->st_value : 0; - tls_val = def.sym ? def.sym->st_value : 0; -@@ -879,7 +898,7 @@ static void do_mips_relocs(struct dso *p - size_t i, j, rel[2]; - unsigned char *base = p->base; - i=0; search_vec(p->dynv, &i, DT_MIPS_LOCAL_GOTNO); -- if (p->rel_early_relative) { -+ if (p==&ldso) { - got += i; - } else { - while (i--) *got++ += (size_t)base; -@@ -1116,7 +1135,7 @@ static void update_tls_size() - * linker itself, but some of the relocations performed may need to be - * replaced later due to copy relocations in the main program. */ - --void __dls2(unsigned char *base) -+void __dls2(unsigned char *base, size_t *sp) - { - Ehdr *ehdr = (void *)base; - ldso.base = base; -@@ -1125,15 +1144,35 @@ void __dls2(unsigned char *base) - ldso.phnum = ehdr->e_phnum; - ldso.phdr = (void *)(base + ehdr->e_phoff); - ldso.phentsize = ehdr->e_phentsize; -- ldso.rel_early_relative = 1; - kernel_mapped_dso(&ldso); - decode_dyn(&ldso); - -+ /* Prepare storage for to save clobbered REL addends so they -+ * can be reused in stage 3. There should be very few. If -+ * something goes wrong and there are a huge number, abort -+ * instead of risking stack overflow. */ -+ size_t dyn[DYN_CNT]; -+ decode_vec(ldso.dynv, dyn, DYN_CNT); -+ size_t *rel = (void *)(base+dyn[DT_REL]); -+ size_t rel_size = dyn[DT_RELSZ]; -+ size_t symbolic_rel_cnt = 0; -+ apply_addends_to = rel; -+ for (; rel_size; rel+=2, rel_size-=2*sizeof(size_t)) -+ if (!IS_RELATIVE(rel[1])) symbolic_rel_cnt++; -+ if (symbolic_rel_cnt >= ADDEND_LIMIT) a_crash(); -+ size_t addends[symbolic_rel_cnt+1]; -+ saved_addends = addends; -+ - head = &ldso; - reloc_all(&ldso); - - ldso.relocated = 0; -- ldso.rel_update_got = 1; -+ -+ /* Call dynamic linker stage-3, __dls3, looking it up -+ * symbolically as a barrier against moving the address -+ * load across the above relocation processing. */ -+ struct symdef dls3_def = find_sym(&ldso, "__dls3", 0); -+ ((stage3_func)(ldso.base+dls3_def.sym->st_value))(sp); - } - - /* Stage 3 of the dynamic linker is called with the dynamic linker/libc ---- a/src/locale/__lctrans.c -+++ b/src/locale/__lctrans.c -@@ -16,5 +16,5 @@ const char *__lctrans(const char *msg, c - - const char *__lctrans_cur(const char *msg) - { -- return __lctrans_impl(msg, CURRENT_LOCALE->cat[LC_MESSAGES-2]); -+ return __lctrans_impl(msg, CURRENT_LOCALE->cat[LC_MESSAGES]); - } ---- a/src/locale/__setlocalecat.c -+++ /dev/null -@@ -1,111 +0,0 @@ --#include <locale.h> --#include <string.h> --#include "locale_impl.h" --#include "libc.h" --#include "atomic.h" -- --const char *__lctrans_impl(const char *msg, const struct __locale_map *lm) --{ -- const char *trans = 0; -- if (lm) trans = __mo_lookup(lm->map, lm->map_size, msg); -- return trans ? trans : msg; --} -- --const unsigned char *__map_file(const char *, size_t *); --int __munmap(void *, size_t); --char *__strchrnul(const char *, int); -- --static struct __locale_map *findlocale(const char *name, size_t n) --{ -- static void *volatile loc_head; -- struct __locale_map *p, *new, *old_head; -- const char *path = 0, *z; -- char buf[256]; -- size_t l; -- const void *map; -- size_t map_size; -- -- for (p=loc_head; p; p=p->next) -- if (!strcmp(name, p->name)) return p; -- -- if (!libc.secure) path = getenv("MUSL_LOCPATH"); -- /* FIXME: add a default path? */ -- if (!path) return 0; -- -- for (; *path; path=z+!!*z) { -- z = __strchrnul(path, ':'); -- l = z - path - !!*z; -- if (l >= sizeof buf - n - 2) continue; -- memcpy(buf, path, l); -- buf[l] = '/'; -- memcpy(buf+l+1, name, n); -- buf[l+1+n] = 0; -- map = __map_file(buf, &map_size); -- if (map) { -- new = malloc(sizeof *new); -- if (!new) { -- __munmap((void *)map, map_size); -- return 0; -- } -- new->map = map; -- new->map_size = map_size; -- memcpy(new->name, name, n); -- new->name[n] = 0; -- do { -- old_head = loc_head; -- new->next = old_head; -- } while (a_cas_p(&loc_head, old_head, new) != old_head); -- return new; -- } -- } -- return 0; --} -- --static const char envvars[][12] = { -- "LC_CTYPE", -- "LC_NUMERIC", -- "LC_TIME", -- "LC_COLLATE", -- "LC_MONETARY", -- "LC_MESSAGES", --}; -- --int __setlocalecat(locale_t loc, int cat, const char *val) --{ -- if (!*val) { -- (val = getenv("LC_ALL")) && *val || -- (val = getenv(envvars[cat])) && *val || -- (val = getenv("LANG")) && *val || -- (val = "C.UTF-8"); -- } -- -- size_t n; -- for (n=0; n<LOCALE_NAME_MAX && val[n] && val[n]!='/'; n++); -- if (val[0]=='.' || val[n]) val = "C.UTF-8"; -- int builtin = (val[0]=='C' && !val[1]) -- || !strcmp(val, "C.UTF-8") -- || !strcmp(val, "POSIX"); -- struct __locale_map *data, *old; -- -- switch (cat) { -- case LC_CTYPE: -- a_store(&loc->ctype_utf8, !builtin || val[1]=='.'); -- break; -- case LC_MESSAGES: -- if (builtin) { -- loc->messages_name[0] = 0; -- } else { -- memcpy(loc->messages_name, val, n); -- loc->messages_name[n] = 0; -- } -- /* fall through */ -- default: -- data = builtin ? 0 : findlocale(val, n); -- if (data == loc->cat[cat-2]) break; -- do old = loc->cat[cat-2]; -- while (a_cas_p(&loc->cat[cat-2], old, data) != old); -- case LC_NUMERIC: -- break; -- } -- return 0; --} ---- a/src/locale/dcngettext.c -+++ b/src/locale/dcngettext.c -@@ -84,13 +84,15 @@ char *bindtextdomain(const char *domainn - } - - static const char catnames[][12] = { -+ "LC_CTYPE", -+ "LC_NUMERIC", - "LC_TIME", - "LC_COLLATE", - "LC_MONETARY", - "LC_MESSAGES", - }; - --static const char catlens[] = { 7, 10, 11, 11 }; -+static const char catlens[] = { 8, 10, 7, 10, 11, 11 }; - - struct msgcat { - struct msgcat *next; -@@ -117,10 +119,12 @@ char *dcngettext(const char *domainname, - static struct msgcat *volatile cats; - struct msgcat *p; - struct __locale_struct *loc = CURRENT_LOCALE; -- struct __locale_map *lm; -+ const struct __locale_map *lm; - const char *dirname, *locname, *catname; - size_t dirlen, loclen, catlen, domlen; - -+ if ((unsigned)category >= LC_ALL) goto notrans; -+ - if (!domainname) domainname = __gettextdomain(); - - domlen = strlen(domainname); -@@ -129,25 +133,15 @@ char *dcngettext(const char *domainname, - dirname = gettextdir(domainname, &dirlen); - if (!dirname) goto notrans; - -- switch (category) { -- case LC_MESSAGES: -- locname = loc->messages_name; -- if (!*locname) goto notrans; -- break; -- case LC_TIME: -- case LC_MONETARY: -- case LC_COLLATE: -- lm = loc->cat[category-2]; -- if (!lm) goto notrans; -- locname = lm->name; -- break; -- default: -+ lm = loc->cat[category]; -+ if (!lm) { - notrans: - return (char *) ((n == 1) ? msgid1 : msgid2); - } -+ locname = lm->name; - -- catname = catnames[category-2]; -- catlen = catlens[category-2]; -+ catname = catnames[category]; -+ catlen = catlens[category]; - loclen = strlen(locname); - - size_t namelen = dirlen+1 + loclen+1 + catlen+1 + domlen+3; ---- a/src/locale/duplocale.c -+++ b/src/locale/duplocale.c -@@ -5,17 +5,10 @@ - - locale_t __duplocale(locale_t old) - { -- locale_t new = calloc(1, sizeof *new + LOCALE_NAME_MAX + 1); -+ locale_t new = malloc(sizeof *new); - if (!new) return 0; -- new->messages_name = (void *)(new+1); -- - if (old == LC_GLOBAL_LOCALE) old = &libc.global_locale; -- new->ctype_utf8 = old->ctype_utf8; -- if (old->messages_name) -- strcpy(new->messages_name, old->messages_name); -- -- for (size_t i=0; i<sizeof new->cat/sizeof new->cat[0]; i++) -- new->cat[i] = old->cat[i]; -+ *new = *old; - return new; - } - ---- a/src/locale/freelocale.c -+++ b/src/locale/freelocale.c -@@ -2,9 +2,11 @@ - #include "locale_impl.h" - #include "libc.h" - -+int __loc_is_allocated(locale_t); -+ - void freelocale(locale_t l) - { -- free(l); -+ if (__loc_is_allocated(l)) free(l); - } - - weak_alias(freelocale, __freelocale); ---- a/src/locale/iconv.c -+++ b/src/locale/iconv.c -@@ -23,19 +23,13 @@ - #define BIG5 0340 - #define EUC_KR 0350 - --/* FIXME: these are not implemented yet -- * EUC: A1-FE A1-FE -- * GBK: 81-FE 40-7E,80-FE -- * Big5: A1-FE 40-7E,A1-FE -- */ -- - /* Definitions of charmaps. Each charmap consists of: - * 1. Empty-string-terminated list of null-terminated aliases. - * 2. Special type code or number of elided entries. - * 3. Character table (size determined by field 2). */ - - static const unsigned char charmaps[] = --"utf8\0\0\310" -+"utf8\0char\0\0\310" - "wchart\0\0\306" - "ucs2\0ucs2be\0\0\304" - "ucs2le\0\0\305" -@@ -90,6 +84,7 @@ static int fuzzycmp(const unsigned char - static size_t find_charmap(const void *name) - { - const unsigned char *s; -+ if (!*(char *)name) name=charmaps; /* "utf8" */ - for (s=charmaps; *s; ) { - if (!fuzzycmp(name, s)) { - for (; *s; s+=strlen((void *)s)+1); ---- /dev/null -+++ b/src/locale/locale_map.c -@@ -0,0 +1,124 @@ -+#include <locale.h> -+#include <string.h> -+#include "locale_impl.h" -+#include "libc.h" -+#include "atomic.h" -+ -+const char *__lctrans_impl(const char *msg, const struct __locale_map *lm) -+{ -+ const char *trans = 0; -+ if (lm) trans = __mo_lookup(lm->map, lm->map_size, msg); -+ return trans ? trans : msg; -+} -+ -+const unsigned char *__map_file(const char *, size_t *); -+int __munmap(void *, size_t); -+char *__strchrnul(const char *, int); -+ -+static const char envvars[][12] = { -+ "LC_CTYPE", -+ "LC_NUMERIC", -+ "LC_TIME", -+ "LC_COLLATE", -+ "LC_MONETARY", -+ "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]; -+ static void *volatile loc_head; -+ const struct __locale_map *p; -+ struct __locale_map *new = 0; -+ const char *path = 0, *z; -+ char buf[256]; -+ size_t l, n; -+ -+ if (!*val) { -+ (val = getenv("LC_ALL")) && *val || -+ (val = getenv(envvars[cat])) && *val || -+ (val = getenv("LANG")) && *val || -+ (val = "C.UTF-8"); -+ } -+ -+ /* Limit name length and forbid leading dot or any slashes. */ -+ for (n=0; n<LOCALE_NAME_MAX && val[n] && val[n]!='/'; n++); -+ if (val[0]=='.' || val[n]) val = "C.UTF-8"; -+ int builtin = (val[0]=='C' && !val[1]) -+ || !strcmp(val, "C.UTF-8") -+ || !strcmp(val, "POSIX"); -+ -+ if (builtin) { -+ if (cat == LC_CTYPE && val[1]=='.') -+ return (void *)&__c_dot_utf8; -+ return 0; -+ } -+ -+ for (p=loc_head; p; p=p->next) -+ if (!strcmp(val, p->name)) return p; -+ -+ LOCK(lock); -+ -+ for (p=loc_head; p; p=p->next) -+ if (!strcmp(val, p->name)) { -+ UNLOCK(lock); -+ return p; -+ } -+ -+ if (!libc.secure) path = getenv("MUSL_LOCPATH"); -+ /* FIXME: add a default path? */ -+ -+ if (path) for (; *path; path=z+!!*z) { -+ z = __strchrnul(path, ':'); -+ l = z - path - !!*z; -+ if (l >= sizeof buf - n - 2) continue; -+ memcpy(buf, path, l); -+ buf[l] = '/'; -+ memcpy(buf+l+1, val, n); -+ buf[l+1+n] = 0; -+ size_t map_size; -+ const void *map = __map_file(buf, &map_size); -+ if (map) { -+ new = malloc(sizeof *new); -+ if (!new) { -+ __munmap((void *)map, map_size); -+ break; -+ } -+ new->map = map; -+ new->map_size = map_size; -+ memcpy(new->name, val, n); -+ new->name[n] = 0; -+ new->next = loc_head; -+ loc_head = new; -+ break; -+ } -+ } -+ -+ /* If no locale definition was found, make a locale map -+ * object anyway to store the name, which is kept for the -+ * 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; -+ memcpy(new->name, val, n); -+ new->name[n] = 0; -+ new->next = loc_head; -+ loc_head = new; -+ } -+ -+ /* For LC_CTYPE, never return a null pointer unless the -+ * requested name was "C" or "POSIX". */ -+ if (!new && cat == LC_CTYPE) new = (void *)&__c_dot_utf8; -+ -+ UNLOCK(lock); -+ return new; -+} ---- a/src/locale/newlocale.c -+++ b/src/locale/newlocale.c -@@ -3,22 +3,52 @@ - #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; -+} -+ - locale_t __newlocale(int mask, const char *name, locale_t loc) - { -- int i; -+ int i, j; -+ struct __locale_struct tmp; -+ const struct __locale_map *lm; - -- if (!loc) { -- loc = calloc(1, sizeof *loc + LOCALE_NAME_MAX + 1); -- if (!loc) return 0; -- loc->messages_name = (void *)(loc+1); -+ /* For locales with allocated storage, modify in-place. */ -+ if (__loc_is_allocated(loc)) { - for (i=0; i<LC_ALL; i++) -- if (!(mask & (1<<i))) -- __setlocalecat(loc, i, ""); -+ if (mask & (1<<i)) -+ loc->cat[i] = __get_locale(i, name); -+ return loc; -+ } -+ -+ /* Otherwise, build a temporary locale object, which will only -+ * be instantiated in allocated storage if it does not match -+ * one of the built-in static locales. This makes the common -+ * usage case for newlocale, getting a C locale with predictable -+ * behavior, very fast, and more importantly, fail-safe. */ -+ for (j=i=0; i<LC_ALL; i++) { -+ if (loc && !(mask & (1<<i))) -+ lm = loc->cat[i]; -+ else -+ lm = __get_locale(i, mask & (1<<i) ? name : ""); -+ if (lm) j++; -+ tmp.cat[i] = lm; - } - -- for (i=0; i<LC_ALL; i++) -- if (mask & (1<<i)) -- __setlocalecat(loc, i, name); -+ 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; -+ -+ if ((loc = malloc(sizeof *loc))) *loc = tmp; - - return loc; - } ---- a/src/locale/setlocale.c -+++ b/src/locale/setlocale.c -@@ -5,73 +5,66 @@ - #include "libc.h" - #include "atomic.h" - --static char buf[2+4*(LOCALE_NAME_MAX+1)]; -+static char buf[LC_ALL*(LOCALE_NAME_MAX+1)]; - --char *setlocale(int cat, const char *name) -+static char *setlocale_one_unlocked(int cat, const char *name) - { -- struct __locale_map *lm; -- int i, j; -+ const struct __locale_map *lm; - -- if (!libc.global_locale.messages_name) { -- libc.global_locale.messages_name = -- buf + 2 + 3*(LOCALE_NAME_MAX+1); -- } -+ if (name) libc.global_locale.cat[cat] = lm = __get_locale(cat, name); -+ else lm = libc.global_locale.cat[cat]; -+ -+ return lm ? (char *)lm->name : "C"; -+} -+ -+char *__strchrnul(const char *, int); -+ -+char *setlocale(int cat, const char *name) -+{ -+ static volatile int lock[2]; - - if ((unsigned)cat > LC_ALL) return 0; - -+ LOCK(lock); -+ - /* For LC_ALL, setlocale is required to return a string which - * encodes the current setting for all categories. The format of - * this string is unspecified, and only the following code, which - * performs both the serialization and deserialization, depends - * on the format, so it can easily be changed if needed. */ - if (cat == LC_ALL) { -+ int i; - if (name) { -- char part[LOCALE_NAME_MAX+1]; -- if (name[0] && name[1]==';' -- && strlen(name) > 2 + 3*(LOCALE_NAME_MAX+1)) { -- part[0] = name[0]; -- part[1] = 0; -- setlocale(LC_CTYPE, part); -- part[LOCALE_NAME_MAX] = 0; -- for (i=LC_TIME; i<LC_MESSAGES; i++) { -- memcpy(part, name + 2 + (i-2)*(LOCALE_NAME_MAX+1), LOCALE_NAME_MAX); -- for (j=LOCALE_NAME_MAX-1; j && part[j]==';'; j--) -- part[j] = 0; -- setlocale(i, part); -+ char part[LOCALE_NAME_MAX+1] = "C.UTF-8"; -+ const char *p = name; -+ for (i=0; i<LC_ALL; i++) { -+ const char *z = __strchrnul(p, ';'); -+ if (z-p <= LOCALE_NAME_MAX) { -+ memcpy(part, p, z-p); -+ part[z-p] = 0; -+ if (*z) p = z+1; - } -- setlocale(LC_MESSAGES, name + 2 + 3*(LOCALE_NAME_MAX+1)); -- } else { -- for (i=0; i<LC_ALL; i++) -- setlocale(i, name); -+ setlocale_one_unlocked(i, part); - } - } -- memset(buf, ';', 2 + 3*(LOCALE_NAME_MAX+1)); -- buf[0] = libc.global_locale.ctype_utf8 ? 'U' : 'C'; -- for (i=LC_TIME; i<LC_MESSAGES; i++) { -- lm = libc.global_locale.cat[i-2]; -- if (lm) memcpy(buf + 2 + (i-2)*(LOCALE_NAME_MAX+1), -- lm->name, strlen(lm->name)); -+ char *s = buf; -+ for (i=0; i<LC_ALL; i++) { -+ const struct __locale_map *lm = -+ libc.global_locale.cat[i]; -+ const char *part = lm ? lm->name : "C"; -+ size_t l = strlen(part); -+ memcpy(s, part, l); -+ s[l] = ';'; -+ s += l+1; - } -+ *--s = 0; -+ UNLOCK(lock); - return buf; - } - -- if (name) { -- int adj = libc.global_locale.ctype_utf8; -- __setlocalecat(&libc.global_locale, cat, name); -- adj -= libc.global_locale.ctype_utf8; -- if (adj) a_fetch_add(&libc.bytelocale_cnt_minus_1, adj); -- } -+ char *ret = setlocale_one_unlocked(cat, name); - -- switch (cat) { -- case LC_CTYPE: -- return libc.global_locale.ctype_utf8 ? "C.UTF-8" : "C"; -- case LC_NUMERIC: -- return "C"; -- case LC_MESSAGES: -- return libc.global_locale.messages_name[0] -- ? libc.global_locale.messages_name : "C"; -- default: -- lm = libc.global_locale.cat[cat-2]; -- return lm ? lm->name : "C"; -- } -+ UNLOCK(lock); -+ -+ return ret; - } ---- a/src/locale/uselocale.c -+++ b/src/locale/uselocale.c -@@ -10,15 +10,7 @@ locale_t __uselocale(locale_t new) - - if (new == LC_GLOBAL_LOCALE) new = global; - -- if (new && new != old) { -- int adj = 0; -- if (new == global) a_dec(&libc.uselocale_cnt); -- else if (!new->ctype_utf8) adj++; -- if (old == global) a_inc(&libc.uselocale_cnt); -- else if (!old->ctype_utf8) adj--; -- a_fetch_add(&libc.bytelocale_cnt_minus_1, adj); -- self->locale = new; -- } -+ self->locale = new; - - return old == global ? LC_GLOBAL_LOCALE : old; - } ---- a/src/stdio/__stdio_read.c -+++ b/src/stdio/__stdio_read.c -@@ -21,7 +21,6 @@ size_t __stdio_read(FILE *f, unsigned ch - pthread_cleanup_pop(0); - if (cnt <= 0) { - f->flags |= F_EOF ^ ((F_ERR^F_EOF) & cnt); -- f->rpos = f->rend = 0; - return cnt; - } - if (cnt <= iov[0].iov_len) return cnt; ---- a/src/stdio/__toread.c -+++ b/src/stdio/__toread.c -@@ -5,12 +5,12 @@ int __toread(FILE *f) - f->mode |= f->mode-1; - if (f->wpos > f->buf) f->write(f, 0, 0); - f->wpos = f->wbase = f->wend = 0; -- if (f->flags & (F_EOF|F_NORD)) { -- if (f->flags & F_NORD) f->flags |= F_ERR; -+ if (f->flags & F_NORD) { -+ f->flags |= F_ERR; - return EOF; - } -- f->rpos = f->rend = f->buf; -- return 0; -+ f->rpos = f->rend = f->buf + f->buf_size; -+ return (f->flags & F_EOF) ? EOF : 0; - } - - void __stdio_exit_needed(void); ---- a/src/stdio/__uflow.c -+++ b/src/stdio/__uflow.c -@@ -1,11 +1,11 @@ - #include "stdio_impl.h" - --/* This function will never be called if there is already data -- * buffered for reading. Thus we can get by with very few branches. */ -+/* This function assumes it will never be called if there is already -+ * data buffered for reading. */ - - int __uflow(FILE *f) - { - unsigned char c; -- if ((f->rend || !__toread(f)) && f->read(f, &c, 1)==1) return c; -+ if (!__toread(f) && f->read(f, &c, 1)==1) return c; - return EOF; - } ---- a/src/stdio/ungetc.c -+++ b/src/stdio/ungetc.c -@@ -6,7 +6,8 @@ int ungetc(int c, FILE *f) - - FLOCK(f); - -- if ((!f->rend && __toread(f)) || f->rpos <= f->buf - UNGET) { -+ if (!f->rpos) __toread(f); -+ if (!f->rpos || f->rpos <= f->buf - UNGET) { - FUNLOCK(f); - return EOF; - } ---- a/src/stdio/ungetwc.c -+++ b/src/stdio/ungetwc.c -@@ -19,7 +19,8 @@ wint_t ungetwc(wint_t c, FILE *f) - - f->mode |= f->mode+1; - -- if ((!f->rend && __toread(f)) || f->rpos < f->buf - UNGET + l) { -+ if (!f->rpos) __toread(f); -+ if (!f->rpos || f->rpos < f->buf - UNGET + l) { - FUNLOCK(f); - return EOF; - } ---- a/src/thread/i386/__set_thread_area.s -+++ b/src/thread/i386/__set_thread_area.s -@@ -6,10 +6,10 @@ __set_thread_area: - push $0x51 - push $0xfffff - push 16(%esp) -- xor %edx,%edx -- mov %gs,%dx -- sub $3,%edx -- sar $3,%edx -+ call 1f -+1: addl $4f-1b,(%esp) -+ pop %ecx -+ mov (%ecx),%edx - push %edx - mov %esp,%ebx - xor %eax,%eax -@@ -18,6 +18,7 @@ __set_thread_area: - testl %eax,%eax - jnz 2f - movl (%esp),%edx -+ movl %edx,(%ecx) - leal 3(,%edx,8),%edx - 3: movw %dx,%gs - 1: -@@ -38,3 +39,7 @@ __set_thread_area: - mov $7,%dl - inc %al - jmp 3b -+ -+.data -+ .align 4 -+4: .long -1 ---- a/src/thread/mips/syscall_cp.s -+++ b/src/thread/mips/syscall_cp.s -@@ -2,10 +2,13 @@ - - .global __cp_begin - .hidden __cp_begin -+.type __cp_begin,@function - .global __cp_end - .hidden __cp_end -+.type __cp_end,@function - .global __cp_cancel - .hidden __cp_cancel -+.type __cp_cancel,@function - .hidden __cancel - .global __syscall_cp_asm - .hidden __syscall_cp_asm ---- a/src/thread/pthread_create.c -+++ b/src/thread/pthread_create.c -@@ -67,12 +67,6 @@ _Noreturn void __pthread_exit(void *resu - exit(0); - } - -- if (self->locale != &libc.global_locale) { -- a_dec(&libc.uselocale_cnt); -- if (self->locale->ctype_utf8) -- a_dec(&libc.bytelocale_cnt_minus_1); -- } -- - /* Process robust list in userspace to handle non-pshared mutexes - * and the detached thread case where the robust list head will - * be invalid when the kernel would process it. */ diff --git a/toolchain/musl/patches/001-git-2015-06-16.patch b/toolchain/musl/patches/001-git-2015-06-16.patch new file mode 100644 index 0000000000..5941adc320 --- /dev/null +++ b/toolchain/musl/patches/001-git-2015-06-16.patch @@ -0,0 +1,1578 @@ +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/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/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/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/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/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 +@@ -1192,6 +1192,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 +1211,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 +--- /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; + } +--- /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,46 @@ + #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); +--- 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; ++ /* 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 (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; ++ /* 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) +--- 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/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 #16 ++ 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/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++) { + +--- /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/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); diff --git a/toolchain/musl/patches/900-iconv_size_hack.patch b/toolchain/musl/patches/900-iconv_size_hack.patch index f4e2be4d03..343915fb06 100644 --- a/toolchain/musl/patches/900-iconv_size_hack.patch +++ b/toolchain/musl/patches/900-iconv_size_hack.patch @@ -1,6 +1,6 @@ --- a/src/locale/iconv.c +++ b/src/locale/iconv.c -@@ -38,6 +38,7 @@ static const unsigned char charmaps[] = +@@ -39,6 +39,7 @@ static const unsigned char charmaps[] = "ucs4\0ucs4be\0utf32\0utf32be\0\0\300" "ucs4le\0utf32le\0\0\303" "ascii\0usascii\0iso646\0iso646us\0\0\307" @@ -8,7 +8,7 @@ "eucjp\0\0\320" "shiftjis\0sjis\0\0\321" "gb18030\0\0\330" -@@ -45,6 +46,7 @@ static const unsigned char charmaps[] = +@@ -46,6 +47,7 @@ static const unsigned char charmaps[] = "gb2312\0\0\332" "big5\0bigfive\0cp950\0big5hkscs\0\0\340" "euckr\0ksc5601\0ksx1001\0cp949\0\0\350" @@ -16,7 +16,7 @@ #include "codepages.h" ; -@@ -52,6 +54,7 @@ static const unsigned short legacy_chars +@@ -53,6 +55,7 @@ static const unsigned short legacy_chars #include "legacychars.h" }; @@ -24,7 +24,7 @@ static const unsigned short jis0208[84][94] = { #include "jis0208.h" }; -@@ -71,6 +74,7 @@ static const unsigned short hkscs[] = { +@@ -72,6 +75,7 @@ static const unsigned short hkscs[] = { static const unsigned short ksc[93][94] = { #include "ksc.h" }; @@ -32,7 +32,7 @@ static int fuzzycmp(const unsigned char *a, const unsigned char *b) { -@@ -212,6 +216,7 @@ size_t iconv(iconv_t cd0, char **restric +@@ -216,6 +220,7 @@ size_t iconv(iconv_t cd0, char **restric c = ((c-0xd7c0)<<10) + (d-0xdc00); } break; @@ -40,7 +40,7 @@ case SHIFT_JIS: if (c-0xa1 <= 0xdf-0xa1) { c += 0xff61-0xa1; -@@ -358,6 +363,7 @@ size_t iconv(iconv_t cd0, char **restric +@@ -362,6 +367,7 @@ size_t iconv(iconv_t cd0, char **restric c = ksc[c][d]; if (!c) goto ilseq; break; |