| author | |
| committer | |
| log | e5fab3ba6898cce3eba63192b0944f4e2208a3b8 |
| tree | b03fc02418a2d18fcf239c0012969a3774cbf844 |
| parent | dba94f453a55d02cc87667fc5636aed3237483f6 |
158 files changed, 2753 insertions(+), 1762 deletions(-)
lib/libc/musl/arch/arm/syscall_arch.h-6| ... | @@ -98,12 +98,6 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo | ... | @@ -98,12 +98,6 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo |
| 98 | 	__asm_syscall(R7_OPERAND, "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5)); | 98 | 	__asm_syscall(R7_OPERAND, "0"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5)); |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | #define VDSO_USEFUL | ||
| 102 | #define VDSO_CGT32_SYM "__vdso_clock_gettime" | ||
| 103 | #define VDSO_CGT32_VER "LINUX_2.6" | ||
| 104 | #define VDSO_CGT_SYM "__vdso_clock_gettime64" | ||
| 105 | #define VDSO_CGT_VER "LINUX_2.6" | ||
| 106 | |||
| 107 | #define SYSCALL_FADVISE_6_ARG | 101 | #define SYSCALL_FADVISE_6_ARG |
| 108 | 102 | ||
| 109 | #define SYSCALL_IPC_BROKEN_MODE | 103 | #define SYSCALL_IPC_BROKEN_MODE |
lib/libc/musl/arch/mips/bits/signal.h+1-1| ... | @@ -93,7 +93,7 @@ typedef struct __ucontext { | ... | @@ -93,7 +93,7 @@ typedef struct __ucontext { |
| 93 | #define SIGTRAP 5 | 93 | #define SIGTRAP 5 |
| 94 | #define SIGABRT 6 | 94 | #define SIGABRT 6 |
| 95 | #define SIGIOT SIGABRT | 95 | #define SIGIOT SIGABRT |
| 96 | #define SIGSTKFLT 7 | 96 | #define SIGEMT 7 |
| 97 | #define SIGFPE 8 | 97 | #define SIGFPE 8 |
| 98 | #define SIGKILL 9 | 98 | #define SIGKILL 9 |
| 99 | #define SIGBUS 10 | 99 | #define SIGBUS 10 |
lib/libc/musl/arch/mips/syscall_arch.h+40-40| ... | @@ -18,26 +18,26 @@ | ... | @@ -18,26 +18,26 @@ |
| 18 | static inline long __syscall0(long n) | 18 | static inline long __syscall0(long n) |
| 19 | { | 19 | { |
| 20 | 	register long r7 __asm__("$7"); | 20 | 	register long r7 __asm__("$7"); |
| 21 | 	register long r2 __asm__("$2") = n; | 21 | 	register long r2 __asm__("$2"); |
| 22 | 	__asm__ __volatile__ ( | 22 | 	__asm__ __volatile__ ( |
| 23 | 		"syscall" | 23 | 		"addu $2,$0,%2 ; syscall" |
| 24 | 		: "+r"(r2), "=r"(r7) | 24 | 		: "=&r"(r2), "=r"(r7) |
| 25 | 		: | 25 | 		: "ir"(n), "0"(r2) |
| 26 | 		: SYSCALL_CLOBBERLIST, "$8", "$9", "$10"); | 26 | 		: SYSCALL_CLOBBERLIST, "$8", "$9", "$10"); |
| 27 | 	return r7 ? -r2 : r2; | 27 | 	return r7 && r2>0 ? -r2 : r2; |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | static inline long __syscall1(long n, long a) | 30 | static inline long __syscall1(long n, long a) |
| 31 | { | 31 | { |
| 32 | 	register long r4 __asm__("$4") = a; | 32 | 	register long r4 __asm__("$4") = a; |
| 33 | 	register long r7 __asm__("$7"); | 33 | 	register long r7 __asm__("$7"); |
| 34 | 	register long r2 __asm__("$2") = n; | 34 | 	register long r2 __asm__("$2"); |
| 35 | 	__asm__ __volatile__ ( | 35 | 	__asm__ __volatile__ ( |
| 36 | 		"syscall" | 36 | 		"addu $2,$0,%2 ; syscall" |
| 37 | 		: "+r"(r2), "=r"(r7) | 37 | 		: "=&r"(r2), "=r"(r7) |
| 38 | 		: "r"(r4) | 38 | 		: "ir"(n), "0"(r2), "r"(r4) |
| 39 | 		: SYSCALL_CLOBBERLIST, "$8", "$9", "$10"); | 39 | 		: SYSCALL_CLOBBERLIST, "$8", "$9", "$10"); |
| 40 | 	return r7 ? -r2 : r2; | 40 | 	return r7 && r2>0 ? -r2 : r2; |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | static inline long __syscall2(long n, long a, long b) | 43 | static inline long __syscall2(long n, long a, long b) |
| ... | @@ -45,13 +45,13 @@ static inline long __syscall2(long n, long a, long b) | ... | @@ -45,13 +45,13 @@ static inline long __syscall2(long n, long a, long b) |
| 45 | 	register long r4 __asm__("$4") = a; | 45 | 	register long r4 __asm__("$4") = a; |
| 46 | 	register long r5 __asm__("$5") = b; | 46 | 	register long r5 __asm__("$5") = b; |
| 47 | 	register long r7 __asm__("$7"); | 47 | 	register long r7 __asm__("$7"); |
| 48 | 	register long r2 __asm__("$2") = n; | 48 | 	register long r2 __asm__("$2"); |
| 49 | 	__asm__ __volatile__ ( | 49 | 	__asm__ __volatile__ ( |
| 50 | 		"syscall" | 50 | 		"addu $2,$0,%2 ; syscall" |
| 51 | 		: "+r"(r2), "=r"(r7) | 51 | 		: "=&r"(r2), "=r"(r7) |
| 52 | 		: "r"(r4), "r"(r5) | 52 | 		: "ir"(n), "0"(r2), "r"(r4), "r"(r5) |
| 53 | 		: SYSCALL_CLOBBERLIST, "$8", "$9", "$10"); | 53 | 		: SYSCALL_CLOBBERLIST, "$8", "$9", "$10"); |
| 54 | 	return r7 ? -r2 : r2; | 54 | 	return r7 && r2>0 ? -r2 : r2; |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | static inline long __syscall3(long n, long a, long b, long c) | 57 | static inline long __syscall3(long n, long a, long b, long c) |
| ... | @@ -60,13 +60,13 @@ static inline long __syscall3(long n, long a, long b, long c) | ... | @@ -60,13 +60,13 @@ static inline long __syscall3(long n, long a, long b, long c) |
| 60 | 	register long r5 __asm__("$5") = b; | 60 | 	register long r5 __asm__("$5") = b; |
| 61 | 	register long r6 __asm__("$6") = c; | 61 | 	register long r6 __asm__("$6") = c; |
| 62 | 	register long r7 __asm__("$7"); | 62 | 	register long r7 __asm__("$7"); |
| 63 | 	register long r2 __asm__("$2") = n; | 63 | 	register long r2 __asm__("$2"); |
| 64 | 	__asm__ __volatile__ ( | 64 | 	__asm__ __volatile__ ( |
| 65 | 		"syscall" | 65 | 		"addu $2,$0,%2 ; syscall" |
| 66 | 		: "+r"(r2), "=r"(r7) | 66 | 		: "=&r"(r2), "=r"(r7) |
| 67 | 		: "r"(r4), "r"(r5), "r"(r6) | 67 | 		: "ir"(n), "0"(r2), "r"(r4), "r"(r5), "r"(r6) |
| 68 | 		: SYSCALL_CLOBBERLIST, "$8", "$9", "$10"); | 68 | 		: SYSCALL_CLOBBERLIST, "$8", "$9", "$10"); |
| 69 | 	return r7 ? -r2 : r2; | 69 | 	return r7 && r2>0 ? -r2 : r2; |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | static inline long __syscall4(long n, long a, long b, long c, long d) | 72 | static inline long __syscall4(long n, long a, long b, long c, long d) |
| ... | @@ -75,13 +75,13 @@ static inline long __syscall4(long n, long a, long b, long c, long d) | ... | @@ -75,13 +75,13 @@ static inline long __syscall4(long n, long a, long b, long c, long d) |
| 75 | 	register long r5 __asm__("$5") = b; | 75 | 	register long r5 __asm__("$5") = b; |
| 76 | 	register long r6 __asm__("$6") = c; | 76 | 	register long r6 __asm__("$6") = c; |
| 77 | 	register long r7 __asm__("$7") = d; | 77 | 	register long r7 __asm__("$7") = d; |
| 78 | 	register long r2 __asm__("$2") = n; | 78 | 	register long r2 __asm__("$2"); |
| 79 | 	__asm__ __volatile__ ( | 79 | 	__asm__ __volatile__ ( |
| 80 | 		"syscall" | 80 | 		"addu $2,$0,%2 ; syscall" |
| 81 | 		: "+r"(r2), "+r"(r7) | 81 | 		: "=&r"(r2), "+r"(r7) |
| 82 | 		: "r"(r4), "r"(r5), "r"(r6) | 82 | 		: "ir"(n), "0"(r2), "r"(r4), "r"(r5), "r"(r6) |
| 83 | 		: SYSCALL_CLOBBERLIST, "$8", "$9", "$10"); | 83 | 		: SYSCALL_CLOBBERLIST, "$8", "$9", "$10"); |
| 84 | 	return r7 ? -r2 : r2; | 84 | 	return r7 && r2>0 ? -r2 : r2; |
| 85 | } | 85 | } |
| 86 | 86 | ||
| 87 | static inline long __syscall5(long n, long a, long b, long c, long d, long e) | 87 | static inline long __syscall5(long n, long a, long b, long c, long d, long e) |
| ... | @@ -91,15 +91,15 @@ static inline long __syscall5(long n, long a, long b, long c, long d, long e) | ... | @@ -91,15 +91,15 @@ static inline long __syscall5(long n, long a, long b, long c, long d, long e) |
| 91 | 	register long r6 __asm__("$6") = c; | 91 | 	register long r6 __asm__("$6") = c; |
| 92 | 	register long r7 __asm__("$7") = d; | 92 | 	register long r7 __asm__("$7") = d; |
| 93 | 	register long r8 __asm__("$8") = e; | 93 | 	register long r8 __asm__("$8") = e; |
| 94 | 	register long r2 __asm__("$2") = n; | 94 | 	register long r2 __asm__("$2"); |
| 95 | 	__asm__ __volatile__ ( | 95 | 	__asm__ __volatile__ ( |
| 96 | 		"subu $sp,$sp,32 ; sw $8,16($sp) ; " | 96 | 		"subu $sp,$sp,32 ; sw $8,16($sp) ; " |
| 97 | 		"syscall ;" | 97 | 		"addu $2,$0,%3 ; syscall ;" |
| 98 | 		"addu $sp,$sp,32" | 98 | 		"addu $sp,$sp,32" |
| 99 | 		: "+r"(r2), "+r"(r7), "+r"(r8) | 99 | 		: "=&r"(r2), "+r"(r7), "+r"(r8) |
| 100 | 		: "r"(r4), "r"(r5), "r"(r6) | 100 | 		: "ir"(n), "0"(r2), "r"(r4), "r"(r5), "r"(r6) |
| 101 | 		: SYSCALL_CLOBBERLIST, "$9", "$10"); | 101 | 		: SYSCALL_CLOBBERLIST, "$9", "$10"); |
| 102 | 	return r7 ? -r2 : r2; | 102 | 	return r7 && r2>0 ? -r2 : r2; |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | static inline long __syscall6(long n, long a, long b, long c, long d, long e, long f) | 105 | static inline long __syscall6(long n, long a, long b, long c, long d, long e, long f) |
| ... | @@ -110,15 +110,15 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo | ... | @@ -110,15 +110,15 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo |
| 110 | 	register long r7 __asm__("$7") = d; | 110 | 	register long r7 __asm__("$7") = d; |
| 111 | 	register long r8 __asm__("$8") = e; | 111 | 	register long r8 __asm__("$8") = e; |
| 112 | 	register long r9 __asm__("$9") = f; | 112 | 	register long r9 __asm__("$9") = f; |
| 113 | 	register long r2 __asm__("$2") = n; | 113 | 	register long r2 __asm__("$2"); |
| 114 | 	__asm__ __volatile__ ( | 114 | 	__asm__ __volatile__ ( |
| 115 | 		"subu $sp,$sp,32 ; sw $8,16($sp) ; sw $9,20($sp) ; " | 115 | 		"subu $sp,$sp,32 ; sw $8,16($sp) ; sw $9,20($sp) ; " |
| 116 | 		"syscall ;" | 116 | 		"addu $2,$0,%4 ; syscall ;" |
| 117 | 		"addu $sp,$sp,32" | 117 | 		"addu $sp,$sp,32" |
| 118 | 		: "+r"(r2), "+r"(r7), "+r"(r8), "+r"(r9) | 118 | 		: "=&r"(r2), "+r"(r7), "+r"(r8), "+r"(r9) |
| 119 | 		: "r"(r4), "r"(r5), "r"(r6) | 119 | 		: "ir"(n), "0"(r2), "r"(r4), "r"(r5), "r"(r6) |
| 120 | 		: SYSCALL_CLOBBERLIST, "$10"); | 120 | 		: SYSCALL_CLOBBERLIST, "$10"); |
| 121 | 	return r7 ? -r2 : r2; | 121 | 	return r7 && r2>0 ? -r2 : r2; |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | static inline long __syscall7(long n, long a, long b, long c, long d, long e, long f, long g) | 124 | static inline long __syscall7(long n, long a, long b, long c, long d, long e, long f, long g) |
| ... | @@ -130,15 +130,15 @@ static inline long __syscall7(long n, long a, long b, long c, long d, long e, lo | ... | @@ -130,15 +130,15 @@ static inline long __syscall7(long n, long a, long b, long c, long d, long e, lo |
| 130 | 	register long r8 __asm__("$8") = e; | 130 | 	register long r8 __asm__("$8") = e; |
| 131 | 	register long r9 __asm__("$9") = f; | 131 | 	register long r9 __asm__("$9") = f; |
| 132 | 	register long r10 __asm__("$10") = g; | 132 | 	register long r10 __asm__("$10") = g; |
| 133 | 	register long r2 __asm__("$2") = n; | 133 | 	register long r2 __asm__("$2"); |
| 134 | 	__asm__ __volatile__ ( | 134 | 	__asm__ __volatile__ ( |
| 135 | 		"subu $sp,$sp,32 ; sw $8,16($sp) ; sw $9,20($sp) ; sw $10,24($sp) ; " | 135 | 		"subu $sp,$sp,32 ; sw $8,16($sp) ; sw $9,20($sp) ; sw $10,24($sp) ; " |
| 136 | 		"syscall ;" | 136 | 		"addu $2,$0,%5 ; syscall ;" |
| 137 | 		"addu $sp,$sp,32" | 137 | 		"addu $sp,$sp,32" |
| 138 | 		: "+r"(r2), "+r"(r7), "+r"(r8), "+r"(r9), "+r"(r10) | 138 | 		: "=&r"(r2), "+r"(r7), "+r"(r8), "+r"(r9), "+r"(r10) |
| 139 | 		: "r"(r4), "r"(r5), "r"(r6) | 139 | 		: "ir"(n), "0"(r2), "r"(r4), "r"(r5), "r"(r6) |
| 140 | 		: SYSCALL_CLOBBERLIST); | 140 | 		: SYSCALL_CLOBBERLIST); |
| 141 | 	return r7 ? -r2 : r2; | 141 | 	return r7 && r2>0 ? -r2 : r2; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | #define VDSO_USEFUL | 144 | #define VDSO_USEFUL |
lib/libc/musl/arch/mips64/bits/signal.h+1-1| ... | @@ -112,7 +112,7 @@ typedef struct __ucontext { | ... | @@ -112,7 +112,7 @@ typedef struct __ucontext { |
| 112 | #define SIGTRAP 5 | 112 | #define SIGTRAP 5 |
| 113 | #define SIGABRT 6 | 113 | #define SIGABRT 6 |
| 114 | #define SIGIOT SIGABRT | 114 | #define SIGIOT SIGABRT |
| 115 | #define SIGSTKFLT 7 | 115 | #define SIGEMT 7 |
| 116 | #define SIGFPE 8 | 116 | #define SIGFPE 8 |
| 117 | #define SIGKILL 9 | 117 | #define SIGKILL 9 |
| 118 | #define SIGBUS 10 | 118 | #define SIGBUS 10 |
lib/libc/musl/arch/mips64/syscall_arch.h+35-35| ... | @@ -16,26 +16,26 @@ | ... | @@ -16,26 +16,26 @@ |
| 16 | static inline long __syscall0(long n) | 16 | static inline long __syscall0(long n) |
| 17 | { | 17 | { |
| 18 | 	register long r7 __asm__("$7"); | 18 | 	register long r7 __asm__("$7"); |
| 19 | 	register long r2 __asm__("$2") = n; | 19 | 	register long r2 __asm__("$2"); |
| 20 | 	__asm__ __volatile__ ( | 20 | 	__asm__ __volatile__ ( |
| 21 | 		"syscall" | 21 | 		"daddu $2,$0,%2 ; syscall" |
| 22 | 		: "+&r"(r2), "=r"(r7) | 22 | 		: "=&r"(r2), "=r"(r7) |
| 23 | 		: | 23 | 		: "ir"(n), "0"(r2) |
| 24 | 		: SYSCALL_CLOBBERLIST); | 24 | 		: SYSCALL_CLOBBERLIST); |
| 25 | 	return r7 ? -r2 : r2; | 25 | 	return r7 && r2>0 ? -r2 : r2; |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | static inline long __syscall1(long n, long a) | 28 | static inline long __syscall1(long n, long a) |
| 29 | { | 29 | { |
| 30 | 	register long r4 __asm__("$4") = a; | 30 | 	register long r4 __asm__("$4") = a; |
| 31 | 	register long r7 __asm__("$7"); | 31 | 	register long r7 __asm__("$7"); |
| 32 | 	register long r2 __asm__("$2") = n; | 32 | 	register long r2 __asm__("$2"); |
| 33 | 	__asm__ __volatile__ ( | 33 | 	__asm__ __volatile__ ( |
| 34 | 		"syscall" | 34 | 		"daddu $2,$0,%2 ; syscall" |
| 35 | 		: "+&r"(r2), "=r"(r7) | 35 | 		: "=&r"(r2), "=r"(r7) |
| 36 | 		: "r"(r4) | 36 | 		: "ir"(n), "0"(r2), "r"(r4) |
| 37 | 		: SYSCALL_CLOBBERLIST); | 37 | 		: SYSCALL_CLOBBERLIST); |
| 38 | 	return r7 ? -r2 : r2; | 38 | 	return r7 && r2>0 ? -r2 : r2; |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | static inline long __syscall2(long n, long a, long b) | 41 | static inline long __syscall2(long n, long a, long b) |
| ... | @@ -43,14 +43,14 @@ static inline long __syscall2(long n, long a, long b) | ... | @@ -43,14 +43,14 @@ static inline long __syscall2(long n, long a, long b) |
| 43 | 	register long r4 __asm__("$4") = a; | 43 | 	register long r4 __asm__("$4") = a; |
| 44 | 	register long r5 __asm__("$5") = b; | 44 | 	register long r5 __asm__("$5") = b; |
| 45 | 	register long r7 __asm__("$7"); | 45 | 	register long r7 __asm__("$7"); |
| 46 | 	register long r2 __asm__("$2") = n; | 46 | 	register long r2 __asm__("$2"); |
| 47 | 47 | ||
| 48 | 	__asm__ __volatile__ ( | 48 | 	__asm__ __volatile__ ( |
| 49 | 		"syscall" | 49 | 		"daddu $2,$0,%2 ; syscall" |
| 50 | 		: "+&r"(r2), "=r"(r7) | 50 | 		: "=&r"(r2), "=r"(r7) |
| 51 | 		: "r"(r4), "r"(r5) | 51 | 		: "ir"(n), "0"(r2), "r"(r4), "r"(r5) |
| 52 | 		: SYSCALL_CLOBBERLIST); | 52 | 		: SYSCALL_CLOBBERLIST); |
| 53 | 	return r7 ? -r2 : r2; | 53 | 	return r7 && r2>0 ? -r2 : r2; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | static inline long __syscall3(long n, long a, long b, long c) | 56 | static inline long __syscall3(long n, long a, long b, long c) |
| ... | @@ -59,14 +59,14 @@ static inline long __syscall3(long n, long a, long b, long c) | ... | @@ -59,14 +59,14 @@ static inline long __syscall3(long n, long a, long b, long c) |
| 59 | 	register long r5 __asm__("$5") = b; | 59 | 	register long r5 __asm__("$5") = b; |
| 60 | 	register long r6 __asm__("$6") = c; | 60 | 	register long r6 __asm__("$6") = c; |
| 61 | 	register long r7 __asm__("$7"); | 61 | 	register long r7 __asm__("$7"); |
| 62 | 	register long r2 __asm__("$2") = n; | 62 | 	register long r2 __asm__("$2"); |
| 63 | 63 | ||
| 64 | 	__asm__ __volatile__ ( | 64 | 	__asm__ __volatile__ ( |
| 65 | 		"syscall" | 65 | 		"daddu $2,$0,%2 ; syscall" |
| 66 | 		: "+&r"(r2), "=r"(r7) | 66 | 		: "=&r"(r2), "=r"(r7) |
| 67 | 		: "r"(r4), "r"(r5), "r"(r6) | 67 | 		: "ir"(n), "0"(r2), "r"(r4), "r"(r5), "r"(r6) |
| 68 | 		: SYSCALL_CLOBBERLIST); | 68 | 		: SYSCALL_CLOBBERLIST); |
| 69 | 	return r7 ? -r2 : r2; | 69 | 	return r7 && r2>0 ? -r2 : r2; |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | static inline long __syscall4(long n, long a, long b, long c, long d) | 72 | static inline long __syscall4(long n, long a, long b, long c, long d) |
| ... | @@ -75,14 +75,14 @@ static inline long __syscall4(long n, long a, long b, long c, long d) | ... | @@ -75,14 +75,14 @@ static inline long __syscall4(long n, long a, long b, long c, long d) |
| 75 | 	register long r5 __asm__("$5") = b; | 75 | 	register long r5 __asm__("$5") = b; |
| 76 | 	register long r6 __asm__("$6") = c; | 76 | 	register long r6 __asm__("$6") = c; |
| 77 | 	register long r7 __asm__("$7") = d; | 77 | 	register long r7 __asm__("$7") = d; |
| 78 | 	register long r2 __asm__("$2") = n; | 78 | 	register long r2 __asm__("$2"); |
| 79 | 79 | ||
| 80 | 	__asm__ __volatile__ ( | 80 | 	__asm__ __volatile__ ( |
| 81 | 		"syscall" | 81 | 		"daddu $2,$0,%2 ; syscall" |
| 82 | 		: "+&r"(r2), "+r"(r7) | 82 | 		: "=&r"(r2), "+r"(r7) |
| 83 | 		: "r"(r4), "r"(r5), "r"(r6) | 83 | 		: "ir"(n), "0"(r2), "r"(r4), "r"(r5), "r"(r6) |
| 84 | 		: SYSCALL_CLOBBERLIST); | 84 | 		: SYSCALL_CLOBBERLIST); |
| 85 | 	return r7 ? -r2 : r2; | 85 | 	return r7 && r2>0 ? -r2 : r2; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | static inline long __syscall5(long n, long a, long b, long c, long d, long e) | 88 | static inline long __syscall5(long n, long a, long b, long c, long d, long e) |
| ... | @@ -92,14 +92,14 @@ static inline long __syscall5(long n, long a, long b, long c, long d, long e) | ... | @@ -92,14 +92,14 @@ static inline long __syscall5(long n, long a, long b, long c, long d, long e) |
| 92 | 	register long r6 __asm__("$6") = c; | 92 | 	register long r6 __asm__("$6") = c; |
| 93 | 	register long r7 __asm__("$7") = d; | 93 | 	register long r7 __asm__("$7") = d; |
| 94 | 	register long r8 __asm__("$8") = e; | 94 | 	register long r8 __asm__("$8") = e; |
| 95 | 	register long r2 __asm__("$2") = n; | 95 | 	register long r2 __asm__("$2"); |
| 96 | 96 | ||
| 97 | 	__asm__ __volatile__ ( | 97 | 	__asm__ __volatile__ ( |
| 98 | 		"syscall" | 98 | 		"daddu $2,$0,%2 ; syscall" |
| 99 | 		: "+&r"(r2), "+r"(r7) | 99 | 		: "=&r"(r2), "+r"(r7) |
| 100 | 		: "r"(r4), "r"(r5), "r"(r6), "r"(r8) | 100 | 		: "ir"(n), "0"(r2), "r"(r4), "r"(r5), "r"(r6), "r"(r8) |
| 101 | 		: SYSCALL_CLOBBERLIST); | 101 | 		: SYSCALL_CLOBBERLIST); |
| 102 | 	return r7 ? -r2 : r2; | 102 | 	return r7 && r2>0 ? -r2 : r2; |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | static inline long __syscall6(long n, long a, long b, long c, long d, long e, long f) | 105 | static inline long __syscall6(long n, long a, long b, long c, long d, long e, long f) |
| ... | @@ -110,14 +110,14 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo | ... | @@ -110,14 +110,14 @@ static inline long __syscall6(long n, long a, long b, long c, long d, long e, lo |
| 110 | 	register long r7 __asm__("$7") = d; | 110 | 	register long r7 __asm__("$7") = d; |
| 111 | 	register long r8 __asm__("$8") = e; | 111 | 	register long r8 __asm__("$8") = e; |
| 112 | 	register long r9 __asm__("$9") = f; | 112 | 	register long r9 __asm__("$9") = f; |
| 113 | 	register long r2 __asm__("$2") = n; | 113 | 	register long r2 __asm__("$2"); |
| 114 | 114 | ||
| 115 | 	__asm__ __volatile__ ( | 115 | 	__asm__ __volatile__ ( |
| 116 | 		"syscall" | 116 | 		"daddu $2,$0,%2 ; syscall" |
| 117 | 		: "+&r"(r2), "+r"(r7) | 117 | 		: "=&r"(r2), "+r"(r7) |
| 118 | 		: "r"(r4), "r"(r5), "r"(r6), "r"(r8), "r"(r9) | 118 | 		: "ir"(n), "0"(r2), "r"(r4), "r"(r5), "r"(r6), "r"(r8), "r"(r9) |
| 119 | 		: SYSCALL_CLOBBERLIST); | 119 | 		: SYSCALL_CLOBBERLIST); |
| 120 | 	return r7 ? -r2 : r2; | 120 | 	return r7 && r2>0 ? -r2 : r2; |
| 121 | } | 121 | } |
| 122 | 122 | ||
| 123 | #define VDSO_USEFUL | 123 | #define VDSO_USEFUL |
lib/libc/musl/arch/powerpc/bits/mman.h-1| ... | @@ -4,7 +4,6 @@ | ... | @@ -4,7 +4,6 @@ |
| 4 | #define MAP_NORESERVE 0x40 | 4 | #define MAP_NORESERVE 0x40 |
| 5 | #undef MAP_LOCKED | 5 | #undef MAP_LOCKED |
| 6 | #define MAP_LOCKED	0x80 | 6 | #define MAP_LOCKED	0x80 |
| 7 | #undef MAP_SYNC | ||
| 8 | 7 | ||
| 9 | #undef MCL_CURRENT | 8 | #undef MCL_CURRENT |
| 10 | #define MCL_CURRENT 0x2000 | 9 | #define MCL_CURRENT 0x2000 |
lib/libc/musl/arch/powerpc64/bits/mman.h-1| ... | @@ -4,7 +4,6 @@ | ... | @@ -4,7 +4,6 @@ |
| 4 | #define MAP_NORESERVE 0x40 | 4 | #define MAP_NORESERVE 0x40 |
| 5 | #undef MAP_LOCKED | 5 | #undef MAP_LOCKED |
| 6 | #define MAP_LOCKED	0x80 | 6 | #define MAP_LOCKED	0x80 |
| 7 | #undef MAP_SYNC | ||
| 8 | 7 | ||
| 9 | #undef MCL_CURRENT | 8 | #undef MCL_CURRENT |
| 10 | #define MCL_CURRENT 0x2000 | 9 | #define MCL_CURRENT 0x2000 |
lib/libc/musl/include/arpa/inet.h-5| ... | @@ -24,11 +24,6 @@ struct in_addr inet_makeaddr(in_addr_t, in_addr_t); | ... | @@ -24,11 +24,6 @@ struct in_addr inet_makeaddr(in_addr_t, in_addr_t); |
| 24 | in_addr_t inet_lnaof(struct in_addr); | 24 | in_addr_t inet_lnaof(struct in_addr); |
| 25 | in_addr_t inet_netof(struct in_addr); | 25 | in_addr_t inet_netof(struct in_addr); |
| 26 | 26 | ||
| 27 | #undef INET_ADDRSTRLEN | ||
| 28 | #undef INET6_ADDRSTRLEN | ||
| 29 | #define INET_ADDRSTRLEN 16 | ||
| 30 | #define INET6_ADDRSTRLEN 46 | ||
| 31 | |||
| 32 | #ifdef __cplusplus | 27 | #ifdef __cplusplus |
| 33 | } | 28 | } |
| 34 | #endif | 29 | #endif |
lib/libc/musl/include/netinet/in.h-2| ... | @@ -60,8 +60,6 @@ struct ipv6_mreq { | ... | @@ -60,8 +60,6 @@ struct ipv6_mreq { |
| 60 | 60 | ||
| 61 | extern const struct in6_addr in6addr_any, in6addr_loopback; | 61 | extern const struct in6_addr in6addr_any, in6addr_loopback; |
| 62 | 62 | ||
| 63 | #undef INET_ADDRSTRLEN | ||
| 64 | #undef INET6_ADDRSTRLEN | ||
| 65 | #define INET_ADDRSTRLEN 16 | 63 | #define INET_ADDRSTRLEN 16 |
| 66 | #define INET6_ADDRSTRLEN 46 | 64 | #define INET6_ADDRSTRLEN 46 |
| 67 | 65 |
lib/libc/musl/include/pthread.h+3| ... | @@ -74,6 +74,9 @@ extern "C" { | ... | @@ -74,6 +74,9 @@ extern "C" { |
| 74 | #define PTHREAD_BARRIER_SERIAL_THREAD (-1) | 74 | #define PTHREAD_BARRIER_SERIAL_THREAD (-1) |
| 75 | 75 | ||
| 76 | 76 | ||
| 77 | #define PTHREAD_NULL ((pthread_t)0) | ||
| 78 | |||
| 79 | |||
| 77 | int pthread_create(pthread_t *__restrict, const pthread_attr_t *__restrict, void *(*)(void *), void *__restrict); | 80 | int pthread_create(pthread_t *__restrict, const pthread_attr_t *__restrict, void *(*)(void *), void *__restrict); |
| 78 | int pthread_detach(pthread_t); | 81 | int pthread_detach(pthread_t); |
| 79 | _Noreturn void pthread_exit(void *); | 82 | _Noreturn void pthread_exit(void *); |
lib/libc/musl/src/errno/__strerror.h+6-7| ... | @@ -1,8 +1,9 @@ | ... | @@ -1,8 +1,9 @@ |
| 1 | /* This file is sorted such that 'errors' which represent exceptional | 1 | /* The first entry is a catch-all for codes not enumerated here. |
| 2 | * conditions under which a correct program may fail come first, followed | 2 | * This file is included multiple times to declare and define a structure |
| 3 | * by messages that indicate an incorrect program or system failure. The | 3 | * with these messages, and then to define a lookup table translating |
| 4 | * macro E() along with double-inclusion is used to ensure that ordering | 4 | * error codes to offsets of corresponding fields in the structure. */ |
| 5 | * of the strings remains synchronized. */ | 5 | |
| 6 | E(0, "No error information") | ||
| 6 | 7 | ||
| 7 | E(EILSEQ, "Illegal byte sequence") | 8 | E(EILSEQ, "Illegal byte sequence") |
| 8 | E(EDOM, "Domain error") | 9 | E(EDOM, "Domain error") |
| ... | @@ -101,5 +102,3 @@ E(EDQUOT, "Quota exceeded") | ... | @@ -101,5 +102,3 @@ E(EDQUOT, "Quota exceeded") |
| 101 | E(ENOMEDIUM, "No medium found") | 102 | E(ENOMEDIUM, "No medium found") |
| 102 | E(EMEDIUMTYPE, "Wrong medium type") | 103 | E(EMEDIUMTYPE, "Wrong medium type") |
| 103 | E(EMULTIHOP, "Multihop attempted") | 104 | E(EMULTIHOP, "Multihop attempted") |
| 104 | |||
| 105 | E(0, "No error information") |
lib/libc/musl/src/errno/strerror.c+26-15| ... | @@ -1,30 +1,41 @@ | ... | @@ -1,30 +1,41 @@ |
| 1 | #include <errno.h> | 1 | #include <errno.h> |
| 2 | #include <stddef.h> | ||
| 2 | #include <string.h> | 3 | #include <string.h> |
| 3 | #include "locale_impl.h" | 4 | #include "locale_impl.h" |
| 4 | 5 | ||
| 5 | #define E(a,b) ((unsigned char)a), | 6 | /* mips has one error code outside of the 8-bit range due to a |
| 6 | static const unsigned char errid[] = { | 7 | * historical typo, so we just remap it. */ |
| 8 | #if EDQUOT==1133 | ||
| 9 | #define EDQUOT_ORIG 1133 | ||
| 10 | #undef EDQUOT | ||
| 11 | #define EDQUOT 109 | ||
| 12 | #endif | ||
| 13 | |||
| 14 | static const struct errmsgstr_t { | ||
| 15 | #define E(n, s) char str##n[sizeof(s)]; | ||
| 16 | #include "__strerror.h" | ||
| 17 | #undef E | ||
| 18 | } errmsgstr = { | ||
| 19 | #define E(n, s) s, | ||
| 7 | #include "__strerror.h" | 20 | #include "__strerror.h" |
| 21 | #undef E | ||
| 8 | }; | 22 | }; |
| 9 | 23 | ||
| 10 | #undef E | 24 | static const unsigned short errmsgidx[] = { |
| 11 | #define E(a,b) b "\0" | 25 | #define E(n, s) [n] = offsetof(struct errmsgstr_t, str##n), |
| 12 | static const char errmsg[] = | ||
| 13 | #include "__strerror.h" | 26 | #include "__strerror.h" |
| 14 | ; | 27 | #undef E |
| 28 | }; | ||
| 15 | 29 | ||
| 16 | char *__strerror_l(int e, locale_t loc) | 30 | char *__strerror_l(int e, locale_t loc) |
| 17 | { | 31 | { |
| 18 | 	const char *s; | 32 | 	const char *s; |
| 19 | 	int i; | 33 | #ifdef EDQUOT_ORIG |
| 20 | 	/* mips has one error code outside of the 8-bit range due to a | 34 | 	if (e==EDQUOT) e=0; |
| 21 | 	 * historical typo, so we just remap it. */ | 35 | 	else if (e==EDQUOT_ORIG) e=EDQUOT; |
| 22 | 	if (EDQUOT==1133) { | 36 | #endif |
| 23 | 		if (e==109) e=-1; | 37 | 	if (e >= sizeof errmsgidx / sizeof *errmsgidx) e = 0; |
| 24 | 		else if (e==EDQUOT) e=109; | 38 | 	s = (char *)&errmsgstr + errmsgidx[e]; |
| 25 | 	} | ||
| 26 | 	for (i=0; errid[i] && errid[i] != e; i++); | ||
| 27 | 	for (s=errmsg; i; s++, i--) for (; *s; s++); | ||
| 28 | 	return (char *)LCTRANS(s, LC_MESSAGES, loc); | 39 | 	return (char *)LCTRANS(s, LC_MESSAGES, loc); |
| 29 | } | 40 | } |
| 30 | 41 |
lib/libc/musl/src/fenv/sh/fenv.S+2| ... | @@ -12,6 +12,8 @@ fegetround: | ... | @@ -12,6 +12,8 @@ fegetround: |
| 12 | .type __fesetround, @function | 12 | .type __fesetround, @function |
| 13 | __fesetround: | 13 | __fesetround: |
| 14 | 	sts fpscr, r0 | 14 | 	sts fpscr, r0 |
| 15 | 	mov #-4, r1 | ||
| 16 | 	and r1, r0 | ||
| 15 | 	or r4, r0 | 17 | 	or r4, r0 |
| 16 | 	lds r0, fpscr | 18 | 	lds r0, fpscr |
| 17 | 	rts | 19 | 	rts |
lib/libc/musl/src/internal/atomic.h+15| ... | @@ -315,4 +315,19 @@ static inline int a_clz_64(uint64_t x) | ... | @@ -315,4 +315,19 @@ static inline int a_clz_64(uint64_t x) |
| 315 | } | 315 | } |
| 316 | #endif | 316 | #endif |
| 317 | 317 | ||
| 318 | #ifndef a_clz_32 | ||
| 319 | #define a_clz_32 a_clz_32 | ||
| 320 | static inline int a_clz_32(uint32_t x) | ||
| 321 | { | ||
| 322 | 	x >>= 1; | ||
| 323 | 	x |= x >> 1; | ||
| 324 | 	x |= x >> 2; | ||
| 325 | 	x |= x >> 4; | ||
| 326 | 	x |= x >> 8; | ||
| 327 | 	x |= x >> 16; | ||
| 328 | 	x++; | ||
| 329 | 	return 31-a_ctz_32(x); | ||
| 330 | } | ||
| 331 | #endif | ||
| 332 | |||
| 318 | #endif | 333 | #endif |
lib/libc/musl/src/internal/dynlink.h+5| ... | @@ -105,4 +105,9 @@ hidden void __dl_vseterr(const char *, va_list); | ... | @@ -105,4 +105,9 @@ hidden void __dl_vseterr(const char *, va_list); |
| 105 | 105 | ||
| 106 | hidden ptrdiff_t __tlsdesc_static(), __tlsdesc_dynamic(); | 106 | hidden ptrdiff_t __tlsdesc_static(), __tlsdesc_dynamic(); |
| 107 | 107 | ||
| 108 | hidden extern int __malloc_replaced; | ||
| 109 | hidden extern int __aligned_alloc_replaced; | ||
| 110 | hidden void __malloc_donate(char *, char *); | ||
| 111 | hidden int __malloc_allzerop(void *); | ||
| 112 | |||
| 108 | #endif | 113 | #endif |
lib/libc/musl/src/internal/libc.h+5-4| ... | @@ -18,10 +18,11 @@ struct tls_module { | ... | @@ -18,10 +18,11 @@ struct tls_module { |
| 18 | }; | 18 | }; |
| 19 | 19 | ||
| 20 | struct __libc { | 20 | struct __libc { |
| 21 | 	int can_do_threads; | 21 | 	char can_do_threads; |
| 22 | 	int threaded; | 22 | 	char threaded; |
| 23 | 	int secure; | 23 | 	char secure; |
| 24 | 	volatile int threads_minus_1; | 24 | 	volatile signed char need_locks; |
| 25 | 	int threads_minus_1; | ||
| 25 | 	size_t *auxv; | 26 | 	size_t *auxv; |
| 26 | 	struct tls_module *tls_head; | 27 | 	struct tls_module *tls_head; |
| 27 | 	size_t tls_size, tls_align, tls_cnt; | 28 | 	size_t tls_size, tls_align, tls_cnt; |
lib/libc/musl/src/internal/libm.h+2-2| ... | @@ -236,13 +236,13 @@ hidden int __rem_pio2(double,double*); | ... | @@ -236,13 +236,13 @@ hidden int __rem_pio2(double,double*); |
| 236 | hidden double __sin(double,double,int); | 236 | hidden double __sin(double,double,int); |
| 237 | hidden double __cos(double,double); | 237 | hidden double __cos(double,double); |
| 238 | hidden double __tan(double,double,int); | 238 | hidden double __tan(double,double,int); |
| 239 | hidden double __expo2(double); | 239 | hidden double __expo2(double,double); |
| 240 | 240 | ||
| 241 | hidden int __rem_pio2f(float,double*); | 241 | hidden int __rem_pio2f(float,double*); |
| 242 | hidden float __sindf(double); | 242 | hidden float __sindf(double); |
| 243 | hidden float __cosdf(double); | 243 | hidden float __cosdf(double); |
| 244 | hidden float __tandf(double,int); | 244 | hidden float __tandf(double,int); |
| 245 | hidden float __expo2f(float); | 245 | hidden float __expo2f(float,float); |
| 246 | 246 | ||
| 247 | hidden int __rem_pio2l(long double, long double *); | 247 | hidden int __rem_pio2l(long double, long double *); |
| 248 | hidden long double __sinl(long double, long double, int); | 248 | hidden long double __sinl(long double, long double, int); |
lib/libc/musl/src/internal/malloc_impl.h deleted-46| ... | @@ -1,46 +0,0 @@ | ||
| 1 | #ifndef MALLOC_IMPL_H | ||
| 2 | #define MALLOC_IMPL_H | ||
| 3 | |||
| 4 | #include <sys/mman.h> | ||
| 5 | |||
| 6 | hidden void *__expand_heap(size_t *); | ||
| 7 | |||
| 8 | hidden void __malloc_donate(char *, char *); | ||
| 9 | |||
| 10 | hidden void *__memalign(size_t, size_t); | ||
| 11 | |||
| 12 | struct chunk { | ||
| 13 | 	size_t psize, csize; | ||
| 14 | 	struct chunk *next, *prev; | ||
| 15 | }; | ||
| 16 | |||
| 17 | struct bin { | ||
| 18 | 	volatile int lock[2]; | ||
| 19 | 	struct chunk *head; | ||
| 20 | 	struct chunk *tail; | ||
| 21 | }; | ||
| 22 | |||
| 23 | #define SIZE_ALIGN (4*sizeof(size_t)) | ||
| 24 | #define SIZE_MASK (-SIZE_ALIGN) | ||
| 25 | #define OVERHEAD (2*sizeof(size_t)) | ||
| 26 | #define MMAP_THRESHOLD (0x1c00*SIZE_ALIGN) | ||
| 27 | #define DONTCARE 16 | ||
| 28 | #define RECLAIM 163840 | ||
| 29 | |||
| 30 | #define CHUNK_SIZE(c) ((c)->csize & -2) | ||
| 31 | #define CHUNK_PSIZE(c) ((c)->psize & -2) | ||
| 32 | #define PREV_CHUNK(c) ((struct chunk *)((char *)(c) - CHUNK_PSIZE(c))) | ||
| 33 | #define NEXT_CHUNK(c) ((struct chunk *)((char *)(c) + CHUNK_SIZE(c))) | ||
| 34 | #define MEM_TO_CHUNK(p) (struct chunk *)((char *)(p) - OVERHEAD) | ||
| 35 | #define CHUNK_TO_MEM(c) (void *)((char *)(c) + OVERHEAD) | ||
| 36 | #define BIN_TO_CHUNK(i) (MEM_TO_CHUNK(&mal.bins[i].head)) | ||
| 37 | |||
| 38 | #define C_INUSE ((size_t)1) | ||
| 39 | |||
| 40 | #define IS_MMAPPED(c) !((c)->csize & (C_INUSE)) | ||
| 41 | |||
| 42 | hidden void __bin_chunk(struct chunk *); | ||
| 43 | |||
| 44 | hidden extern int __malloc_replaced; | ||
| 45 | |||
| 46 | #endif | ||
lib/libc/musl/src/internal/shgetc.c+1-1| ... | @@ -32,6 +32,6 @@ int __shgetc(FILE *f) | ... | @@ -32,6 +32,6 @@ int __shgetc(FILE *f) |
| 32 | 	else | 32 | 	else |
| 33 | 		f->shend = f->rend; | 33 | 		f->shend = f->rend; |
| 34 | 	f->shcnt = f->buf - f->rpos + cnt; | 34 | 	f->shcnt = f->buf - f->rpos + cnt; |
| 35 | 	if (f->rpos[-1] != c) f->rpos[-1] = c; | 35 | 	if (f->rpos <= f->buf) f->rpos[-1] = c; |
| 36 | 	return c; | 36 | 	return c; |
| 37 | } | 37 | } |
lib/libc/musl/src/internal/stdio_impl.h-2| ... | @@ -60,8 +60,6 @@ hidden size_t __stdout_write(FILE *, const unsigned char *, size_t); | ... | @@ -60,8 +60,6 @@ hidden size_t __stdout_write(FILE *, const unsigned char *, size_t); |
| 60 | hidden off_t __stdio_seek(FILE *, off_t, int); | 60 | hidden off_t __stdio_seek(FILE *, off_t, int); |
| 61 | hidden int __stdio_close(FILE *); | 61 | hidden int __stdio_close(FILE *); |
| 62 | 62 | ||
| 63 | hidden size_t __string_read(FILE *, unsigned char *, size_t); | ||
| 64 | |||
| 65 | hidden int __toread(FILE *); | 63 | hidden int __toread(FILE *); |
| 66 | hidden int __towrite(FILE *); | 64 | hidden int __towrite(FILE *); |
| 67 | 65 |
lib/libc/musl/src/internal/version.h+1-1| ... | @@ -1 +1 @@ | ... | @@ -1 +1 @@ |
| 1 | #define VERSION "1.2.0" | 1 | #define VERSION "1.2.1" |
lib/libc/musl/src/ipc/msgctl.c+10| ... | @@ -9,6 +9,14 @@ | ... | @@ -9,6 +9,14 @@ |
| 9 | 9 | ||
| 10 | int msgctl(int q, int cmd, struct msqid_ds *buf) | 10 | int msgctl(int q, int cmd, struct msqid_ds *buf) |
| 11 | { | 11 | { |
| 12 | #if IPC_TIME64 | ||
| 13 | 	struct msqid_ds out, *orig; | ||
| 14 | 	if (cmd&IPC_TIME64) { | ||
| 15 | 		out = (struct msqid_ds){0}; | ||
| 16 | 		orig = buf; | ||
| 17 | 		buf = &out; | ||
| 18 | 	} | ||
| 19 | #endif | ||
| 12 | #ifdef SYSCALL_IPC_BROKEN_MODE | 20 | #ifdef SYSCALL_IPC_BROKEN_MODE |
| 13 | 	struct msqid_ds tmp; | 21 | 	struct msqid_ds tmp; |
| 14 | 	if (cmd == IPC_SET) { | 22 | 	if (cmd == IPC_SET) { |
| ... | @@ -32,6 +40,8 @@ int msgctl(int q, int cmd, struct msqid_ds *buf) | ... | @@ -32,6 +40,8 @@ int msgctl(int q, int cmd, struct msqid_ds *buf) |
| 32 | #endif | 40 | #endif |
| 33 | #if IPC_TIME64 | 41 | #if IPC_TIME64 |
| 34 | 	if (r >= 0 && (cmd&IPC_TIME64)) { | 42 | 	if (r >= 0 && (cmd&IPC_TIME64)) { |
| 43 | 		buf = orig; | ||
| 44 | 		*buf = out; | ||
| 35 | 		IPC_HILO(buf, msg_stime); | 45 | 		IPC_HILO(buf, msg_stime); |
| 36 | 		IPC_HILO(buf, msg_rtime); | 46 | 		IPC_HILO(buf, msg_rtime); |
| 37 | 		IPC_HILO(buf, msg_ctime); | 47 | 		IPC_HILO(buf, msg_ctime); |
lib/libc/musl/src/ipc/semctl.c+10| ... | @@ -28,6 +28,14 @@ int semctl(int id, int num, int cmd, ...) | ... | @@ -28,6 +28,14 @@ int semctl(int id, int num, int cmd, ...) |
| 28 | 		arg = va_arg(ap, union semun); | 28 | 		arg = va_arg(ap, union semun); |
| 29 | 		va_end(ap); | 29 | 		va_end(ap); |
| 30 | 	} | 30 | 	} |
| 31 | #if IPC_TIME64 | ||
| 32 | 	struct semid_ds out, *orig; | ||
| 33 | 	if (cmd&IPC_TIME64) { | ||
| 34 | 		out = (struct semid_ds){0}; | ||
| 35 | 		orig = arg.buf; | ||
| 36 | 		arg.buf = &out; | ||
| 37 | 	} | ||
| 38 | #endif | ||
| 31 | #ifdef SYSCALL_IPC_BROKEN_MODE | 39 | #ifdef SYSCALL_IPC_BROKEN_MODE |
| 32 | 	struct semid_ds tmp; | 40 | 	struct semid_ds tmp; |
| 33 | 	if (cmd == IPC_SET) { | 41 | 	if (cmd == IPC_SET) { |
| ... | @@ -51,6 +59,8 @@ int semctl(int id, int num, int cmd, ...) | ... | @@ -51,6 +59,8 @@ int semctl(int id, int num, int cmd, ...) |
| 51 | #endif | 59 | #endif |
| 52 | #if IPC_TIME64 | 60 | #if IPC_TIME64 |
| 53 | 	if (r >= 0 && (cmd&IPC_TIME64)) { | 61 | 	if (r >= 0 && (cmd&IPC_TIME64)) { |
| 62 | 		arg.buf = orig; | ||
| 63 | 		*arg.buf = out; | ||
| 54 | 		IPC_HILO(arg.buf, sem_otime); | 64 | 		IPC_HILO(arg.buf, sem_otime); |
| 55 | 		IPC_HILO(arg.buf, sem_ctime); | 65 | 		IPC_HILO(arg.buf, sem_ctime); |
| 56 | 	} | 66 | 	} |
lib/libc/musl/src/ipc/shmctl.c+10| ... | @@ -9,6 +9,14 @@ | ... | @@ -9,6 +9,14 @@ |
| 9 | 9 | ||
| 10 | int shmctl(int id, int cmd, struct shmid_ds *buf) | 10 | int shmctl(int id, int cmd, struct shmid_ds *buf) |
| 11 | { | 11 | { |
| 12 | #if IPC_TIME64 | ||
| 13 | 	struct shmid_ds out, *orig; | ||
| 14 | 	if (cmd&IPC_TIME64) { | ||
| 15 | 		out = (struct shmid_ds){0}; | ||
| 16 | 		orig = buf; | ||
| 17 | 		buf = &out; | ||
| 18 | 	} | ||
| 19 | #endif | ||
| 12 | #ifdef SYSCALL_IPC_BROKEN_MODE | 20 | #ifdef SYSCALL_IPC_BROKEN_MODE |
| 13 | 	struct shmid_ds tmp; | 21 | 	struct shmid_ds tmp; |
| 14 | 	if (cmd == IPC_SET) { | 22 | 	if (cmd == IPC_SET) { |
| ... | @@ -32,6 +40,8 @@ int shmctl(int id, int cmd, struct shmid_ds *buf) | ... | @@ -32,6 +40,8 @@ int shmctl(int id, int cmd, struct shmid_ds *buf) |
| 32 | #endif | 40 | #endif |
| 33 | #if IPC_TIME64 | 41 | #if IPC_TIME64 |
| 34 | 	if (r >= 0 && (cmd&IPC_TIME64)) { | 42 | 	if (r >= 0 && (cmd&IPC_TIME64)) { |
| 43 | 		buf = orig; | ||
| 44 | 		*buf = out; | ||
| 35 | 		IPC_HILO(buf, shm_atime); | 45 | 		IPC_HILO(buf, shm_atime); |
| 36 | 		IPC_HILO(buf, shm_dtime); | 46 | 		IPC_HILO(buf, shm_dtime); |
| 37 | 		IPC_HILO(buf, shm_ctime); | 47 | 		IPC_HILO(buf, shm_ctime); |
lib/libc/musl/src/linux/clock_adjtime.c+46-49| ... | @@ -38,55 +38,52 @@ int clock_adjtime (clockid_t clock_id, struct timex *utx) | ... | @@ -38,55 +38,52 @@ int clock_adjtime (clockid_t clock_id, struct timex *utx) |
| 38 | { | 38 | { |
| 39 | 	int r = -ENOSYS; | 39 | 	int r = -ENOSYS; |
| 40 | #ifdef SYS_clock_adjtime64 | 40 | #ifdef SYS_clock_adjtime64 |
| 41 | 	if (SYS_clock_adjtime == SYS_clock_adjtime64 || | 41 | 	struct ktimex64 ktx = { |
| 42 | 	 (utx->modes & ADJ_SETOFFSET) && !IS32BIT(utx->time.tv_sec)) { | 42 | 		.modes = utx->modes, |
| 43 | 		struct ktimex64 ktx = { | 43 | 		.offset = utx->offset, |
| 44 | 			.modes = utx->modes, | 44 | 		.freq = utx->freq, |
| 45 | 			.offset = utx->offset, | 45 | 		.maxerror = utx->maxerror, |
| 46 | 			.freq = utx->freq, | 46 | 		.esterror = utx->esterror, |
| 47 | 			.maxerror = utx->maxerror, | 47 | 		.status = utx->status, |
| 48 | 			.esterror = utx->esterror, | 48 | 		.constant = utx->constant, |
| 49 | 			.status = utx->status, | 49 | 		.precision = utx->precision, |
| 50 | 			.constant = utx->constant, | 50 | 		.tolerance = utx->tolerance, |
| 51 | 			.precision = utx->precision, | 51 | 		.time_sec = utx->time.tv_sec, |
| 52 | 			.tolerance = utx->tolerance, | 52 | 		.time_usec = utx->time.tv_usec, |
| 53 | 			.time_sec = utx->time.tv_sec, | 53 | 		.tick = utx->tick, |
| 54 | 			.time_usec = utx->time.tv_usec, | 54 | 		.ppsfreq = utx->ppsfreq, |
| 55 | 			.tick = utx->tick, | 55 | 		.jitter = utx->jitter, |
| 56 | 			.ppsfreq = utx->ppsfreq, | 56 | 		.shift = utx->shift, |
| 57 | 			.jitter = utx->jitter, | 57 | 		.stabil = utx->stabil, |
| 58 | 			.shift = utx->shift, | 58 | 		.jitcnt = utx->jitcnt, |
| 59 | 			.stabil = utx->stabil, | 59 | 		.calcnt = utx->calcnt, |
| 60 | 			.jitcnt = utx->jitcnt, | 60 | 		.errcnt = utx->errcnt, |
| 61 | 			.calcnt = utx->calcnt, | 61 | 		.stbcnt = utx->stbcnt, |
| 62 | 			.errcnt = utx->errcnt, | 62 | 		.tai = utx->tai, |
| 63 | 			.stbcnt = utx->stbcnt, | 63 | 	}; |
| 64 | 			.tai = utx->tai, | 64 | 	r = __syscall(SYS_clock_adjtime64, clock_id, &ktx); |
| 65 | 		}; | 65 | 	if (r>=0) { |
| 66 | 		r = __syscall(SYS_clock_adjtime, clock_id, &ktx); | 66 | 		utx->modes = ktx.modes; |
| 67 | 		if (r>=0) { | 67 | 		utx->offset = ktx.offset; |
| 68 | 			utx->modes = ktx.modes; | 68 | 		utx->freq = ktx.freq; |
| 69 | 			utx->offset = ktx.offset; | 69 | 		utx->maxerror = ktx.maxerror; |
| 70 | 			utx->freq = ktx.freq; | 70 | 		utx->esterror = ktx.esterror; |
| 71 | 			utx->maxerror = ktx.maxerror; | 71 | 		utx->status = ktx.status; |
| 72 | 			utx->esterror = ktx.esterror; | 72 | 		utx->constant = ktx.constant; |
| 73 | 			utx->status = ktx.status; | 73 | 		utx->precision = ktx.precision; |
| 74 | 			utx->constant = ktx.constant; | 74 | 		utx->tolerance = ktx.tolerance; |
| 75 | 			utx->precision = ktx.precision; | 75 | 		utx->time.tv_sec = ktx.time_sec; |
| 76 | 			utx->tolerance = ktx.tolerance; | 76 | 		utx->time.tv_usec = ktx.time_usec; |
| 77 | 			utx->time.tv_sec = ktx.time_sec; | 77 | 		utx->tick = ktx.tick; |
| 78 | 			utx->time.tv_usec = ktx.time_usec; | 78 | 		utx->ppsfreq = ktx.ppsfreq; |
| 79 | 			utx->tick = ktx.tick; | 79 | 		utx->jitter = ktx.jitter; |
| 80 | 			utx->ppsfreq = ktx.ppsfreq; | 80 | 		utx->shift = ktx.shift; |
| 81 | 			utx->jitter = ktx.jitter; | 81 | 		utx->stabil = ktx.stabil; |
| 82 | 			utx->shift = ktx.shift; | 82 | 		utx->jitcnt = ktx.jitcnt; |
| 83 | 			utx->stabil = ktx.stabil; | 83 | 		utx->calcnt = ktx.calcnt; |
| 84 | 			utx->jitcnt = ktx.jitcnt; | 84 | 		utx->errcnt = ktx.errcnt; |
| 85 | 			utx->calcnt = ktx.calcnt; | 85 | 		utx->stbcnt = ktx.stbcnt; |
| 86 | 			utx->errcnt = ktx.errcnt; | 86 | 		utx->tai = ktx.tai; |
| 87 | 			utx->stbcnt = ktx.stbcnt; | ||
| 88 | 			utx->tai = ktx.tai; | ||
| 89 | 		} | ||
| 90 | 	} | 87 | 	} |
| 91 | 	if (SYS_clock_adjtime == SYS_clock_adjtime64 || r!=-ENOSYS) | 88 | 	if (SYS_clock_adjtime == SYS_clock_adjtime64 || r!=-ENOSYS) |
| 92 | 		return __syscall_ret(r); | 89 | 		return __syscall_ret(r); |
lib/libc/musl/src/malloc/DESIGN deleted-22| ... | @@ -1,22 +0,0 @@ | ||
| 1 | |||
| 2 | |||
| 3 | In principle, this memory allocator is roughly equivalent to Doug | ||
| 4 | Lea's dlmalloc with fine-grained locking. | ||
| 5 | |||
| 6 | |||
| 7 | |||
| 8 | malloc: | ||
| 9 | |||
| 10 | Uses a freelist binned by chunk size, with a bitmap to optimize | ||
| 11 | searching for the smallest non-empty bin which can satisfy an | ||
| 12 | allocation. If no free chunks are available, it creates a new chunk of | ||
| 13 | the requested size and attempts to merge it with any existing free | ||
| 14 | chunk immediately below the newly created chunk. | ||
| 15 | |||
| 16 | Whether the chunk was obtained from a bin or newly created, it's | ||
| 17 | likely to be larger than the requested allocation. malloc always | ||
| 18 | finishes its work by passing the new chunk to realloc, which will | ||
| 19 | split it into two chunks and free the tail portion. | ||
| 20 | |||
| 21 | |||
| 22 | |||
lib/libc/musl/src/malloc/aligned_alloc.c deleted-7| ... | @@ -1,7 +0,0 @@ | ||
| 1 | #include <stdlib.h> | ||
| 2 | #include "malloc_impl.h" | ||
| 3 | |||
| 4 | void *aligned_alloc(size_t align, size_t len) | ||
| 5 | { | ||
| 6 | 	return __memalign(align, len); | ||
| 7 | } | ||
lib/libc/musl/src/malloc/calloc.c created+45| ... | @@ -0,0 +1,45 @@ | ||
| 1 | #include <stdlib.h> | ||
| 2 | #include <stdint.h> | ||
| 3 | #include <string.h> | ||
| 4 | #include <errno.h> | ||
| 5 | #include "dynlink.h" | ||
| 6 | |||
| 7 | static size_t mal0_clear(char *p, size_t n) | ||
| 8 | { | ||
| 9 | 	const size_t pagesz = 4096; /* arbitrary */ | ||
| 10 | 	if (n < pagesz) return n; | ||
| 11 | #ifdef __GNUC__ | ||
| 12 | 	typedef uint64_t __attribute__((__may_alias__)) T; | ||
| 13 | #else | ||
| 14 | 	typedef unsigned char T; | ||
| 15 | #endif | ||
| 16 | 	char *pp = p + n; | ||
| 17 | 	size_t i = (uintptr_t)pp & (pagesz - 1); | ||
| 18 | 	for (;;) { | ||
| 19 | 		pp = memset(pp - i, 0, i); | ||
| 20 | 		if (pp - p < pagesz) return pp - p; | ||
| 21 | 		for (i = pagesz; i; i -= 2*sizeof(T), pp -= 2*sizeof(T)) | ||
| 22 | 		 if (((T *)pp)[-1] | ((T *)pp)[-2]) | ||
| 23 | 				break; | ||
| 24 | 	} | ||
| 25 | } | ||
| 26 | |||
| 27 | static int allzerop(void *p) | ||
| 28 | { | ||
| 29 | 	return 0; | ||
| 30 | } | ||
| 31 | weak_alias(allzerop, __malloc_allzerop); | ||
| 32 | |||
| 33 | void *calloc(size_t m, size_t n) | ||
| 34 | { | ||
| 35 | 	if (n && m > (size_t)-1/n) { | ||
| 36 | 		errno = ENOMEM; | ||
| 37 | 		return 0; | ||
| 38 | 	} | ||
| 39 | 	n *= m; | ||
| 40 | 	void *p = malloc(n); | ||
| 41 | 	if (!p || (!__malloc_replaced && __malloc_allzerop(p))) | ||
| 42 | 		return p; | ||
| 43 | 	n = mal0_clear(p, n); | ||
| 44 | 	return memset(p, 0, n); | ||
| 45 | } | ||
lib/libc/musl/src/malloc/expand_heap.c deleted-71| ... | @@ -1,71 +0,0 @@ | ||
| 1 | #include <limits.h> | ||
| 2 | #include <stdint.h> | ||
| 3 | #include <errno.h> | ||
| 4 | #include <sys/mman.h> | ||
| 5 | #include "libc.h" | ||
| 6 | #include "syscall.h" | ||
| 7 | #include "malloc_impl.h" | ||
| 8 | |||
| 9 | /* This function returns true if the interval [old,new] | ||
| 10 | * intersects the 'len'-sized interval below &libc.auxv | ||
| 11 | * (interpreted as the main-thread stack) or below &b | ||
| 12 | * (the current stack). It is used to defend against | ||
| 13 | * buggy brk implementations that can cross the stack. */ | ||
| 14 | |||
| 15 | static int traverses_stack_p(uintptr_t old, uintptr_t new) | ||
| 16 | { | ||
| 17 | 	const uintptr_t len = 8<<20; | ||
| 18 | 	uintptr_t a, b; | ||
| 19 | |||
| 20 | 	b = (uintptr_t)libc.auxv; | ||
| 21 | 	a = b > len ? b-len : 0; | ||
| 22 | 	if (new>a && old<b) return 1; | ||
| 23 | |||
| 24 | 	b = (uintptr_t)&b; | ||
| 25 | 	a = b > len ? b-len : 0; | ||
| 26 | 	if (new>a && old<b) return 1; | ||
| 27 | |||
| 28 | 	return 0; | ||
| 29 | } | ||
| 30 | |||
| 31 | /* Expand the heap in-place if brk can be used, or otherwise via mmap, | ||
| 32 | * using an exponential lower bound on growth by mmap to make | ||
| 33 | * fragmentation asymptotically irrelevant. The size argument is both | ||
| 34 | * an input and an output, since the caller needs to know the size | ||
| 35 | * allocated, which will be larger than requested due to page alignment | ||
| 36 | * and mmap minimum size rules. The caller is responsible for locking | ||
| 37 | * to prevent concurrent calls. */ | ||
| 38 | |||
| 39 | void *__expand_heap(size_t *pn) | ||
| 40 | { | ||
| 41 | 	static uintptr_t brk; | ||
| 42 | 	static unsigned mmap_step; | ||
| 43 | 	size_t n = *pn; | ||
| 44 | |||
| 45 | 	if (n > SIZE_MAX/2 - PAGE_SIZE) { | ||
| 46 | 		errno = ENOMEM; | ||
| 47 | 		return 0; | ||
| 48 | 	} | ||
| 49 | 	n += -n & PAGE_SIZE-1; | ||
| 50 | |||
| 51 | 	if (!brk) { | ||
| 52 | 		brk = __syscall(SYS_brk, 0); | ||
| 53 | 		brk += -brk & PAGE_SIZE-1; | ||
| 54 | 	} | ||
| 55 | |||
| 56 | 	if (n < SIZE_MAX-brk && !traverses_stack_p(brk, brk+n) | ||
| 57 | 	 && __syscall(SYS_brk, brk+n)==brk+n) { | ||
| 58 | 		*pn = n; | ||
| 59 | 		brk += n; | ||
| 60 | 		return (void *)(brk-n); | ||
| 61 | 	} | ||
| 62 | |||
| 63 | 	size_t min = (size_t)PAGE_SIZE << mmap_step/2; | ||
| 64 | 	if (n < min) n = min; | ||
| 65 | 	void *area = __mmap(0, n, PROT_READ|PROT_WRITE, | ||
| 66 | 		MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); | ||
| 67 | 	if (area == MAP_FAILED) return 0; | ||
| 68 | 	*pn = n; | ||
| 69 | 	mmap_step++; | ||
| 70 | 	return area; | ||
| 71 | } | ||
lib/libc/musl/src/malloc/lite_malloc.c+72-28| ... | @@ -2,58 +2,102 @@ | ... | @@ -2,58 +2,102 @@ |
| 2 | #include <stdint.h> | 2 | #include <stdint.h> |
| 3 | #include <limits.h> | 3 | #include <limits.h> |
| 4 | #include <errno.h> | 4 | #include <errno.h> |
| 5 | #include <sys/mman.h> | ||
| 6 | #include "libc.h" | ||
| 5 | #include "lock.h" | 7 | #include "lock.h" |
| 6 | #include "malloc_impl.h" | 8 | #include "syscall.h" |
| 7 | 9 | ||
| 8 | #define ALIGN 16 | 10 | #define ALIGN 16 |
| 9 | 11 | ||
| 12 | /* This function returns true if the interval [old,new] | ||
| 13 | * intersects the 'len'-sized interval below &libc.auxv | ||
| 14 | * (interpreted as the main-thread stack) or below &b | ||
| 15 | * (the current stack). It is used to defend against | ||
| 16 | * buggy brk implementations that can cross the stack. */ | ||
| 17 | |||
| 18 | static int traverses_stack_p(uintptr_t old, uintptr_t new) | ||
| 19 | { | ||
| 20 | 	const uintptr_t len = 8<<20; | ||
| 21 | 	uintptr_t a, b; | ||
| 22 | |||
| 23 | 	b = (uintptr_t)libc.auxv; | ||
| 24 | 	a = b > len ? b-len : 0; | ||
| 25 | 	if (new>a && old<b) return 1; | ||
| 26 | |||
| 27 | 	b = (uintptr_t)&b; | ||
| 28 | 	a = b > len ? b-len : 0; | ||
| 29 | 	if (new>a && old<b) return 1; | ||
| 30 | |||
| 31 | 	return 0; | ||
| 32 | } | ||
| 33 | |||
| 10 | static void *__simple_malloc(size_t n) | 34 | static void *__simple_malloc(size_t n) |
| 11 | { | 35 | { |
| 12 | 	static char *cur, *end; | 36 | 	static uintptr_t brk, cur, end; |
| 13 | 	static volatile int lock[1]; | 37 | 	static volatile int lock[1]; |
| 14 | 	size_t align=1, pad; | 38 | 	static unsigned mmap_step; |
| 39 | 	size_t align=1; | ||
| 15 | 	void *p; | 40 | 	void *p; |
| 16 | 41 | ||
| 42 | 	if (n > SIZE_MAX/2) { | ||
| 43 | 		errno = ENOMEM; | ||
| 44 | 		return 0; | ||
| 45 | 	} | ||
| 46 | |||
| 17 | 	if (!n) n++; | 47 | 	if (!n) n++; |
| 18 | 	while (align<n && align<ALIGN) | 48 | 	while (align<n && align<ALIGN) |
| 19 | 		align += align; | 49 | 		align += align; |
| 20 | 50 | ||
| 21 | 	LOCK(lock); | 51 | 	LOCK(lock); |
| 22 | 52 | ||
| 23 | 	pad = -(uintptr_t)cur & align-1; | 53 | 	cur += -cur & align-1; |
| 24 | |||
| 25 | 	if (n <= SIZE_MAX/2 + ALIGN) n += pad; | ||
| 26 | 54 | ||
| 27 | 	if (n > end-cur) { | 55 | 	if (n > end-cur) { |
| 28 | 		size_t m = n; | 56 | 		size_t req = n - (end-cur) + PAGE_SIZE-1 & -PAGE_SIZE; |
| 29 | 		char *new = __expand_heap(&m); | 57 | |
| 30 | 		if (!new) { | 58 | 		if (!cur) { |
| 31 | 			UNLOCK(lock); | 59 | 			brk = __syscall(SYS_brk, 0); |
| 32 | 			return 0; | 60 | 			brk += -brk & PAGE_SIZE-1; |
| 61 | 			cur = end = brk; | ||
| 33 | 		} | 62 | 		} |
| 34 | 		if (new != end) { | 63 | |
| 35 | 			cur = new; | 64 | 		if (brk == end && req < SIZE_MAX-brk |
| 36 | 			n -= pad; | 65 | 		 && !traverses_stack_p(brk, brk+req) |
| 37 | 			pad = 0; | 66 | 		 && __syscall(SYS_brk, brk+req)==brk+req) { |
| 67 | 			brk = end += req; | ||
| 68 | 		} else { | ||
| 69 | 			int new_area = 0; | ||
| 70 | 			req = n + PAGE_SIZE-1 & -PAGE_SIZE; | ||
| 71 | 			/* Only make a new area rather than individual mmap | ||
| 72 | 			 * if wasted space would be over 1/8 of the map. */ | ||
| 73 | 			if (req-n > req/8) { | ||
| 74 | 				/* Geometric area size growth up to 64 pages, | ||
| 75 | 				 * bounding waste by 1/8 of the area. */ | ||
| 76 | 				size_t min = PAGE_SIZE<<(mmap_step/2); | ||
| 77 | 				if (min-n > end-cur) { | ||
| 78 | 					if (req < min) { | ||
| 79 | 						req = min; | ||
| 80 | 						if (mmap_step < 12) | ||
| 81 | 							mmap_step++; | ||
| 82 | 					} | ||
| 83 | 					new_area = 1; | ||
| 84 | 				} | ||
| 85 | 			} | ||
| 86 | 			void *mem = __mmap(0, req, PROT_READ|PROT_WRITE, | ||
| 87 | 				MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); | ||
| 88 | 			if (mem == MAP_FAILED || !new_area) { | ||
| 89 | 				UNLOCK(lock); | ||
| 90 | 				return mem==MAP_FAILED ? 0 : mem; | ||
| 91 | 			} | ||
| 92 | 			cur = (uintptr_t)mem; | ||
| 93 | 			end = cur + req; | ||
| 38 | 		} | 94 | 		} |
| 39 | 		end = new + m; | ||
| 40 | 	} | 95 | 	} |
| 41 | 96 | ||
| 42 | 	p = cur + pad; | 97 | 	p = (void *)cur; |
| 43 | 	cur += n; | 98 | 	cur += n; |
| 44 | 	UNLOCK(lock); | 99 | 	UNLOCK(lock); |
| 45 | 	return p; | 100 | 	return p; |
| 46 | } | 101 | } |
| 47 | 102 | ||
| 48 | weak_alias(__simple_malloc, malloc); | 103 | weak_alias(__simple_malloc, malloc); |
| 49 | |||
| 50 | static void *__simple_calloc(size_t m, size_t n) | ||
| 51 | { | ||
| 52 | 	if (n && m > (size_t)-1/n) { | ||
| 53 | 		errno = ENOMEM; | ||
| 54 | 		return 0; | ||
| 55 | 	} | ||
| 56 | 	return __simple_malloc(n * m); | ||
| 57 | } | ||
| 58 | |||
| 59 | weak_alias(__simple_calloc, calloc); |
lib/libc/musl/src/malloc/malloc.c deleted-548| ... | @@ -1,548 +0,0 @@ | ||
| 1 | #define _GNU_SOURCE | ||
| 2 | #include <stdlib.h> | ||
| 3 | #include <string.h> | ||
| 4 | #include <limits.h> | ||
| 5 | #include <stdint.h> | ||
| 6 | #include <errno.h> | ||
| 7 | #include <sys/mman.h> | ||
| 8 | #include "libc.h" | ||
| 9 | #include "atomic.h" | ||
| 10 | #include "pthread_impl.h" | ||
| 11 | #include "malloc_impl.h" | ||
| 12 | |||
| 13 | #if defined(__GNUC__) && defined(__PIC__) | ||
| 14 | #define inline inline __attribute__((always_inline)) | ||
| 15 | #endif | ||
| 16 | |||
| 17 | static struct { | ||
| 18 | 	volatile uint64_t binmap; | ||
| 19 | 	struct bin bins[64]; | ||
| 20 | 	volatile int free_lock[2]; | ||
| 21 | } mal; | ||
| 22 | |||
| 23 | int __malloc_replaced; | ||
| 24 | |||
| 25 | /* Synchronization tools */ | ||
| 26 | |||
| 27 | static inline void lock(volatile int *lk) | ||
| 28 | { | ||
| 29 | 	if (libc.threads_minus_1) | ||
| 30 | 		while(a_swap(lk, 1)) __wait(lk, lk+1, 1, 1); | ||
| 31 | } | ||
| 32 | |||
| 33 | static inline void unlock(volatile int *lk) | ||
| 34 | { | ||
| 35 | 	if (lk[0]) { | ||
| 36 | 		a_store(lk, 0); | ||
| 37 | 		if (lk[1]) __wake(lk, 1, 1); | ||
| 38 | 	} | ||
| 39 | } | ||
| 40 | |||
| 41 | static inline void lock_bin(int i) | ||
| 42 | { | ||
| 43 | 	lock(mal.bins[i].lock); | ||
| 44 | 	if (!mal.bins[i].head) | ||
| 45 | 		mal.bins[i].head = mal.bins[i].tail = BIN_TO_CHUNK(i); | ||
| 46 | } | ||
| 47 | |||
| 48 | static inline void unlock_bin(int i) | ||
| 49 | { | ||
| 50 | 	unlock(mal.bins[i].lock); | ||
| 51 | } | ||
| 52 | |||
| 53 | static int first_set(uint64_t x) | ||
| 54 | { | ||
| 55 | #if 1 | ||
| 56 | 	return a_ctz_64(x); | ||
| 57 | #else | ||
| 58 | 	static const char debruijn64[64] = { | ||
| 59 | 		0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, | ||
| 60 | 		62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, | ||
| 61 | 		63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, | ||
| 62 | 		51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 | ||
| 63 | 	}; | ||
| 64 | 	static const char debruijn32[32] = { | ||
| 65 | 		0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, | ||
| 66 | 		31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14 | ||
| 67 | 	}; | ||
| 68 | 	if (sizeof(long) < 8) { | ||
| 69 | 		uint32_t y = x; | ||
| 70 | 		if (!y) { | ||
| 71 | 			y = x>>32; | ||
| 72 | 			return 32 + debruijn32[(y&-y)*0x076be629 >> 27]; | ||
| 73 | 		} | ||
| 74 | 		return debruijn32[(y&-y)*0x076be629 >> 27]; | ||
| 75 | 	} | ||
| 76 | 	return debruijn64[(x&-x)*0x022fdd63cc95386dull >> 58]; | ||
| 77 | #endif | ||
| 78 | } | ||
| 79 | |||
| 80 | static const unsigned char bin_tab[60] = { | ||
| 81 | 	 32,33,34,35,36,36,37,37,38,38,39,39, | ||
| 82 | 	40,40,40,40,41,41,41,41,42,42,42,42,43,43,43,43, | ||
| 83 | 	44,44,44,44,44,44,44,44,45,45,45,45,45,45,45,45, | ||
| 84 | 	46,46,46,46,46,46,46,46,47,47,47,47,47,47,47,47, | ||
| 85 | }; | ||
| 86 | |||
| 87 | static int bin_index(size_t x) | ||
| 88 | { | ||
| 89 | 	x = x / SIZE_ALIGN - 1; | ||
| 90 | 	if (x <= 32) return x; | ||
| 91 | 	if (x < 512) return bin_tab[x/8-4]; | ||
| 92 | 	if (x > 0x1c00) return 63; | ||
| 93 | 	return bin_tab[x/128-4] + 16; | ||
| 94 | } | ||
| 95 | |||
| 96 | static int bin_index_up(size_t x) | ||
| 97 | { | ||
| 98 | 	x = x / SIZE_ALIGN - 1; | ||
| 99 | 	if (x <= 32) return x; | ||
| 100 | 	x--; | ||
| 101 | 	if (x < 512) return bin_tab[x/8-4] + 1; | ||
| 102 | 	return bin_tab[x/128-4] + 17; | ||
| 103 | } | ||
| 104 | |||
| 105 | #if 0 | ||
| 106 | void __dump_heap(int x) | ||
| 107 | { | ||
| 108 | 	struct chunk *c; | ||
| 109 | 	int i; | ||
| 110 | 	for (c = (void *)mal.heap; CHUNK_SIZE(c); c = NEXT_CHUNK(c)) | ||
| 111 | 		fprintf(stderr, "base %p size %zu (%d) flags %d/%d\n", | ||
| 112 | 			c, CHUNK_SIZE(c), bin_index(CHUNK_SIZE(c)), | ||
| 113 | 			c->csize & 15, | ||
| 114 | 			NEXT_CHUNK(c)->psize & 15); | ||
| 115 | 	for (i=0; i<64; i++) { | ||
| 116 | 		if (mal.bins[i].head != BIN_TO_CHUNK(i) && mal.bins[i].head) { | ||
| 117 | 			fprintf(stderr, "bin %d: %p\n", i, mal.bins[i].head); | ||
| 118 | 			if (!(mal.binmap & 1ULL<<i)) | ||
| 119 | 				fprintf(stderr, "missing from binmap!\n"); | ||
| 120 | 		} else if (mal.binmap & 1ULL<<i) | ||
| 121 | 			fprintf(stderr, "binmap wrongly contains %d!\n", i); | ||
| 122 | 	} | ||
| 123 | } | ||
| 124 | #endif | ||
| 125 | |||
| 126 | static struct chunk *expand_heap(size_t n) | ||
| 127 | { | ||
| 128 | 	static int heap_lock[2]; | ||
| 129 | 	static void *end; | ||
| 130 | 	void *p; | ||
| 131 | 	struct chunk *w; | ||
| 132 | |||
| 133 | 	/* The argument n already accounts for the caller's chunk | ||
| 134 | 	 * overhead needs, but if the heap can't be extended in-place, | ||
| 135 | 	 * we need room for an extra zero-sized sentinel chunk. */ | ||
| 136 | 	n += SIZE_ALIGN; | ||
| 137 | |||
| 138 | 	lock(heap_lock); | ||
| 139 | |||
| 140 | 	p = __expand_heap(&n); | ||
| 141 | 	if (!p) { | ||
| 142 | 		unlock(heap_lock); | ||
| 143 | 		return 0; | ||
| 144 | 	} | ||
| 145 | |||
| 146 | 	/* If not just expanding existing space, we need to make a | ||
| 147 | 	 * new sentinel chunk below the allocated space. */ | ||
| 148 | 	if (p != end) { | ||
| 149 | 		/* Valid/safe because of the prologue increment. */ | ||
| 150 | 		n -= SIZE_ALIGN; | ||
| 151 | 		p = (char *)p + SIZE_ALIGN; | ||
| 152 | 		w = MEM_TO_CHUNK(p); | ||
| 153 | 		w->psize = 0 | C_INUSE; | ||
| 154 | 	} | ||
| 155 | |||
| 156 | 	/* Record new heap end and fill in footer. */ | ||
| 157 | 	end = (char *)p + n; | ||
| 158 | 	w = MEM_TO_CHUNK(end); | ||
| 159 | 	w->psize = n | C_INUSE; | ||
| 160 | 	w->csize = 0 | C_INUSE; | ||
| 161 | |||
| 162 | 	/* Fill in header, which may be new or may be replacing a | ||
| 163 | 	 * zero-size sentinel header at the old end-of-heap. */ | ||
| 164 | 	w = MEM_TO_CHUNK(p); | ||
| 165 | 	w->csize = n | C_INUSE; | ||
| 166 | |||
| 167 | 	unlock(heap_lock); | ||
| 168 | |||
| 169 | 	return w; | ||
| 170 | } | ||
| 171 | |||
| 172 | static int adjust_size(size_t *n) | ||
| 173 | { | ||
| 174 | 	/* Result of pointer difference must fit in ptrdiff_t. */ | ||
| 175 | 	if (*n-1 > PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE) { | ||
| 176 | 		if (*n) { | ||
| 177 | 			errno = ENOMEM; | ||
| 178 | 			return -1; | ||
| 179 | 		} else { | ||
| 180 | 			*n = SIZE_ALIGN; | ||
| 181 | 			return 0; | ||
| 182 | 		} | ||
| 183 | 	} | ||
| 184 | 	*n = (*n + OVERHEAD + SIZE_ALIGN - 1) & SIZE_MASK; | ||
| 185 | 	return 0; | ||
| 186 | } | ||
| 187 | |||
| 188 | static void unbin(struct chunk *c, int i) | ||
| 189 | { | ||
| 190 | 	if (c->prev == c->next) | ||
| 191 | 		a_and_64(&mal.binmap, ~(1ULL<<i)); | ||
| 192 | 	c->prev->next = c->next; | ||
| 193 | 	c->next->prev = c->prev; | ||
| 194 | 	c->csize |= C_INUSE; | ||
| 195 | 	NEXT_CHUNK(c)->psize |= C_INUSE; | ||
| 196 | } | ||
| 197 | |||
| 198 | static int alloc_fwd(struct chunk *c) | ||
| 199 | { | ||
| 200 | 	int i; | ||
| 201 | 	size_t k; | ||
| 202 | 	while (!((k=c->csize) & C_INUSE)) { | ||
| 203 | 		i = bin_index(k); | ||
| 204 | 		lock_bin(i); | ||
| 205 | 		if (c->csize == k) { | ||
| 206 | 			unbin(c, i); | ||
| 207 | 			unlock_bin(i); | ||
| 208 | 			return 1; | ||
| 209 | 		} | ||
| 210 | 		unlock_bin(i); | ||
| 211 | 	} | ||
| 212 | 	return 0; | ||
| 213 | } | ||
| 214 | |||
| 215 | static int alloc_rev(struct chunk *c) | ||
| 216 | { | ||
| 217 | 	int i; | ||
| 218 | 	size_t k; | ||
| 219 | 	while (!((k=c->psize) & C_INUSE)) { | ||
| 220 | 		i = bin_index(k); | ||
| 221 | 		lock_bin(i); | ||
| 222 | 		if (c->psize == k) { | ||
| 223 | 			unbin(PREV_CHUNK(c), i); | ||
| 224 | 			unlock_bin(i); | ||
| 225 | 			return 1; | ||
| 226 | 		} | ||
| 227 | 		unlock_bin(i); | ||
| 228 | 	} | ||
| 229 | 	return 0; | ||
| 230 | } | ||
| 231 | |||
| 232 | |||
| 233 | /* pretrim - trims a chunk _prior_ to removing it from its bin. | ||
| 234 | * Must be called with i as the ideal bin for size n, j the bin | ||
| 235 | * for the _free_ chunk self, and bin j locked. */ | ||
| 236 | static int pretrim(struct chunk *self, size_t n, int i, int j) | ||
| 237 | { | ||
| 238 | 	size_t n1; | ||
| 239 | 	struct chunk *next, *split; | ||
| 240 | |||
| 241 | 	/* We cannot pretrim if it would require re-binning. */ | ||
| 242 | 	if (j < 40) return 0; | ||
| 243 | 	if (j < i+3) { | ||
| 244 | 		if (j != 63) return 0; | ||
| 245 | 		n1 = CHUNK_SIZE(self); | ||
| 246 | 		if (n1-n <= MMAP_THRESHOLD) return 0; | ||
| 247 | 	} else { | ||
| 248 | 		n1 = CHUNK_SIZE(self); | ||
| 249 | 	} | ||
| 250 | 	if (bin_index(n1-n) != j) return 0; | ||
| 251 | |||
| 252 | 	next = NEXT_CHUNK(self); | ||
| 253 | 	split = (void *)((char *)self + n); | ||
| 254 | |||
| 255 | 	split->prev = self->prev; | ||
| 256 | 	split->next = self->next; | ||
| 257 | 	split->prev->next = split; | ||
| 258 | 	split->next->prev = split; | ||
| 259 | 	split->psize = n | C_INUSE; | ||
| 260 | 	split->csize = n1-n; | ||
| 261 | 	next->psize = n1-n; | ||
| 262 | 	self->csize = n | C_INUSE; | ||
| 263 | 	return 1; | ||
| 264 | } | ||
| 265 | |||
| 266 | static void trim(struct chunk *self, size_t n) | ||
| 267 | { | ||
| 268 | 	size_t n1 = CHUNK_SIZE(self); | ||
| 269 | 	struct chunk *next, *split; | ||
| 270 | |||
| 271 | 	if (n >= n1 - DONTCARE) return; | ||
| 272 | |||
| 273 | 	next = NEXT_CHUNK(self); | ||
| 274 | 	split = (void *)((char *)self + n); | ||
| 275 | |||
| 276 | 	split->psize = n | C_INUSE; | ||
| 277 | 	split->csize = n1-n | C_INUSE; | ||
| 278 | 	next->psize = n1-n | C_INUSE; | ||
| 279 | 	self->csize = n | C_INUSE; | ||
| 280 | |||
| 281 | 	__bin_chunk(split); | ||
| 282 | } | ||
| 283 | |||
| 284 | void *malloc(size_t n) | ||
| 285 | { | ||
| 286 | 	struct chunk *c; | ||
| 287 | 	int i, j; | ||
| 288 | |||
| 289 | 	if (adjust_size(&n) < 0) return 0; | ||
| 290 | |||
| 291 | 	if (n > MMAP_THRESHOLD) { | ||
| 292 | 		size_t len = n + OVERHEAD + PAGE_SIZE - 1 & -PAGE_SIZE; | ||
| 293 | 		char *base = __mmap(0, len, PROT_READ|PROT_WRITE, | ||
| 294 | 			MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); | ||
| 295 | 		if (base == (void *)-1) return 0; | ||
| 296 | 		c = (void *)(base + SIZE_ALIGN - OVERHEAD); | ||
| 297 | 		c->csize = len - (SIZE_ALIGN - OVERHEAD); | ||
| 298 | 		c->psize = SIZE_ALIGN - OVERHEAD; | ||
| 299 | 		return CHUNK_TO_MEM(c); | ||
| 300 | 	} | ||
| 301 | |||
| 302 | 	i = bin_index_up(n); | ||
| 303 | 	for (;;) { | ||
| 304 | 		uint64_t mask = mal.binmap & -(1ULL<<i); | ||
| 305 | 		if (!mask) { | ||
| 306 | 			c = expand_heap(n); | ||
| 307 | 			if (!c) return 0; | ||
| 308 | 			if (alloc_rev(c)) { | ||
| 309 | 				struct chunk *x = c; | ||
| 310 | 				c = PREV_CHUNK(c); | ||
| 311 | 				NEXT_CHUNK(x)->psize = c->csize = | ||
| 312 | 					x->csize + CHUNK_SIZE(c); | ||
| 313 | 			} | ||
| 314 | 			break; | ||
| 315 | 		} | ||
| 316 | 		j = first_set(mask); | ||
| 317 | 		lock_bin(j); | ||
| 318 | 		c = mal.bins[j].head; | ||
| 319 | 		if (c != BIN_TO_CHUNK(j)) { | ||
| 320 | 			if (!pretrim(c, n, i, j)) unbin(c, j); | ||
| 321 | 			unlock_bin(j); | ||
| 322 | 			break; | ||
| 323 | 		} | ||
| 324 | 		unlock_bin(j); | ||
| 325 | 	} | ||
| 326 | |||
| 327 | 	/* Now patch up in case we over-allocated */ | ||
| 328 | 	trim(c, n); | ||
| 329 | |||
| 330 | 	return CHUNK_TO_MEM(c); | ||
| 331 | } | ||
| 332 | |||
| 333 | static size_t mal0_clear(char *p, size_t pagesz, size_t n) | ||
| 334 | { | ||
| 335 | #ifdef __GNUC__ | ||
| 336 | 	typedef uint64_t __attribute__((__may_alias__)) T; | ||
| 337 | #else | ||
| 338 | 	typedef unsigned char T; | ||
| 339 | #endif | ||
| 340 | 	char *pp = p + n; | ||
| 341 | 	size_t i = (uintptr_t)pp & (pagesz - 1); | ||
| 342 | 	for (;;) { | ||
| 343 | 		pp = memset(pp - i, 0, i); | ||
| 344 | 		if (pp - p < pagesz) return pp - p; | ||
| 345 | 		for (i = pagesz; i; i -= 2*sizeof(T), pp -= 2*sizeof(T)) | ||
| 346 | 		 if (((T *)pp)[-1] | ((T *)pp)[-2]) | ||
| 347 | 				break; | ||
| 348 | 	} | ||
| 349 | } | ||
| 350 | |||
| 351 | void *calloc(size_t m, size_t n) | ||
| 352 | { | ||
| 353 | 	if (n && m > (size_t)-1/n) { | ||
| 354 | 		errno = ENOMEM; | ||
| 355 | 		return 0; | ||
| 356 | 	} | ||
| 357 | 	n *= m; | ||
| 358 | 	void *p = malloc(n); | ||
| 359 | 	if (!p) return p; | ||
| 360 | 	if (!__malloc_replaced) { | ||
| 361 | 		if (IS_MMAPPED(MEM_TO_CHUNK(p))) | ||
| 362 | 			return p; | ||
| 363 | 		if (n >= PAGE_SIZE) | ||
| 364 | 			n = mal0_clear(p, PAGE_SIZE, n); | ||
| 365 | 	} | ||
| 366 | 	return memset(p, 0, n); | ||
| 367 | } | ||
| 368 | |||
| 369 | void *realloc(void *p, size_t n) | ||
| 370 | { | ||
| 371 | 	struct chunk *self, *next; | ||
| 372 | 	size_t n0, n1; | ||
| 373 | 	void *new; | ||
| 374 | |||
| 375 | 	if (!p) return malloc(n); | ||
| 376 | |||
| 377 | 	if (adjust_size(&n) < 0) return 0; | ||
| 378 | |||
| 379 | 	self = MEM_TO_CHUNK(p); | ||
| 380 | 	n1 = n0 = CHUNK_SIZE(self); | ||
| 381 | |||
| 382 | 	if (IS_MMAPPED(self)) { | ||
| 383 | 		size_t extra = self->psize; | ||
| 384 | 		char *base = (char *)self - extra; | ||
| 385 | 		size_t oldlen = n0 + extra; | ||
| 386 | 		size_t newlen = n + extra; | ||
| 387 | 		/* Crash on realloc of freed chunk */ | ||
| 388 | 		if (extra & 1) a_crash(); | ||
| 389 | 		if (newlen < PAGE_SIZE && (new = malloc(n-OVERHEAD))) { | ||
| 390 | 			n0 = n; | ||
| 391 | 			goto copy_free_ret; | ||
| 392 | 		} | ||
| 393 | 		newlen = (newlen + PAGE_SIZE-1) & -PAGE_SIZE; | ||
| 394 | 		if (oldlen == newlen) return p; | ||
| 395 | 		base = __mremap(base, oldlen, newlen, MREMAP_MAYMOVE); | ||
| 396 | 		if (base == (void *)-1) | ||
| 397 | 			goto copy_realloc; | ||
| 398 | 		self = (void *)(base + extra); | ||
| 399 | 		self->csize = newlen - extra; | ||
| 400 | 		return CHUNK_TO_MEM(self); | ||
| 401 | 	} | ||
| 402 | |||
| 403 | 	next = NEXT_CHUNK(self); | ||
| 404 | |||
| 405 | 	/* Crash on corrupted footer (likely from buffer overflow) */ | ||
| 406 | 	if (next->psize != self->csize) a_crash(); | ||
| 407 | |||
| 408 | 	/* Merge adjacent chunks if we need more space. This is not | ||
| 409 | 	 * a waste of time even if we fail to get enough space, because our | ||
| 410 | 	 * subsequent call to free would otherwise have to do the merge. */ | ||
| 411 | 	if (n > n1 && alloc_fwd(next)) { | ||
| 412 | 		n1 += CHUNK_SIZE(next); | ||
| 413 | 		next = NEXT_CHUNK(next); | ||
| 414 | 	} | ||
| 415 | 	/* FIXME: find what's wrong here and reenable it..? */ | ||
| 416 | 	if (0 && n > n1 && alloc_rev(self)) { | ||
| 417 | 		self = PREV_CHUNK(self); | ||
| 418 | 		n1 += CHUNK_SIZE(self); | ||
| 419 | 	} | ||
| 420 | 	self->csize = n1 | C_INUSE; | ||
| 421 | 	next->psize = n1 | C_INUSE; | ||
| 422 | |||
| 423 | 	/* If we got enough space, split off the excess and return */ | ||
| 424 | 	if (n <= n1) { | ||
| 425 | 		//memmove(CHUNK_TO_MEM(self), p, n0-OVERHEAD); | ||
| 426 | 		trim(self, n); | ||
| 427 | 		return CHUNK_TO_MEM(self); | ||
| 428 | 	} | ||
| 429 | |||
| 430 | copy_realloc: | ||
| 431 | 	/* As a last resort, allocate a new chunk and copy to it. */ | ||
| 432 | 	new = malloc(n-OVERHEAD); | ||
| 433 | 	if (!new) return 0; | ||
| 434 | copy_free_ret: | ||
| 435 | 	memcpy(new, p, n0-OVERHEAD); | ||
| 436 | 	free(CHUNK_TO_MEM(self)); | ||
| 437 | 	return new; | ||
| 438 | } | ||
| 439 | |||
| 440 | void __bin_chunk(struct chunk *self) | ||
| 441 | { | ||
| 442 | 	struct chunk *next = NEXT_CHUNK(self); | ||
| 443 | 	size_t final_size, new_size, size; | ||
| 444 | 	int reclaim=0; | ||
| 445 | 	int i; | ||
| 446 | |||
| 447 | 	final_size = new_size = CHUNK_SIZE(self); | ||
| 448 | |||
| 449 | 	/* Crash on corrupted footer (likely from buffer overflow) */ | ||
| 450 | 	if (next->psize != self->csize) a_crash(); | ||
| 451 | |||
| 452 | 	for (;;) { | ||
| 453 | 		if (self->psize & next->csize & C_INUSE) { | ||
| 454 | 			self->csize = final_size | C_INUSE; | ||
| 455 | 			next->psize = final_size | C_INUSE; | ||
| 456 | 			i = bin_index(final_size); | ||
| 457 | 			lock_bin(i); | ||
| 458 | 			lock(mal.free_lock); | ||
| 459 | 			if (self->psize & next->csize & C_INUSE) | ||
| 460 | 				break; | ||
| 461 | 			unlock(mal.free_lock); | ||
| 462 | 			unlock_bin(i); | ||
| 463 | 		} | ||
| 464 | |||
| 465 | 		if (alloc_rev(self)) { | ||
| 466 | 			self = PREV_CHUNK(self); | ||
| 467 | 			size = CHUNK_SIZE(self); | ||
| 468 | 			final_size += size; | ||
| 469 | 			if (new_size+size > RECLAIM && (new_size+size^size) > size) | ||
| 470 | 				reclaim = 1; | ||
| 471 | 		} | ||
| 472 | |||
| 473 | 		if (alloc_fwd(next)) { | ||
| 474 | 			size = CHUNK_SIZE(next); | ||
| 475 | 			final_size += size; | ||
| 476 | 			if (new_size+size > RECLAIM && (new_size+size^size) > size) | ||
| 477 | 				reclaim = 1; | ||
| 478 | 			next = NEXT_CHUNK(next); | ||
| 479 | 		} | ||
| 480 | 	} | ||
| 481 | |||
| 482 | 	if (!(mal.binmap & 1ULL<<i)) | ||
| 483 | 		a_or_64(&mal.binmap, 1ULL<<i); | ||
| 484 | |||
| 485 | 	self->csize = final_size; | ||
| 486 | 	next->psize = final_size; | ||
| 487 | 	unlock(mal.free_lock); | ||
| 488 | |||
| 489 | 	self->next = BIN_TO_CHUNK(i); | ||
| 490 | 	self->prev = mal.bins[i].tail; | ||
| 491 | 	self->next->prev = self; | ||
| 492 | 	self->prev->next = self; | ||
| 493 | |||
| 494 | 	/* Replace middle of large chunks with fresh zero pages */ | ||
| 495 | 	if (reclaim) { | ||
| 496 | 		uintptr_t a = (uintptr_t)self + SIZE_ALIGN+PAGE_SIZE-1 & -PAGE_SIZE; | ||
| 497 | 		uintptr_t b = (uintptr_t)next - SIZE_ALIGN & -PAGE_SIZE; | ||
| 498 | #if 1 | ||
| 499 | 		__madvise((void *)a, b-a, MADV_DONTNEED); | ||
| 500 | #else | ||
| 501 | 		__mmap((void *)a, b-a, PROT_READ|PROT_WRITE, | ||
| 502 | 			MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0); | ||
| 503 | #endif | ||
| 504 | 	} | ||
| 505 | |||
| 506 | 	unlock_bin(i); | ||
| 507 | } | ||
| 508 | |||
| 509 | static void unmap_chunk(struct chunk *self) | ||
| 510 | { | ||
| 511 | 	size_t extra = self->psize; | ||
| 512 | 	char *base = (char *)self - extra; | ||
| 513 | 	size_t len = CHUNK_SIZE(self) + extra; | ||
| 514 | 	/* Crash on double free */ | ||
| 515 | 	if (extra & 1) a_crash(); | ||
| 516 | 	__munmap(base, len); | ||
| 517 | } | ||
| 518 | |||
| 519 | void free(void *p) | ||
| 520 | { | ||
| 521 | 	if (!p) return; | ||
| 522 | |||
| 523 | 	struct chunk *self = MEM_TO_CHUNK(p); | ||
| 524 | |||
| 525 | 	if (IS_MMAPPED(self)) | ||
| 526 | 		unmap_chunk(self); | ||
| 527 | 	else | ||
| 528 | 		__bin_chunk(self); | ||
| 529 | } | ||
| 530 | |||
| 531 | void __malloc_donate(char *start, char *end) | ||
| 532 | { | ||
| 533 | 	size_t align_start_up = (SIZE_ALIGN-1) & (-(uintptr_t)start - OVERHEAD); | ||
| 534 | 	size_t align_end_down = (SIZE_ALIGN-1) & (uintptr_t)end; | ||
| 535 | |||
| 536 | 	/* Getting past this condition ensures that the padding for alignment | ||
| 537 | 	 * and header overhead will not overflow and will leave a nonzero | ||
| 538 | 	 * multiple of SIZE_ALIGN bytes between start and end. */ | ||
| 539 | 	if (end - start <= OVERHEAD + align_start_up + align_end_down) | ||
| 540 | 		return; | ||
| 541 | 	start += align_start_up + OVERHEAD; | ||
| 542 | 	end -= align_end_down; | ||
| 543 | |||
| 544 | 	struct chunk *c = MEM_TO_CHUNK(start), *n = MEM_TO_CHUNK(end); | ||
| 545 | 	c->psize = n->csize = C_INUSE; | ||
| 546 | 	c->csize = n->psize = C_INUSE | (end-start); | ||
| 547 | 	__bin_chunk(c); | ||
| 548 | } | ||
lib/libc/musl/src/malloc/malloc_usable_size.c deleted-9| ... | @@ -1,9 +0,0 @@ | ||
| 1 | #include <malloc.h> | ||
| 2 | #include "malloc_impl.h" | ||
| 3 | |||
| 4 | hidden void *(*const __realloc_dep)(void *, size_t) = realloc; | ||
| 5 | |||
| 6 | size_t malloc_usable_size(void *p) | ||
| 7 | { | ||
| 8 | 	return p ? CHUNK_SIZE(MEM_TO_CHUNK(p)) - OVERHEAD : 0; | ||
| 9 | } | ||
lib/libc/musl/src/malloc/mallocng/aligned_alloc.c created+57| ... | @@ -0,0 +1,57 @@ | ||
| 1 | #include <stdlib.h> | ||
| 2 | #include <errno.h> | ||
| 3 | #include "meta.h" | ||
| 4 | |||
| 5 | void *aligned_alloc(size_t align, size_t len) | ||
| 6 | { | ||
| 7 | 	if ((align & -align) != align) { | ||
| 8 | 		errno = EINVAL; | ||
| 9 | 		return 0; | ||
| 10 | 	} | ||
| 11 | |||
| 12 | 	if (len > SIZE_MAX - align || align >= (1ULL<<31)*UNIT) { | ||
| 13 | 		errno = ENOMEM; | ||
| 14 | 		return 0; | ||
| 15 | 	} | ||
| 16 | |||
| 17 | 	if (DISABLE_ALIGNED_ALLOC) { | ||
| 18 | 		errno = ENOMEM; | ||
| 19 | 		return 0; | ||
| 20 | 	} | ||
| 21 | |||
| 22 | 	if (align <= UNIT) align = UNIT; | ||
| 23 | |||
| 24 | 	unsigned char *p = malloc(len + align - UNIT); | ||
| 25 | 	struct meta *g = get_meta(p); | ||
| 26 | 	int idx = get_slot_index(p); | ||
| 27 | 	size_t stride = get_stride(g); | ||
| 28 | 	unsigned char *start = g->mem->storage + stride*idx; | ||
| 29 | 	unsigned char *end = g->mem->storage + stride*(idx+1) - IB; | ||
| 30 | 	size_t adj = -(uintptr_t)p & (align-1); | ||
| 31 | |||
| 32 | 	if (!adj) { | ||
| 33 | 		set_size(p, end, len); | ||
| 34 | 		return p; | ||
| 35 | 	} | ||
| 36 | 	p += adj; | ||
| 37 | 	uint32_t offset = (size_t)(p-g->mem->storage)/UNIT; | ||
| 38 | 	if (offset <= 0xffff) { | ||
| 39 | 		*(uint16_t *)(p-2) = offset; | ||
| 40 | 		p[-4] = 0; | ||
| 41 | 	} else { | ||
| 42 | 		// use a 32-bit offset if 16-bit doesn't fit. for this, | ||
| 43 | 		// 16-bit field must be zero, [-4] byte nonzero. | ||
| 44 | 		*(uint16_t *)(p-2) = 0; | ||
| 45 | 		*(uint32_t *)(p-8) = offset; | ||
| 46 | 		p[-4] = 1; | ||
| 47 | 	} | ||
| 48 | 	p[-3] = idx; | ||
| 49 | 	set_size(p, end, len); | ||
| 50 | 	// store offset to aligned enframing. this facilitates cycling | ||
| 51 | 	// offset and also iteration of heap for debugging/measurement. | ||
| 52 | 	// for extreme overalignment it won't fit but these are classless | ||
| 53 | 	// allocations anyway. | ||
| 54 | 	*(uint16_t *)(start - 2) = (size_t)(p-start)/UNIT; | ||
| 55 | 	start[-3] = 7<<5; | ||
| 56 | 	return p; | ||
| 57 | } | ||
lib/libc/musl/src/malloc/mallocng/donate.c created+39| ... | @@ -0,0 +1,39 @@ | ||
| 1 | #include <stdlib.h> | ||
| 2 | #include <stdint.h> | ||
| 3 | #include <limits.h> | ||
| 4 | #include <string.h> | ||
| 5 | #include <sys/mman.h> | ||
| 6 | #include <errno.h> | ||
| 7 | |||
| 8 | #include "meta.h" | ||
| 9 | |||
| 10 | static void donate(unsigned char *base, size_t len) | ||
| 11 | { | ||
| 12 | 	uintptr_t a = (uintptr_t)base; | ||
| 13 | 	uintptr_t b = a + len; | ||
| 14 | 	a += -a & (UNIT-1); | ||
| 15 | 	b -= b & (UNIT-1); | ||
| 16 | 	memset(base, 0, len); | ||
| 17 | 	for (int sc=47; sc>0 && b>a; sc-=4) { | ||
| 18 | 		if (b-a < (size_classes[sc]+1)*UNIT) continue; | ||
| 19 | 		struct meta *m = alloc_meta(); | ||
| 20 | 		m->avail_mask = 0; | ||
| 21 | 		m->freed_mask = 1; | ||
| 22 | 		m->mem = (void *)a; | ||
| 23 | 		m->mem->meta = m; | ||
| 24 | 		m->last_idx = 0; | ||
| 25 | 		m->freeable = 0; | ||
| 26 | 		m->sizeclass = sc; | ||
| 27 | 		m->maplen = 0; | ||
| 28 | 		*((unsigned char *)m->mem+UNIT-4) = 0; | ||
| 29 | 		*((unsigned char *)m->mem+UNIT-3) = 255; | ||
| 30 | 		m->mem->storage[size_classes[sc]*UNIT-4] = 0; | ||
| 31 | 		queue(&ctx.active[sc], m); | ||
| 32 | 		a += (size_classes[sc]+1)*UNIT; | ||
| 33 | 	} | ||
| 34 | } | ||
| 35 | |||
| 36 | void __malloc_donate(char *start, char *end) | ||
| 37 | { | ||
| 38 | 	donate((void *)start, end-start); | ||
| 39 | } | ||
lib/libc/musl/src/malloc/mallocng/free.c created+143| ... | @@ -0,0 +1,143 @@ | ||
| 1 | #define _BSD_SOURCE | ||
| 2 | #include <stdlib.h> | ||
| 3 | #include <sys/mman.h> | ||
| 4 | |||
| 5 | #include "meta.h" | ||
| 6 | |||
| 7 | struct mapinfo { | ||
| 8 | 	void *base; | ||
| 9 | 	size_t len; | ||
| 10 | }; | ||
| 11 | |||
| 12 | static struct mapinfo nontrivial_free(struct meta *, int); | ||
| 13 | |||
| 14 | static struct mapinfo free_group(struct meta *g) | ||
| 15 | { | ||
| 16 | 	struct mapinfo mi = { 0 }; | ||
| 17 | 	int sc = g->sizeclass; | ||
| 18 | 	if (sc < 48) { | ||
| 19 | 		ctx.usage_by_class[sc] -= g->last_idx+1; | ||
| 20 | 	} | ||
| 21 | 	if (g->maplen) { | ||
| 22 | 		step_seq(); | ||
| 23 | 		record_seq(sc); | ||
| 24 | 		mi.base = g->mem; | ||
| 25 | 		mi.len = g->maplen*4096UL; | ||
| 26 | 	} else { | ||
| 27 | 		void *p = g->mem; | ||
| 28 | 		struct meta *m = get_meta(p); | ||
| 29 | 		int idx = get_slot_index(p); | ||
| 30 | 		g->mem->meta = 0; | ||
| 31 | 		// not checking size/reserved here; it's intentionally invalid | ||
| 32 | 		mi = nontrivial_free(m, idx); | ||
| 33 | 	} | ||
| 34 | 	free_meta(g); | ||
| 35 | 	return mi; | ||
| 36 | } | ||
| 37 | |||
| 38 | static int okay_to_free(struct meta *g) | ||
| 39 | { | ||
| 40 | 	int sc = g->sizeclass; | ||
| 41 | |||
| 42 | 	if (!g->freeable) return 0; | ||
| 43 | |||
| 44 | 	// always free individual mmaps not suitable for reuse | ||
| 45 | 	if (sc >= 48 || get_stride(g) < UNIT*size_classes[sc]) | ||
| 46 | 		return 1; | ||
| 47 | |||
| 48 | 	// always free groups allocated inside another group's slot | ||
| 49 | 	// since recreating them should not be expensive and they | ||
| 50 | 	// might be blocking freeing of a much larger group. | ||
| 51 | 	if (!g->maplen) return 1; | ||
| 52 | |||
| 53 | 	// if there is another non-full group, free this one to | ||
| 54 | 	// consolidate future allocations, reduce fragmentation. | ||
| 55 | 	if (g->next != g) return 1; | ||
| 56 | |||
| 57 | 	// free any group in a size class that's not bouncing | ||
| 58 | 	if (!is_bouncing(sc)) return 1; | ||
| 59 | |||
| 60 | 	size_t cnt = g->last_idx+1; | ||
| 61 | 	size_t usage = ctx.usage_by_class[sc]; | ||
| 62 | |||
| 63 | 	// if usage is high enough that a larger count should be | ||
| 64 | 	// used, free the low-count group so a new one will be made. | ||
| 65 | 	if (9*cnt <= usage && cnt < 20) | ||
| 66 | 		return 1; | ||
| 67 | |||
| 68 | 	// otherwise, keep the last group in a bouncing class. | ||
| 69 | 	return 0; | ||
| 70 | } | ||
| 71 | |||
| 72 | static struct mapinfo nontrivial_free(struct meta *g, int i) | ||
| 73 | { | ||
| 74 | 	uint32_t self = 1u<<i; | ||
| 75 | 	int sc = g->sizeclass; | ||
| 76 | 	uint32_t mask = g->freed_mask | g->avail_mask; | ||
| 77 | |||
| 78 | 	if (mask+self == (2u<<g->last_idx)-1 && okay_to_free(g)) { | ||
| 79 | 		// any multi-slot group is necessarily on an active list | ||
| 80 | 		// here, but single-slot groups might or might not be. | ||
| 81 | 		if (g->next) { | ||
| 82 | 			assert(sc < 48); | ||
| 83 | 			int activate_new = (ctx.active[sc]==g); | ||
| 84 | 			dequeue(&ctx.active[sc], g); | ||
| 85 | 			if (activate_new && ctx.active[sc]) | ||
| 86 | 				activate_group(ctx.active[sc]); | ||
| 87 | 		} | ||
| 88 | 		return free_group(g); | ||
| 89 | 	} else if (!mask) { | ||
| 90 | 		assert(sc < 48); | ||
| 91 | 		// might still be active if there were no allocations | ||
| 92 | 		// after last available slot was taken. | ||
| 93 | 		if (ctx.active[sc] != g) { | ||
| 94 | 			queue(&ctx.active[sc], g); | ||
| 95 | 		} | ||
| 96 | 	} | ||
| 97 | 	a_or(&g->freed_mask, self); | ||
| 98 | 	return (struct mapinfo){ 0 }; | ||
| 99 | } | ||
| 100 | |||
| 101 | void free(void *p) | ||
| 102 | { | ||
| 103 | 	if (!p) return; | ||
| 104 | |||
| 105 | 	struct meta *g = get_meta(p); | ||
| 106 | 	int idx = get_slot_index(p); | ||
| 107 | 	size_t stride = get_stride(g); | ||
| 108 | 	unsigned char *start = g->mem->storage + stride*idx; | ||
| 109 | 	unsigned char *end = start + stride - IB; | ||
| 110 | 	get_nominal_size(p, end); | ||
| 111 | 	uint32_t self = 1u<<idx, all = (2u<<g->last_idx)-1; | ||
| 112 | 	((unsigned char *)p)[-3] = 255; | ||
| 113 | 	// invalidate offset to group header, and cycle offset of | ||
| 114 | 	// used region within slot if current offset is zero. | ||
| 115 | 	*(uint16_t *)((char *)p-2) = 0; | ||
| 116 | |||
| 117 | 	// release any whole pages contained in the slot to be freed | ||
| 118 | 	// unless it's a single-slot group that will be unmapped. | ||
| 119 | 	if (((uintptr_t)(start-1) ^ (uintptr_t)end) >= 2*PGSZ && g->last_idx) { | ||
| 120 | 		unsigned char *base = start + (-(uintptr_t)start & (PGSZ-1)); | ||
| 121 | 		size_t len = (end-base) & -PGSZ; | ||
| 122 | 		if (len) madvise(base, len, MADV_FREE); | ||
| 123 | 	} | ||
| 124 | |||
| 125 | 	// atomic free without locking if this is neither first or last slot | ||
| 126 | 	for (;;) { | ||
| 127 | 		uint32_t freed = g->freed_mask; | ||
| 128 | 		uint32_t avail = g->avail_mask; | ||
| 129 | 		uint32_t mask = freed | avail; | ||
| 130 | 		assert(!(mask&self)); | ||
| 131 | 		if (!freed || mask+self==all) break; | ||
| 132 | 		if (!MT) | ||
| 133 | 			g->freed_mask = freed+self; | ||
| 134 | 		else if (a_cas(&g->freed_mask, freed, freed+self)!=freed) | ||
| 135 | 			continue; | ||
| 136 | 		return; | ||
| 137 | 	} | ||
| 138 | |||
| 139 | 	wrlock(); | ||
| 140 | 	struct mapinfo mi = nontrivial_free(g, idx); | ||
| 141 | 	unlock(); | ||
| 142 | 	if (mi.len) munmap(mi.base, mi.len); | ||
| 143 | } | ||
lib/libc/musl/src/malloc/mallocng/glue.h created+77| ... | @@ -0,0 +1,77 @@ | ||
| 1 | #ifndef MALLOC_GLUE_H | ||
| 2 | #define MALLOC_GLUE_H | ||
| 3 | |||
| 4 | #include <stdint.h> | ||
| 5 | #include <sys/mman.h> | ||
| 6 | #include <pthread.h> | ||
| 7 | #include <unistd.h> | ||
| 8 | #include <elf.h> | ||
| 9 | #include <string.h> | ||
| 10 | #include "atomic.h" | ||
| 11 | #include "syscall.h" | ||
| 12 | #include "libc.h" | ||
| 13 | #include "lock.h" | ||
| 14 | #include "dynlink.h" | ||
| 15 | |||
| 16 | // use macros to appropriately namespace these. | ||
| 17 | #define size_classes __malloc_size_classes | ||
| 18 | #define ctx __malloc_context | ||
| 19 | #define alloc_meta __malloc_alloc_meta | ||
| 20 | #define is_allzero __malloc_allzerop | ||
| 21 | #define dump_heap __dump_heap | ||
| 22 | |||
| 23 | #if USE_REAL_ASSERT | ||
| 24 | #include <assert.h> | ||
| 25 | #else | ||
| 26 | #undef assert | ||
| 27 | #define assert(x) do { if (!(x)) a_crash(); } while(0) | ||
| 28 | #endif | ||
| 29 | |||
| 30 | #define brk(p) ((uintptr_t)__syscall(SYS_brk, p)) | ||
| 31 | |||
| 32 | #define mmap __mmap | ||
| 33 | #define madvise __madvise | ||
| 34 | #define mremap __mremap | ||
| 35 | |||
| 36 | #define DISABLE_ALIGNED_ALLOC (__malloc_replaced && !__aligned_alloc_replaced) | ||
| 37 | |||
| 38 | static inline uint64_t get_random_secret() | ||
| 39 | { | ||
| 40 | 	uint64_t secret = (uintptr_t)&secret * 1103515245; | ||
| 41 | 	for (size_t i=0; libc.auxv[i]; i+=2) | ||
| 42 | 		if (libc.auxv[i]==AT_RANDOM) | ||
| 43 | 			memcpy(&secret, (char *)libc.auxv[i+1]+8, sizeof secret); | ||
| 44 | 	return secret; | ||
| 45 | } | ||
| 46 | |||
| 47 | #ifndef PAGESIZE | ||
| 48 | #define PAGESIZE PAGE_SIZE | ||
| 49 | #endif | ||
| 50 | |||
| 51 | #define MT (libc.need_locks) | ||
| 52 | |||
| 53 | #define RDLOCK_IS_EXCLUSIVE 1 | ||
| 54 | |||
| 55 | __attribute__((__visibility__("hidden"))) | ||
| 56 | extern int __malloc_lock[1]; | ||
| 57 | |||
| 58 | #define LOCK_OBJ_DEF \ | ||
| 59 | int __malloc_lock[1]; | ||
| 60 | |||
| 61 | static inline void rdlock() | ||
| 62 | { | ||
| 63 | 	if (MT) LOCK(__malloc_lock); | ||
| 64 | } | ||
| 65 | static inline void wrlock() | ||
| 66 | { | ||
| 67 | 	if (MT) LOCK(__malloc_lock); | ||
| 68 | } | ||
| 69 | static inline void unlock() | ||
| 70 | { | ||
| 71 | 	UNLOCK(__malloc_lock); | ||
| 72 | } | ||
| 73 | static inline void upgradelock() | ||
| 74 | { | ||
| 75 | } | ||
| 76 | |||
| 77 | #endif | ||
lib/libc/musl/src/malloc/mallocng/malloc.c created+387| ... | @@ -0,0 +1,387 @@ | ||
| 1 | #include <stdlib.h> | ||
| 2 | #include <stdint.h> | ||
| 3 | #include <limits.h> | ||
| 4 | #include <string.h> | ||
| 5 | #include <sys/mman.h> | ||
| 6 | #include <errno.h> | ||
| 7 | |||
| 8 | #include "meta.h" | ||
| 9 | |||
| 10 | LOCK_OBJ_DEF; | ||
| 11 | |||
| 12 | const uint16_t size_classes[] = { | ||
| 13 | 	1, 2, 3, 4, 5, 6, 7, 8, | ||
| 14 | 	9, 10, 12, 15, | ||
| 15 | 	18, 20, 25, 31, | ||
| 16 | 	36, 42, 50, 63, | ||
| 17 | 	72, 84, 102, 127, | ||
| 18 | 	146, 170, 204, 255, | ||
| 19 | 	292, 340, 409, 511, | ||
| 20 | 	584, 682, 818, 1023, | ||
| 21 | 	1169, 1364, 1637, 2047, | ||
| 22 | 	2340, 2730, 3276, 4095, | ||
| 23 | 	4680, 5460, 6552, 8191, | ||
| 24 | }; | ||
| 25 | |||
| 26 | static const uint8_t small_cnt_tab[][3] = { | ||
| 27 | 	{ 30, 30, 30 }, | ||
| 28 | 	{ 31, 15, 15 }, | ||
| 29 | 	{ 20, 10, 10 }, | ||
| 30 | 	{ 31, 15, 7 }, | ||
| 31 | 	{ 25, 12, 6 }, | ||
| 32 | 	{ 21, 10, 5 }, | ||
| 33 | 	{ 18, 8, 4 }, | ||
| 34 | 	{ 31, 15, 7 }, | ||
| 35 | 	{ 28, 14, 6 }, | ||
| 36 | }; | ||
| 37 | |||
| 38 | static const uint8_t med_cnt_tab[4] = { 28, 24, 20, 32 }; | ||
| 39 | |||
| 40 | struct malloc_context ctx = { 0 }; | ||
| 41 | |||
| 42 | struct meta *alloc_meta(void) | ||
| 43 | { | ||
| 44 | 	struct meta *m; | ||
| 45 | 	unsigned char *p; | ||
| 46 | 	if (!ctx.init_done) { | ||
| 47 | #ifndef PAGESIZE | ||
| 48 | 		ctx.pagesize = get_page_size(); | ||
| 49 | #endif | ||
| 50 | 		ctx.secret = get_random_secret(); | ||
| 51 | 		ctx.init_done = 1; | ||
| 52 | 	} | ||
| 53 | 	size_t pagesize = PGSZ; | ||
| 54 | 	if (pagesize < 4096) pagesize = 4096; | ||
| 55 | 	if ((m = dequeue_head(&ctx.free_meta_head))) return m; | ||
| 56 | 	if (!ctx.avail_meta_count) { | ||
| 57 | 		int need_unprotect = 1; | ||
| 58 | 		if (!ctx.avail_meta_area_count && ctx.brk!=-1) { | ||
| 59 | 			uintptr_t new = ctx.brk + pagesize; | ||
| 60 | 			int need_guard = 0; | ||
| 61 | 			if (!ctx.brk) { | ||
| 62 | 				need_guard = 1; | ||
| 63 | 				ctx.brk = brk(0); | ||
| 64 | 				// some ancient kernels returned _ebss | ||
| 65 | 				// instead of next page as initial brk. | ||
| 66 | 				ctx.brk += -ctx.brk & (pagesize-1); | ||
| 67 | 				new = ctx.brk + 2*pagesize; | ||
| 68 | 			} | ||
| 69 | 			if (brk(new) != new) { | ||
| 70 | 				ctx.brk = -1; | ||
| 71 | 			} else { | ||
| 72 | 				if (need_guard) mmap((void *)ctx.brk, pagesize, | ||
| 73 | 					PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); | ||
| 74 | 				ctx.brk = new; | ||
| 75 | 				ctx.avail_meta_areas = (void *)(new - pagesize); | ||
| 76 | 				ctx.avail_meta_area_count = pagesize>>12; | ||
| 77 | 				need_unprotect = 0; | ||
| 78 | 			} | ||
| 79 | 		} | ||
| 80 | 		if (!ctx.avail_meta_area_count) { | ||
| 81 | 			size_t n = 2UL << ctx.meta_alloc_shift; | ||
| 82 | 			p = mmap(0, n*pagesize, PROT_NONE, | ||
| 83 | 				MAP_PRIVATE|MAP_ANON, -1, 0); | ||
| 84 | 			if (p==MAP_FAILED) return 0; | ||
| 85 | 			ctx.avail_meta_areas = p + pagesize; | ||
| 86 | 			ctx.avail_meta_area_count = (n-1)*(pagesize>>12); | ||
| 87 | 			ctx.meta_alloc_shift++; | ||
| 88 | 		} | ||
| 89 | 		p = ctx.avail_meta_areas; | ||
| 90 | 		if ((uintptr_t)p & (pagesize-1)) need_unprotect = 0; | ||
| 91 | 		if (need_unprotect) | ||
| 92 | 			if (mprotect(p, pagesize, PROT_READ|PROT_WRITE) | ||
| 93 | 			 && errno != ENOSYS) | ||
| 94 | 				return 0; | ||
| 95 | 		ctx.avail_meta_area_count--; | ||
| 96 | 		ctx.avail_meta_areas = p + 4096; | ||
| 97 | 		if (ctx.meta_area_tail) { | ||
| 98 | 			ctx.meta_area_tail->next = (void *)p; | ||
| 99 | 		} else { | ||
| 100 | 			ctx.meta_area_head = (void *)p; | ||
| 101 | 		} | ||
| 102 | 		ctx.meta_area_tail = (void *)p; | ||
| 103 | 		ctx.meta_area_tail->check = ctx.secret; | ||
| 104 | 		ctx.avail_meta_count = ctx.meta_area_tail->nslots | ||
| 105 | 			= (4096-sizeof(struct meta_area))/sizeof *m; | ||
| 106 | 		ctx.avail_meta = ctx.meta_area_tail->slots; | ||
| 107 | 	} | ||
| 108 | 	ctx.avail_meta_count--; | ||
| 109 | 	m = ctx.avail_meta++; | ||
| 110 | 	m->prev = m->next = 0; | ||
| 111 | 	return m; | ||
| 112 | } | ||
| 113 | |||
| 114 | static uint32_t try_avail(struct meta **pm) | ||
| 115 | { | ||
| 116 | 	struct meta *m = *pm; | ||
| 117 | 	uint32_t first; | ||
| 118 | 	if (!m) return 0; | ||
| 119 | 	uint32_t mask = m->avail_mask; | ||
| 120 | 	if (!mask) { | ||
| 121 | 		if (!m) return 0; | ||
| 122 | 		if (!m->freed_mask) { | ||
| 123 | 			dequeue(pm, m); | ||
| 124 | 			m = *pm; | ||
| 125 | 			if (!m) return 0; | ||
| 126 | 		} else { | ||
| 127 | 			m = m->next; | ||
| 128 | 			*pm = m; | ||
| 129 | 		} | ||
| 130 | |||
| 131 | 		mask = m->freed_mask; | ||
| 132 | |||
| 133 | 		// skip fully-free group unless it's the only one | ||
| 134 | 		// or it's a permanently non-freeable group | ||
| 135 | 		if (mask == (2u<<m->last_idx)-1 && m->freeable) { | ||
| 136 | 			m = m->next; | ||
| 137 | 			*pm = m; | ||
| 138 | 			mask = m->freed_mask; | ||
| 139 | 		} | ||
| 140 | |||
| 141 | 		// activate more slots in a not-fully-active group | ||
| 142 | 		// if needed, but only as a last resort. prefer using | ||
| 143 | 		// any other group with free slots. this avoids | ||
| 144 | 		// touching & dirtying as-yet-unused pages. | ||
| 145 | 		if (!(mask & ((2u<<m->mem->active_idx)-1))) { | ||
| 146 | 			if (m->next != m) { | ||
| 147 | 				m = m->next; | ||
| 148 | 				*pm = m; | ||
| 149 | 			} else { | ||
| 150 | 				int cnt = m->mem->active_idx + 2; | ||
| 151 | 				int size = size_classes[m->sizeclass]*UNIT; | ||
| 152 | 				int span = UNIT + size*cnt; | ||
| 153 | 				// activate up to next 4k boundary | ||
| 154 | 				while ((span^(span+size-1)) < 4096) { | ||
| 155 | 					cnt++; | ||
| 156 | 					span += size; | ||
| 157 | 				} | ||
| 158 | 				if (cnt > m->last_idx+1) | ||
| 159 | 					cnt = m->last_idx+1; | ||
| 160 | 				m->mem->active_idx = cnt-1; | ||
| 161 | 			} | ||
| 162 | 		} | ||
| 163 | 		mask = activate_group(m); | ||
| 164 | 		assert(mask); | ||
| 165 | 		decay_bounces(m->sizeclass); | ||
| 166 | 	} | ||
| 167 | 	first = mask&-mask; | ||
| 168 | 	m->avail_mask = mask-first; | ||
| 169 | 	return first; | ||
| 170 | } | ||
| 171 | |||
| 172 | static int alloc_slot(int, size_t); | ||
| 173 | |||
| 174 | static struct meta *alloc_group(int sc, size_t req) | ||
| 175 | { | ||
| 176 | 	size_t size = UNIT*size_classes[sc]; | ||
| 177 | 	int i = 0, cnt; | ||
| 178 | 	unsigned char *p; | ||
| 179 | 	struct meta *m = alloc_meta(); | ||
| 180 | 	if (!m) return 0; | ||
| 181 | 	size_t usage = ctx.usage_by_class[sc]; | ||
| 182 | 	size_t pagesize = PGSZ; | ||
| 183 | 	int active_idx; | ||
| 184 | 	if (sc < 9) { | ||
| 185 | 		while (i<2 && 4*small_cnt_tab[sc][i] > usage) | ||
| 186 | 			i++; | ||
| 187 | 		cnt = small_cnt_tab[sc][i]; | ||
| 188 | 	} else { | ||
| 189 | 		// lookup max number of slots fitting in power-of-two size | ||
| 190 | 		// from a table, along with number of factors of two we | ||
| 191 | 		// can divide out without a remainder or reaching 1. | ||
| 192 | 		cnt = med_cnt_tab[sc&3]; | ||
| 193 | |||
| 194 | 		// reduce cnt to avoid excessive eagar allocation. | ||
| 195 | 		while (!(cnt&1) && 4*cnt > usage) | ||
| 196 | 			cnt >>= 1; | ||
| 197 | |||
| 198 | 		// data structures don't support groups whose slot offsets | ||
| 199 | 		// in units don't fit in 16 bits. | ||
| 200 | 		while (size*cnt >= 65536*UNIT) | ||
| 201 | 			cnt >>= 1; | ||
| 202 | 	} | ||
| 203 | |||
| 204 | 	// If we selected a count of 1 above but it's not sufficient to use | ||
| 205 | 	// mmap, increase to 2. Then it might be; if not it will nest. | ||
| 206 | 	if (cnt==1 && size*cnt+UNIT <= pagesize/2) cnt = 2; | ||
| 207 | |||
| 208 | 	// All choices of size*cnt are "just below" a power of two, so anything | ||
| 209 | 	// larger than half the page size should be allocated as whole pages. | ||
| 210 | 	if (size*cnt+UNIT > pagesize/2) { | ||
| 211 | 		// check/update bounce counter to start/increase retention | ||
| 212 | 		// of freed maps, and inhibit use of low-count, odd-size | ||
| 213 | 		// small mappings and single-slot groups if activated. | ||
| 214 | 		int nosmall = is_bouncing(sc); | ||
| 215 | 		account_bounce(sc); | ||
| 216 | 		step_seq(); | ||
| 217 | |||
| 218 | 		// since the following count reduction opportunities have | ||
| 219 | 		// an absolute memory usage cost, don't overdo them. count | ||
| 220 | 		// coarse usage as part of usage. | ||
| 221 | 		if (!(sc&1) && sc<32) usage += ctx.usage_by_class[sc+1]; | ||
| 222 | |||
| 223 | 		// try to drop to a lower count if the one found above | ||
| 224 | 		// increases usage by more than 25%. these reduced counts | ||
| 225 | 		// roughly fill an integral number of pages, just not a | ||
| 226 | 		// power of two, limiting amount of unusable space. | ||
| 227 | 		if (4*cnt > usage && !nosmall) { | ||
| 228 | 			if (0); | ||
| 229 | 			else if ((sc&3)==1 && size*cnt>8*pagesize) cnt = 2; | ||
| 230 | 			else if ((sc&3)==2 && size*cnt>4*pagesize) cnt = 3; | ||
| 231 | 			else if ((sc&3)==0 && size*cnt>8*pagesize) cnt = 3; | ||
| 232 | 			else if ((sc&3)==0 && size*cnt>2*pagesize) cnt = 5; | ||
| 233 | 		} | ||
| 234 | 		size_t needed = size*cnt + UNIT; | ||
| 235 | 		needed += -needed & (pagesize-1); | ||
| 236 | |||
| 237 | 		// produce an individually-mmapped allocation if usage is low, | ||
| 238 | 		// bounce counter hasn't triggered, and either it saves memory | ||
| 239 | 		// or it avoids eagar slot allocation without wasting too much. | ||
| 240 | 		if (!nosmall && cnt<=7) { | ||
| 241 | 			req += IB + UNIT; | ||
| 242 | 			req += -req & (pagesize-1); | ||
| 243 | 			if (req<size+UNIT || (req>=4*pagesize && 2*cnt>usage)) { | ||
| 244 | 				cnt = 1; | ||
| 245 | 				needed = req; | ||
| 246 | 			} | ||
| 247 | 		} | ||
| 248 | |||
| 249 | 		p = mmap(0, needed, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); | ||
| 250 | 		if (p==MAP_FAILED) { | ||
| 251 | 			free_meta(m); | ||
| 252 | 			return 0; | ||
| 253 | 		} | ||
| 254 | 		m->maplen = needed>>12; | ||
| 255 | 		ctx.mmap_counter++; | ||
| 256 | 		active_idx = (4096-UNIT)/size-1; | ||
| 257 | 		if (active_idx > cnt-1) active_idx = cnt-1; | ||
| 258 | 		if (active_idx < 0) active_idx = 0; | ||
| 259 | 	} else { | ||
| 260 | 		int j = size_to_class(UNIT+cnt*size-IB); | ||
| 261 | 		int idx = alloc_slot(j, UNIT+cnt*size-IB); | ||
| 262 | 		if (idx < 0) { | ||
| 263 | 			free_meta(m); | ||
| 264 | 			return 0; | ||
| 265 | 		} | ||
| 266 | 		struct meta *g = ctx.active[j]; | ||
| 267 | 		p = enframe(g, idx, UNIT*size_classes[j]-IB, ctx.mmap_counter); | ||
| 268 | 		m->maplen = 0; | ||
| 269 | 		p[-3] = (p[-3]&31) | (6<<5); | ||
| 270 | 		for (int i=0; i<=cnt; i++) | ||
| 271 | 			p[UNIT+i*size-4] = 0; | ||
| 272 | 		active_idx = cnt-1; | ||
| 273 | 	} | ||
| 274 | 	ctx.usage_by_class[sc] += cnt; | ||
| 275 | 	m->avail_mask = (2u<<active_idx)-1; | ||
| 276 | 	m->freed_mask = (2u<<(cnt-1))-1 - m->avail_mask; | ||
| 277 | 	m->mem = (void *)p; | ||
| 278 | 	m->mem->meta = m; | ||
| 279 | 	m->mem->active_idx = active_idx; | ||
| 280 | 	m->last_idx = cnt-1; | ||
| 281 | 	m->freeable = 1; | ||
| 282 | 	m->sizeclass = sc; | ||
| 283 | 	return m; | ||
| 284 | } | ||
| 285 | |||
| 286 | static int alloc_slot(int sc, size_t req) | ||
| 287 | { | ||
| 288 | 	uint32_t first = try_avail(&ctx.active[sc]); | ||
| 289 | 	if (first) return a_ctz_32(first); | ||
| 290 | |||
| 291 | 	struct meta *g = alloc_group(sc, req); | ||
| 292 | 	if (!g) return -1; | ||
| 293 | |||
| 294 | 	g->avail_mask--; | ||
| 295 | 	queue(&ctx.active[sc], g); | ||
| 296 | 	return 0; | ||
| 297 | } | ||
| 298 | |||
| 299 | void *malloc(size_t n) | ||
| 300 | { | ||
| 301 | 	if (size_overflows(n)) return 0; | ||
| 302 | 	struct meta *g; | ||
| 303 | 	uint32_t mask, first; | ||
| 304 | 	int sc; | ||
| 305 | 	int idx; | ||
| 306 | 	int ctr; | ||
| 307 | |||
| 308 | 	if (n >= MMAP_THRESHOLD) { | ||
| 309 | 		size_t needed = n + IB + UNIT; | ||
| 310 | 		void *p = mmap(0, needed, PROT_READ|PROT_WRITE, | ||
| 311 | 			MAP_PRIVATE|MAP_ANON, -1, 0); | ||
| 312 | 		if (p==MAP_FAILED) return 0; | ||
| 313 | 		wrlock(); | ||
| 314 | 		step_seq(); | ||
| 315 | 		g = alloc_meta(); | ||
| 316 | 		if (!g) { | ||
| 317 | 			unlock(); | ||
| 318 | 			munmap(p, needed); | ||
| 319 | 			return 0; | ||
| 320 | 		} | ||
| 321 | 		g->mem = p; | ||
| 322 | 		g->mem->meta = g; | ||
| 323 | 		g->last_idx = 0; | ||
| 324 | 		g->freeable = 1; | ||
| 325 | 		g->sizeclass = 63; | ||
| 326 | 		g->maplen = (needed+4095)/4096; | ||
| 327 | 		g->avail_mask = g->freed_mask = 0; | ||
| 328 | 		// use a global counter to cycle offset in | ||
| 329 | 		// individually-mmapped allocations. | ||
| 330 | 		ctx.mmap_counter++; | ||
| 331 | 		idx = 0; | ||
| 332 | 		goto success; | ||
| 333 | 	} | ||
| 334 | |||
| 335 | 	sc = size_to_class(n); | ||
| 336 | |||
| 337 | 	rdlock(); | ||
| 338 | 	g = ctx.active[sc]; | ||
| 339 | |||
| 340 | 	// use coarse size classes initially when there are not yet | ||
| 341 | 	// any groups of desired size. this allows counts of 2 or 3 | ||
| 342 | 	// to be allocated at first rather than having to start with | ||
| 343 | 	// 7 or 5, the min counts for even size classes. | ||
| 344 | 	if (!g && sc>=4 && sc<32 && sc!=6 && !(sc&1) && !ctx.usage_by_class[sc]) { | ||
| 345 | 		size_t usage = ctx.usage_by_class[sc|1]; | ||
| 346 | 		// if a new group may be allocated, count it toward | ||
| 347 | 		// usage in deciding if we can use coarse class. | ||
| 348 | 		if (!ctx.active[sc|1] || (!ctx.active[sc|1]->avail_mask | ||
| 349 | 		 && !ctx.active[sc|1]->freed_mask)) | ||
| 350 | 			usage += 3; | ||
| 351 | 		if (usage <= 12) | ||
| 352 | 			sc |= 1; | ||
| 353 | 		g = ctx.active[sc]; | ||
| 354 | 	} | ||
| 355 | |||
| 356 | 	for (;;) { | ||
| 357 | 		mask = g ? g->avail_mask : 0; | ||
| 358 | 		first = mask&-mask; | ||
| 359 | 		if (!first) break; | ||
| 360 | 		if (RDLOCK_IS_EXCLUSIVE || !MT) | ||
| 361 | 			g->avail_mask = mask-first; | ||
| 362 | 		else if (a_cas(&g->avail_mask, mask, mask-first)!=mask) | ||
| 363 | 			continue; | ||
| 364 | 		idx = a_ctz_32(first); | ||
| 365 | 		goto success; | ||
| 366 | 	} | ||
| 367 | 	upgradelock(); | ||
| 368 | |||
| 369 | 	idx = alloc_slot(sc, n); | ||
| 370 | 	if (idx < 0) { | ||
| 371 | 		unlock(); | ||
| 372 | 		return 0; | ||
| 373 | 	} | ||
| 374 | 	g = ctx.active[sc]; | ||
| 375 | |||
| 376 | success: | ||
| 377 | 	ctr = ctx.mmap_counter; | ||
| 378 | 	unlock(); | ||
| 379 | 	return enframe(g, idx, n, ctr); | ||
| 380 | } | ||
| 381 | |||
| 382 | int is_allzero(void *p) | ||
| 383 | { | ||
| 384 | 	struct meta *g = get_meta(p); | ||
| 385 | 	return g->sizeclass >= 48 || | ||
| 386 | 		get_stride(g) < UNIT*size_classes[g->sizeclass]; | ||
| 387 | } | ||
lib/libc/musl/src/malloc/mallocng/malloc_usable_size.c created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | #include <stdlib.h> | ||
| 2 | #include "meta.h" | ||
| 3 | |||
| 4 | size_t malloc_usable_size(void *p) | ||
| 5 | { | ||
| 6 | 	struct meta *g = get_meta(p); | ||
| 7 | 	int idx = get_slot_index(p); | ||
| 8 | 	size_t stride = get_stride(g); | ||
| 9 | 	unsigned char *start = g->mem->storage + stride*idx; | ||
| 10 | 	unsigned char *end = start + stride - IB; | ||
| 11 | 	return get_nominal_size(p, end); | ||
| 12 | } | ||
lib/libc/musl/src/malloc/mallocng/meta.h created+288| ... | @@ -0,0 +1,288 @@ | ||
| 1 | #ifndef MALLOC_META_H | ||
| 2 | #define MALLOC_META_H | ||
| 3 | |||
| 4 | #include <stdint.h> | ||
| 5 | #include <errno.h> | ||
| 6 | #include <limits.h> | ||
| 7 | #include "glue.h" | ||
| 8 | |||
| 9 | __attribute__((__visibility__("hidden"))) | ||
| 10 | extern const uint16_t size_classes[]; | ||
| 11 | |||
| 12 | #define MMAP_THRESHOLD 131052 | ||
| 13 | |||
| 14 | #define UNIT 16 | ||
| 15 | #define IB 4 | ||
| 16 | |||
| 17 | struct group { | ||
| 18 | 	struct meta *meta; | ||
| 19 | 	unsigned char active_idx:5; | ||
| 20 | 	char pad[UNIT - sizeof(struct meta *) - 1]; | ||
| 21 | 	unsigned char storage[]; | ||
| 22 | }; | ||
| 23 | |||
| 24 | struct meta { | ||
| 25 | 	struct meta *prev, *next; | ||
| 26 | 	struct group *mem; | ||
| 27 | 	volatile int avail_mask, freed_mask; | ||
| 28 | 	uintptr_t last_idx:5; | ||
| 29 | 	uintptr_t freeable:1; | ||
| 30 | 	uintptr_t sizeclass:6; | ||
| 31 | 	uintptr_t maplen:8*sizeof(uintptr_t)-12; | ||
| 32 | }; | ||
| 33 | |||
| 34 | struct meta_area { | ||
| 35 | 	uint64_t check; | ||
| 36 | 	struct meta_area *next; | ||
| 37 | 	int nslots; | ||
| 38 | 	struct meta slots[]; | ||
| 39 | }; | ||
| 40 | |||
| 41 | struct malloc_context { | ||
| 42 | 	uint64_t secret; | ||
| 43 | #ifndef PAGESIZE | ||
| 44 | 	size_t pagesize; | ||
| 45 | #endif | ||
| 46 | 	int init_done; | ||
| 47 | 	unsigned mmap_counter; | ||
| 48 | 	struct meta *free_meta_head; | ||
| 49 | 	struct meta *avail_meta; | ||
| 50 | 	size_t avail_meta_count, avail_meta_area_count, meta_alloc_shift; | ||
| 51 | 	struct meta_area *meta_area_head, *meta_area_tail; | ||
| 52 | 	unsigned char *avail_meta_areas; | ||
| 53 | 	struct meta *active[48]; | ||
| 54 | 	size_t usage_by_class[48]; | ||
| 55 | 	uint8_t unmap_seq[32], bounces[32]; | ||
| 56 | 	uint8_t seq; | ||
| 57 | 	uintptr_t brk; | ||
| 58 | }; | ||
| 59 | |||
| 60 | __attribute__((__visibility__("hidden"))) | ||
| 61 | extern struct malloc_context ctx; | ||
| 62 | |||
| 63 | #ifdef PAGESIZE | ||
| 64 | #define PGSZ PAGESIZE | ||
| 65 | #else | ||
| 66 | #define PGSZ ctx.pagesize | ||
| 67 | #endif | ||
| 68 | |||
| 69 | __attribute__((__visibility__("hidden"))) | ||
| 70 | struct meta *alloc_meta(void); | ||
| 71 | |||
| 72 | __attribute__((__visibility__("hidden"))) | ||
| 73 | int is_allzero(void *); | ||
| 74 | |||
| 75 | static inline void queue(struct meta **phead, struct meta *m) | ||
| 76 | { | ||
| 77 | 	assert(!m->next); | ||
| 78 | 	assert(!m->prev); | ||
| 79 | 	if (*phead) { | ||
| 80 | 		struct meta *head = *phead; | ||
| 81 | 		m->next = head; | ||
| 82 | 		m->prev = head->prev; | ||
| 83 | 		m->next->prev = m->prev->next = m; | ||
| 84 | 	} else { | ||
| 85 | 		m->prev = m->next = m; | ||
| 86 | 		*phead = m; | ||
| 87 | 	} | ||
| 88 | } | ||
| 89 | |||
| 90 | static inline void dequeue(struct meta **phead, struct meta *m) | ||
| 91 | { | ||
| 92 | 	if (m->next != m) { | ||
| 93 | 		m->prev->next = m->next; | ||
| 94 | 		m->next->prev = m->prev; | ||
| 95 | 		if (*phead == m) *phead = m->next; | ||
| 96 | 	} else { | ||
| 97 | 		*phead = 0; | ||
| 98 | 	} | ||
| 99 | 	m->prev = m->next = 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | static inline struct meta *dequeue_head(struct meta **phead) | ||
| 103 | { | ||
| 104 | 	struct meta *m = *phead; | ||
| 105 | 	if (m) dequeue(phead, m); | ||
| 106 | 	return m; | ||
| 107 | } | ||
| 108 | |||
| 109 | static inline void free_meta(struct meta *m) | ||
| 110 | { | ||
| 111 | 	*m = (struct meta){0}; | ||
| 112 | 	queue(&ctx.free_meta_head, m); | ||
| 113 | } | ||
| 114 | |||
| 115 | static inline uint32_t activate_group(struct meta *m) | ||
| 116 | { | ||
| 117 | 	assert(!m->avail_mask); | ||
| 118 | 	uint32_t mask, act = (2u<<m->mem->active_idx)-1; | ||
| 119 | 	do mask = m->freed_mask; | ||
| 120 | 	while (a_cas(&m->freed_mask, mask, mask&~act)!=mask); | ||
| 121 | 	return m->avail_mask = mask & act; | ||
| 122 | } | ||
| 123 | |||
| 124 | static inline int get_slot_index(const unsigned char *p) | ||
| 125 | { | ||
| 126 | 	return p[-3] & 31; | ||
| 127 | } | ||
| 128 | |||
| 129 | static inline struct meta *get_meta(const unsigned char *p) | ||
| 130 | { | ||
| 131 | 	assert(!((uintptr_t)p & 15)); | ||
| 132 | 	int offset = *(const uint16_t *)(p - 2); | ||
| 133 | 	int index = get_slot_index(p); | ||
| 134 | 	if (p[-4]) { | ||
| 135 | 		assert(!offset); | ||
| 136 | 		offset = *(uint32_t *)(p - 8); | ||
| 137 | 		assert(offset > 0xffff); | ||
| 138 | 	} | ||
| 139 | 	const struct group *base = (const void *)(p - UNIT*offset - UNIT); | ||
| 140 | 	const struct meta *meta = base->meta; | ||
| 141 | 	assert(meta->mem == base); | ||
| 142 | 	assert(index <= meta->last_idx); | ||
| 143 | 	assert(!(meta->avail_mask & (1u<<index))); | ||
| 144 | 	assert(!(meta->freed_mask & (1u<<index))); | ||
| 145 | 	const struct meta_area *area = (void *)((uintptr_t)meta & -4096); | ||
| 146 | 	assert(area->check == ctx.secret); | ||
| 147 | 	if (meta->sizeclass < 48) { | ||
| 148 | 		assert(offset >= size_classes[meta->sizeclass]*index); | ||
| 149 | 		assert(offset < size_classes[meta->sizeclass]*(index+1)); | ||
| 150 | 	} else { | ||
| 151 | 		assert(meta->sizeclass == 63); | ||
| 152 | 	} | ||
| 153 | 	if (meta->maplen) { | ||
| 154 | 		assert(offset <= meta->maplen*4096UL/UNIT - 1); | ||
| 155 | 	} | ||
| 156 | 	return (struct meta *)meta; | ||
| 157 | } | ||
| 158 | |||
| 159 | static inline size_t get_nominal_size(const unsigned char *p, const unsigned char *end) | ||
| 160 | { | ||
| 161 | 	size_t reserved = p[-3] >> 5; | ||
| 162 | 	if (reserved >= 5) { | ||
| 163 | 		assert(reserved == 5); | ||
| 164 | 		reserved = *(const uint32_t *)(end-4); | ||
| 165 | 		assert(reserved >= 5); | ||
| 166 | 		assert(!end[-5]); | ||
| 167 | 	} | ||
| 168 | 	assert(reserved <= end-p); | ||
| 169 | 	assert(!*(end-reserved)); | ||
| 170 | 	// also check the slot's overflow byte | ||
| 171 | 	assert(!*end); | ||
| 172 | 	return end-reserved-p; | ||
| 173 | } | ||
| 174 | |||
| 175 | static inline size_t get_stride(const struct meta *g) | ||
| 176 | { | ||
| 177 | 	if (!g->last_idx && g->maplen) { | ||
| 178 | 		return g->maplen*4096UL - UNIT; | ||
| 179 | 	} else { | ||
| 180 | 		return UNIT*size_classes[g->sizeclass]; | ||
| 181 | 	} | ||
| 182 | } | ||
| 183 | |||
| 184 | static inline void set_size(unsigned char *p, unsigned char *end, size_t n) | ||
| 185 | { | ||
| 186 | 	int reserved = end-p-n; | ||
| 187 | 	if (reserved) end[-reserved] = 0; | ||
| 188 | 	if (reserved >= 5) { | ||
| 189 | 		*(uint32_t *)(end-4) = reserved; | ||
| 190 | 		end[-5] = 0; | ||
| 191 | 		reserved = 5; | ||
| 192 | 	} | ||
| 193 | 	p[-3] = (p[-3]&31) + (reserved<<5); | ||
| 194 | } | ||
| 195 | |||
| 196 | static inline void *enframe(struct meta *g, int idx, size_t n, int ctr) | ||
| 197 | { | ||
| 198 | 	size_t stride = get_stride(g); | ||
| 199 | 	size_t slack = (stride-IB-n)/UNIT; | ||
| 200 | 	unsigned char *p = g->mem->storage + stride*idx; | ||
| 201 | 	unsigned char *end = p+stride-IB; | ||
| 202 | 	// cycle offset within slot to increase interval to address | ||
| 203 | 	// reuse, facilitate trapping double-free. | ||
| 204 | 	int off = (p[-3] ? *(uint16_t *)(p-2) + 1 : ctr) & 255; | ||
| 205 | 	assert(!p[-4]); | ||
| 206 | 	if (off > slack) { | ||
| 207 | 		size_t m = slack; | ||
| 208 | 		m |= m>>1; m |= m>>2; m |= m>>4; | ||
| 209 | 		off &= m; | ||
| 210 | 		if (off > slack) off -= slack+1; | ||
| 211 | 		assert(off <= slack); | ||
| 212 | 	} | ||
| 213 | 	if (off) { | ||
| 214 | 		// store offset in unused header at offset zero | ||
| 215 | 		// if enframing at non-zero offset. | ||
| 216 | 		*(uint16_t *)(p-2) = off; | ||
| 217 | 		p[-3] = 7<<5; | ||
| 218 | 		p += UNIT*off; | ||
| 219 | 		// for nonzero offset there is no permanent check | ||
| 220 | 		// byte, so make one. | ||
| 221 | 		p[-4] = 0; | ||
| 222 | 	} | ||
| 223 | 	*(uint16_t *)(p-2) = (size_t)(p-g->mem->storage)/UNIT; | ||
| 224 | 	p[-3] = idx; | ||
| 225 | 	set_size(p, end, n); | ||
| 226 | 	return p; | ||
| 227 | } | ||
| 228 | |||
| 229 | static inline int size_to_class(size_t n) | ||
| 230 | { | ||
| 231 | 	n = (n+IB-1)>>4; | ||
| 232 | 	if (n<10) return n; | ||
| 233 | 	n++; | ||
| 234 | 	int i = (28-a_clz_32(n))*4 + 8; | ||
| 235 | 	if (n>size_classes[i+1]) i+=2; | ||
| 236 | 	if (n>size_classes[i]) i++; | ||
| 237 | 	return i; | ||
| 238 | } | ||
| 239 | |||
| 240 | static inline int size_overflows(size_t n) | ||
| 241 | { | ||
| 242 | 	if (n >= SIZE_MAX/2 - 4096) { | ||
| 243 | 		errno = ENOMEM; | ||
| 244 | 		return 1; | ||
| 245 | 	} | ||
| 246 | 	return 0; | ||
| 247 | } | ||
| 248 | |||
| 249 | static inline void step_seq(void) | ||
| 250 | { | ||
| 251 | 	if (ctx.seq==255) { | ||
| 252 | 		for (int i=0; i<32; i++) ctx.unmap_seq[i] = 0; | ||
| 253 | 		ctx.seq = 1; | ||
| 254 | 	} else { | ||
| 255 | 		ctx.seq++; | ||
| 256 | 	} | ||
| 257 | } | ||
| 258 | |||
| 259 | static inline void record_seq(int sc) | ||
| 260 | { | ||
| 261 | 	if (sc-7U < 32) ctx.unmap_seq[sc-7] = ctx.seq; | ||
| 262 | } | ||
| 263 | |||
| 264 | static inline void account_bounce(int sc) | ||
| 265 | { | ||
| 266 | 	if (sc-7U < 32) { | ||
| 267 | 		int seq = ctx.unmap_seq[sc-7]; | ||
| 268 | 		if (seq && ctx.seq-seq < 10) { | ||
| 269 | 			if (ctx.bounces[sc-7]+1 < 100) | ||
| 270 | 				ctx.bounces[sc-7]++; | ||
| 271 | 			else | ||
| 272 | 				ctx.bounces[sc-7] = 150; | ||
| 273 | 		} | ||
| 274 | 	} | ||
| 275 | } | ||
| 276 | |||
| 277 | static inline void decay_bounces(int sc) | ||
| 278 | { | ||
| 279 | 	if (sc-7U < 32 && ctx.bounces[sc-7]) | ||
| 280 | 		ctx.bounces[sc-7]--; | ||
| 281 | } | ||
| 282 | |||
| 283 | static inline int is_bouncing(int sc) | ||
| 284 | { | ||
| 285 | 	return (sc-7U < 32 && ctx.bounces[sc-7] >= 100); | ||
| 286 | } | ||
| 287 | |||
| 288 | #endif | ||
lib/libc/musl/src/malloc/mallocng/realloc.c created+51| ... | @@ -0,0 +1,51 @@ | ||
| 1 | #define _GNU_SOURCE | ||
| 2 | #include <stdlib.h> | ||
| 3 | #include <sys/mman.h> | ||
| 4 | #include <string.h> | ||
| 5 | #include "meta.h" | ||
| 6 | |||
| 7 | void *realloc(void *p, size_t n) | ||
| 8 | { | ||
| 9 | 	if (!p) return malloc(n); | ||
| 10 | 	if (size_overflows(n)) return 0; | ||
| 11 | |||
| 12 | 	struct meta *g = get_meta(p); | ||
| 13 | 	int idx = get_slot_index(p); | ||
| 14 | 	size_t stride = get_stride(g); | ||
| 15 | 	unsigned char *start = g->mem->storage + stride*idx; | ||
| 16 | 	unsigned char *end = start + stride - IB; | ||
| 17 | 	size_t old_size = get_nominal_size(p, end); | ||
| 18 | 	size_t avail_size = end-(unsigned char *)p; | ||
| 19 | 	void *new; | ||
| 20 | |||
| 21 | 	// only resize in-place if size class matches | ||
| 22 | 	if (n <= avail_size && n<MMAP_THRESHOLD | ||
| 23 | 	 && size_to_class(n)+1 >= g->sizeclass) { | ||
| 24 | 		set_size(p, end, n); | ||
| 25 | 		return p; | ||
| 26 | 	} | ||
| 27 | |||
| 28 | 	// use mremap if old and new size are both mmap-worthy | ||
| 29 | 	if (g->sizeclass>=48 && n>=MMAP_THRESHOLD) { | ||
| 30 | 		assert(g->sizeclass==63); | ||
| 31 | 		size_t base = (unsigned char *)p-start; | ||
| 32 | 		size_t needed = (n + base + UNIT + IB + 4095) & -4096; | ||
| 33 | 		new = g->maplen*4096UL == needed ? g->mem : | ||
| 34 | 			mremap(g->mem, g->maplen*4096UL, needed, MREMAP_MAYMOVE); | ||
| 35 | 		if (new!=MAP_FAILED) { | ||
| 36 | 			g->mem = new; | ||
| 37 | 			g->maplen = needed/4096; | ||
| 38 | 			p = g->mem->storage + base; | ||
| 39 | 			end = g->mem->storage + (needed - UNIT) - IB; | ||
| 40 | 			*end = 0; | ||
| 41 | 			set_size(p, end, n); | ||
| 42 | 			return p; | ||
| 43 | 		} | ||
| 44 | 	} | ||
| 45 | |||
| 46 | 	new = malloc(n); | ||
| 47 | 	if (!new) return 0; | ||
| 48 | 	memcpy(new, p, n < old_size ? n : old_size); | ||
| 49 | 	free(p); | ||
| 50 | 	return new; | ||
| 51 | } | ||
lib/libc/musl/src/malloc/memalign.c+3-50| ... | @@ -1,54 +1,7 @@ | ... | @@ -1,54 +1,7 @@ |
| 1 | #define _BSD_SOURCE | ||
| 1 | #include <stdlib.h> | 2 | #include <stdlib.h> |
| 2 | #include <stdint.h> | ||
| 3 | #include <errno.h> | ||
| 4 | #include "malloc_impl.h" | ||
| 5 | 3 | ||
| 6 | void *__memalign(size_t align, size_t len) | 4 | void *memalign(size_t align, size_t len) |
| 7 | { | 5 | { |
| 8 | 	unsigned char *mem, *new; | 6 | 	return aligned_alloc(align, len); |
| 9 | |||
| 10 | 	if ((align & -align) != align) { | ||
| 11 | 		errno = EINVAL; | ||
| 12 | 		return 0; | ||
| 13 | 	} | ||
| 14 | |||
| 15 | 	if (len > SIZE_MAX - align || __malloc_replaced) { | ||
| 16 | 		errno = ENOMEM; | ||
| 17 | 		return 0; | ||
| 18 | 	} | ||
| 19 | |||
| 20 | 	if (align <= SIZE_ALIGN) | ||
| 21 | 		return malloc(len); | ||
| 22 | |||
| 23 | 	if (!(mem = malloc(len + align-1))) | ||
| 24 | 		return 0; | ||
| 25 | |||
| 26 | 	new = (void *)((uintptr_t)mem + align-1 & -align); | ||
| 27 | 	if (new == mem) return mem; | ||
| 28 | |||
| 29 | 	struct chunk *c = MEM_TO_CHUNK(mem); | ||
| 30 | 	struct chunk *n = MEM_TO_CHUNK(new); | ||
| 31 | |||
| 32 | 	if (IS_MMAPPED(c)) { | ||
| 33 | 		/* Apply difference between aligned and original | ||
| 34 | 		 * address to the "extra" field of mmapped chunk. */ | ||
| 35 | 		n->psize = c->psize + (new-mem); | ||
| 36 | 		n->csize = c->csize - (new-mem); | ||
| 37 | 		return new; | ||
| 38 | 	} | ||
| 39 | |||
| 40 | 	struct chunk *t = NEXT_CHUNK(c); | ||
| 41 | |||
| 42 | 	/* Split the allocated chunk into two chunks. The aligned part | ||
| 43 | 	 * that will be used has the size in its footer reduced by the | ||
| 44 | 	 * difference between the aligned and original addresses, and | ||
| 45 | 	 * the resulting size copied to its header. A new header and | ||
| 46 | 	 * footer are written for the split-off part to be freed. */ | ||
| 47 | 	n->psize = c->csize = C_INUSE | (new-mem); | ||
| 48 | 	n->csize = t->psize -= new-mem; | ||
| 49 | |||
| 50 | 	__bin_chunk(c); | ||
| 51 | 	return new; | ||
| 52 | } | 7 | } |
| 53 | |||
| 54 | weak_alias(__memalign, memalign); |
lib/libc/musl/src/malloc/posix_memalign.c+1-2| ... | @@ -1,11 +1,10 @@ | ... | @@ -1,11 +1,10 @@ |
| 1 | #include <stdlib.h> | 1 | #include <stdlib.h> |
| 2 | #include <errno.h> | 2 | #include <errno.h> |
| 3 | #include "malloc_impl.h" | ||
| 4 | 3 | ||
| 5 | int posix_memalign(void **res, size_t align, size_t len) | 4 | int posix_memalign(void **res, size_t align, size_t len) |
| 6 | { | 5 | { |
| 7 | 	if (align < sizeof(void *)) return EINVAL; | 6 | 	if (align < sizeof(void *)) return EINVAL; |
| 8 | 	void *mem = __memalign(align, len); | 7 | 	void *mem = aligned_alloc(align, len); |
| 9 | 	if (!mem) return errno; | 8 | 	if (!mem) return errno; |
| 10 | 	*res = mem; | 9 | 	*res = mem; |
| 11 | 	return 0; | 10 | 	return 0; |
lib/libc/musl/src/malloc/replaced.c created+4| ... | @@ -0,0 +1,4 @@ | ||
| 1 | #include "dynlink.h" | ||
| 2 | |||
| 3 | int __malloc_replaced; | ||
| 4 | int __aligned_alloc_replaced; | ||
lib/libc/musl/src/math/__expo2.c+3-2| ... | @@ -5,12 +5,13 @@ static const int k = 2043; | ... | @@ -5,12 +5,13 @@ static const int k = 2043; |
| 5 | static const double kln2 = 0x1.62066151add8bp+10; | 5 | static const double kln2 = 0x1.62066151add8bp+10; |
| 6 | 6 | ||
| 7 | /* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ | 7 | /* exp(x)/2 for x >= log(DBL_MAX), slightly better than 0.5*exp(x/2)*exp(x/2) */ |
| 8 | double __expo2(double x) | 8 | double __expo2(double x, double sign) |
| 9 | { | 9 | { |
| 10 | 	double scale; | 10 | 	double scale; |
| 11 | 11 | ||
| 12 | 	/* note that k is odd and scale*scale overflows */ | 12 | 	/* note that k is odd and scale*scale overflows */ |
| 13 | 	INSERT_WORDS(scale, (uint32_t)(0x3ff + k/2) << 20, 0); | 13 | 	INSERT_WORDS(scale, (uint32_t)(0x3ff + k/2) << 20, 0); |
| 14 | 	/* exp(x - k ln2) * 2**(k-1) */ | 14 | 	/* exp(x - k ln2) * 2**(k-1) */ |
| 15 | 	return exp(x - kln2) * scale * scale; | 15 | 	/* in directed rounding correct sign before rounding or overflow is important */ |
| 16 | 	return exp(x - kln2) * (sign * scale) * scale; | ||
| 16 | } | 17 | } |
lib/libc/musl/src/math/__expo2f.c+3-2| ... | @@ -5,12 +5,13 @@ static const int k = 235; | ... | @@ -5,12 +5,13 @@ static const int k = 235; |
| 5 | static const float kln2 = 0x1.45c778p+7f; | 5 | static const float kln2 = 0x1.45c778p+7f; |
| 6 | 6 | ||
| 7 | /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ | 7 | /* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */ |
| 8 | float __expo2f(float x) | 8 | float __expo2f(float x, float sign) |
| 9 | { | 9 | { |
| 10 | 	float scale; | 10 | 	float scale; |
| 11 | 11 | ||
| 12 | 	/* note that k is odd and scale*scale overflows */ | 12 | 	/* note that k is odd and scale*scale overflows */ |
| 13 | 	SET_FLOAT_WORD(scale, (uint32_t)(0x7f + k/2) << 23); | 13 | 	SET_FLOAT_WORD(scale, (uint32_t)(0x7f + k/2) << 23); |
| 14 | 	/* exp(x - k ln2) * 2**(k-1) */ | 14 | 	/* exp(x - k ln2) * 2**(k-1) */ |
| 15 | 	return expf(x - kln2) * scale * scale; | 15 | 	/* in directed rounding correct sign before rounding or overflow is important */ |
| 16 | 	return expf(x - kln2) * (sign * scale) * scale; | ||
| 16 | } | 17 | } |
lib/libc/musl/src/math/__rem_pio2.c+14-1| ... | @@ -36,6 +36,7 @@ | ... | @@ -36,6 +36,7 @@ |
| 36 | */ | 36 | */ |
| 37 | static const double | 37 | static const double |
| 38 | toint = 1.5/EPS, | 38 | toint = 1.5/EPS, |
| 39 | pio4 = 0x1.921fb54442d18p-1, | ||
| 39 | invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ | 40 | invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ |
| 40 | pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */ | 41 | pio2_1 = 1.57079632673412561417e+00, /* 0x3FF921FB, 0x54400000 */ |
| 41 | pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */ | 42 | pio2_1t = 6.07710050650619224932e-11, /* 0x3DD0B461, 0x1A626331 */ |
| ... | @@ -117,11 +118,23 @@ int __rem_pio2(double x, double *y) | ... | @@ -117,11 +118,23 @@ int __rem_pio2(double x, double *y) |
| 117 | 	} | 118 | 	} |
| 118 | 	if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */ | 119 | 	if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */ |
| 119 | medium: | 120 | medium: |
| 120 | 		/* rint(x/(pi/2)), Assume round-to-nearest. */ | 121 | 		/* rint(x/(pi/2)) */ |
| 121 | 		fn = (double_t)x*invpio2 + toint - toint; | 122 | 		fn = (double_t)x*invpio2 + toint - toint; |
| 122 | 		n = (int32_t)fn; | 123 | 		n = (int32_t)fn; |
| 123 | 		r = x - fn*pio2_1; | 124 | 		r = x - fn*pio2_1; |
| 124 | 		w = fn*pio2_1t; /* 1st round, good to 85 bits */ | 125 | 		w = fn*pio2_1t; /* 1st round, good to 85 bits */ |
| 126 | 		/* Matters with directed rounding. */ | ||
| 127 | 		if (predict_false(r - w < -pio4)) { | ||
| 128 | 			n--; | ||
| 129 | 			fn--; | ||
| 130 | 			r = x - fn*pio2_1; | ||
| 131 | 			w = fn*pio2_1t; | ||
| 132 | 		} else if (predict_false(r - w > pio4)) { | ||
| 133 | 			n++; | ||
| 134 | 			fn++; | ||
| 135 | 			r = x - fn*pio2_1; | ||
| 136 | 			w = fn*pio2_1t; | ||
| 137 | 		} | ||
| 125 | 		y[0] = r - w; | 138 | 		y[0] = r - w; |
| 126 | 		u.f = y[0]; | 139 | 		u.f = y[0]; |
| 127 | 		ey = u.i>>52 & 0x7ff; | 140 | 		ey = u.i>>52 & 0x7ff; |
lib/libc/musl/src/math/__rem_pio2f.c+12-1| ... | @@ -35,6 +35,7 @@ | ... | @@ -35,6 +35,7 @@ |
| 35 | */ | 35 | */ |
| 36 | static const double | 36 | static const double |
| 37 | toint = 1.5/EPS, | 37 | toint = 1.5/EPS, |
| 38 | pio4 = 0x1.921fb6p-1, | ||
| 38 | invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ | 39 | invpio2 = 6.36619772367581382433e-01, /* 0x3FE45F30, 0x6DC9C883 */ |
| 39 | pio2_1 = 1.57079631090164184570e+00, /* 0x3FF921FB, 0x50000000 */ | 40 | pio2_1 = 1.57079631090164184570e+00, /* 0x3FF921FB, 0x50000000 */ |
| 40 | pio2_1t = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ | 41 | pio2_1t = 1.58932547735281966916e-08; /* 0x3E5110b4, 0x611A6263 */ |
| ... | @@ -50,10 +51,20 @@ int __rem_pio2f(float x, double *y) | ... | @@ -50,10 +51,20 @@ int __rem_pio2f(float x, double *y) |
| 50 | 	ix = u.i & 0x7fffffff; | 51 | 	ix = u.i & 0x7fffffff; |
| 51 | 	/* 25+53 bit pi is good enough for medium size */ | 52 | 	/* 25+53 bit pi is good enough for medium size */ |
| 52 | 	if (ix < 0x4dc90fdb) { /* |x| ~< 2^28*(pi/2), medium size */ | 53 | 	if (ix < 0x4dc90fdb) { /* |x| ~< 2^28*(pi/2), medium size */ |
| 53 | 		/* Use a specialized rint() to get fn. Assume round-to-nearest. */ | 54 | 		/* Use a specialized rint() to get fn. */ |
| 54 | 		fn = (double_t)x*invpio2 + toint - toint; | 55 | 		fn = (double_t)x*invpio2 + toint - toint; |
| 55 | 		n = (int32_t)fn; | 56 | 		n = (int32_t)fn; |
| 56 | 		*y = x - fn*pio2_1 - fn*pio2_1t; | 57 | 		*y = x - fn*pio2_1 - fn*pio2_1t; |
| 58 | 		/* Matters with directed rounding. */ | ||
| 59 | 		if (predict_false(*y < -pio4)) { | ||
| 60 | 			n--; | ||
| 61 | 			fn--; | ||
| 62 | 			*y = x - fn*pio2_1 - fn*pio2_1t; | ||
| 63 | 		} else if (predict_false(*y > pio4)) { | ||
| 64 | 			n++; | ||
| 65 | 			fn++; | ||
| 66 | 			*y = x - fn*pio2_1 - fn*pio2_1t; | ||
| 67 | 		} | ||
| 57 | 		return n; | 68 | 		return n; |
| 58 | 	} | 69 | 	} |
| 59 | 	if(ix>=0x7f800000) { /* x is inf or NaN */ | 70 | 	if(ix>=0x7f800000) { /* x is inf or NaN */ |
lib/libc/musl/src/math/__rem_pio2l.c+15-1| ... | @@ -44,6 +44,7 @@ pio2_1 = 1.57079632679597125389e+00, /* 0x3FF921FB, 0x54444000 */ | ... | @@ -44,6 +44,7 @@ pio2_1 = 1.57079632679597125389e+00, /* 0x3FF921FB, 0x54444000 */ |
| 44 | pio2_2 = -1.07463465549783099519e-12, /* -0x12e7b967674000.0p-92 */ | 44 | pio2_2 = -1.07463465549783099519e-12, /* -0x12e7b967674000.0p-92 */ |
| 45 | pio2_3 = 6.36831716351370313614e-25; /* 0x18a2e037074000.0p-133 */ | 45 | pio2_3 = 6.36831716351370313614e-25; /* 0x18a2e037074000.0p-133 */ |
| 46 | static const long double | 46 | static const long double |
| 47 | pio4 = 0x1.921fb54442d1846ap-1L, | ||
| 47 | invpio2 = 6.36619772367581343076e-01L, /* 0xa2f9836e4e44152a.0p-64 */ | 48 | invpio2 = 6.36619772367581343076e-01L, /* 0xa2f9836e4e44152a.0p-64 */ |
| 48 | pio2_1t = -1.07463465549719416346e-12L, /* -0x973dcb3b399d747f.0p-103 */ | 49 | pio2_1t = -1.07463465549719416346e-12L, /* -0x973dcb3b399d747f.0p-103 */ |
| 49 | pio2_2t = 6.36831716351095013979e-25L, /* 0xc51701b839a25205.0p-144 */ | 50 | pio2_2t = 6.36831716351095013979e-25L, /* 0xc51701b839a25205.0p-144 */ |
| ... | @@ -57,6 +58,7 @@ pio2_3t = -2.75299651904407171810e-37L; /* -0xbb5bf6c7ddd660ce.0p-185 */ | ... | @@ -57,6 +58,7 @@ pio2_3t = -2.75299651904407171810e-37L; /* -0xbb5bf6c7ddd660ce.0p-185 */ |
| 57 | #define NX 5 | 58 | #define NX 5 |
| 58 | #define NY 3 | 59 | #define NY 3 |
| 59 | static const long double | 60 | static const long double |
| 61 | pio4 = 0x1.921fb54442d18469898cc51701b8p-1L, | ||
| 60 | invpio2 = 6.3661977236758134307553505349005747e-01L,	/* 0x145f306dc9c882a53f84eafa3ea6a.0p-113 */ | 62 | invpio2 = 6.3661977236758134307553505349005747e-01L,	/* 0x145f306dc9c882a53f84eafa3ea6a.0p-113 */ |
| 61 | pio2_1 = 1.5707963267948966192292994253909555e+00L,	/* 0x1921fb54442d18469800000000000.0p-112 */ | 63 | pio2_1 = 1.5707963267948966192292994253909555e+00L,	/* 0x1921fb54442d18469800000000000.0p-112 */ |
| 62 | pio2_1t = 2.0222662487959507323996846200947577e-21L,	/* 0x13198a2e03707344a4093822299f3.0p-181 */ | 64 | pio2_1t = 2.0222662487959507323996846200947577e-21L,	/* 0x13198a2e03707344a4093822299f3.0p-181 */ |
| ... | @@ -76,11 +78,23 @@ int __rem_pio2l(long double x, long double *y) | ... | @@ -76,11 +78,23 @@ int __rem_pio2l(long double x, long double *y) |
| 76 | 	u.f = x; | 78 | 	u.f = x; |
| 77 | 	ex = u.i.se & 0x7fff; | 79 | 	ex = u.i.se & 0x7fff; |
| 78 | 	if (SMALL(u)) { | 80 | 	if (SMALL(u)) { |
| 79 | 		/* rint(x/(pi/2)), Assume round-to-nearest. */ | 81 | 		/* rint(x/(pi/2)) */ |
| 80 | 		fn = x*invpio2 + toint - toint; | 82 | 		fn = x*invpio2 + toint - toint; |
| 81 | 		n = QUOBITS(fn); | 83 | 		n = QUOBITS(fn); |
| 82 | 		r = x-fn*pio2_1; | 84 | 		r = x-fn*pio2_1; |
| 83 | 		w = fn*pio2_1t; /* 1st round good to 102/180 bits (ld80/ld128) */ | 85 | 		w = fn*pio2_1t; /* 1st round good to 102/180 bits (ld80/ld128) */ |
| 86 | 		/* Matters with directed rounding. */ | ||
| 87 | 		if (predict_false(r - w < -pio4)) { | ||
| 88 | 			n--; | ||
| 89 | 			fn--; | ||
| 90 | 			r = x - fn*pio2_1; | ||
| 91 | 			w = fn*pio2_1t; | ||
| 92 | 		} else if (predict_false(r - w > pio4)) { | ||
| 93 | 			n++; | ||
| 94 | 			fn++; | ||
| 95 | 			r = x - fn*pio2_1; | ||
| 96 | 			w = fn*pio2_1t; | ||
| 97 | 		} | ||
| 84 | 		y[0] = r-w; | 98 | 		y[0] = r-w; |
| 85 | 		u.f = y[0]; | 99 | 		u.f = y[0]; |
| 86 | 		ey = u.i.se & 0x7fff; | 100 | 		ey = u.i.se & 0x7fff; |
lib/libc/musl/src/math/cosh.c+1-1| ... | @@ -35,6 +35,6 @@ double cosh(double x) | ... | @@ -35,6 +35,6 @@ double cosh(double x) |
| 35 | 35 | ||
| 36 | 	/* |x| > log(DBL_MAX) or nan */ | 36 | 	/* |x| > log(DBL_MAX) or nan */ |
| 37 | 	/* note: the result is stored to handle overflow */ | 37 | 	/* note: the result is stored to handle overflow */ |
| 38 | 	t = __expo2(x); | 38 | 	t = __expo2(x, 1.0); |
| 39 | 	return t; | 39 | 	return t; |
| 40 | } | 40 | } |
lib/libc/musl/src/math/coshf.c+1-1| ... | @@ -28,6 +28,6 @@ float coshf(float x) | ... | @@ -28,6 +28,6 @@ float coshf(float x) |
| 28 | 	} | 28 | 	} |
| 29 | 29 | ||
| 30 | 	/* |x| > log(FLT_MAX) or nan */ | 30 | 	/* |x| > log(FLT_MAX) or nan */ |
| 31 | 	t = __expo2f(x); | 31 | 	t = __expo2f(x, 1.0f); |
| 32 | 	return t; | 32 | 	return t; |
| 33 | } | 33 | } |
lib/libc/musl/src/math/i386/fabs.c created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | double fabs(double x) | ||
| 4 | { | ||
| 5 | 	__asm__ ("fabs" : "+t"(x)); | ||
| 6 | 	return x; | ||
| 7 | } | ||
lib/libc/musl/src/math/i386/fabs.s deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | .global fabs | ||
| 2 | .type fabs,@function | ||
| 3 | fabs: | ||
| 4 | 	fldl 4(%esp) | ||
| 5 | 	fabs | ||
| 6 | 	ret | ||
lib/libc/musl/src/math/i386/fabsf.c created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | float fabsf(float x) | ||
| 4 | { | ||
| 5 | 	__asm__ ("fabs" : "+t"(x)); | ||
| 6 | 	return x; | ||
| 7 | } | ||
lib/libc/musl/src/math/i386/fabsf.s deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | .global fabsf | ||
| 2 | .type fabsf,@function | ||
| 3 | fabsf: | ||
| 4 | 	flds 4(%esp) | ||
| 5 | 	fabs | ||
| 6 | 	ret | ||
lib/libc/musl/src/math/i386/fabsl.c created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long double fabsl(long double x) | ||
| 4 | { | ||
| 5 | 	__asm__ ("fabs" : "+t"(x)); | ||
| 6 | 	return x; | ||
| 7 | } | ||
lib/libc/musl/src/math/i386/fabsl.s deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | .global fabsl | ||
| 2 | .type fabsl,@function | ||
| 3 | fabsl: | ||
| 4 | 	fldt 4(%esp) | ||
| 5 | 	fabs | ||
| 6 | 	ret | ||
lib/libc/musl/src/math/i386/fmod.c created+10| ... | @@ -0,0 +1,10 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | double fmod(double x, double y) | ||
| 4 | { | ||
| 5 | 	unsigned short fpsr; | ||
| 6 | 	// fprem does not introduce excess precision into x | ||
| 7 | 	do __asm__ ("fprem; fnstsw %%ax" : "+t"(x), "=a"(fpsr) : "u"(y)); | ||
| 8 | 	while (fpsr & 0x400); | ||
| 9 | 	return x; | ||
| 10 | } | ||
lib/libc/musl/src/math/i386/fmod.s deleted-11| ... | @@ -1,11 +0,0 @@ | ||
| 1 | .global fmod | ||
| 2 | .type fmod,@function | ||
| 3 | fmod: | ||
| 4 | 	fldl 12(%esp) | ||
| 5 | 	fldl 4(%esp) | ||
| 6 | 1:	fprem | ||
| 7 | 	fnstsw %ax | ||
| 8 | 	sahf | ||
| 9 | 	jp 1b | ||
| 10 | 	fstp %st(1) | ||
| 11 | 	ret | ||
lib/libc/musl/src/math/i386/fmodf.c created+10| ... | @@ -0,0 +1,10 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | float fmodf(float x, float y) | ||
| 4 | { | ||
| 5 | 	unsigned short fpsr; | ||
| 6 | 	// fprem does not introduce excess precision into x | ||
| 7 | 	do __asm__ ("fprem; fnstsw %%ax" : "+t"(x), "=a"(fpsr) : "u"(y)); | ||
| 8 | 	while (fpsr & 0x400); | ||
| 9 | 	return x; | ||
| 10 | } | ||
lib/libc/musl/src/math/i386/fmodf.s deleted-11| ... | @@ -1,11 +0,0 @@ | ||
| 1 | .global fmodf | ||
| 2 | .type fmodf,@function | ||
| 3 | fmodf: | ||
| 4 | 	flds 8(%esp) | ||
| 5 | 	flds 4(%esp) | ||
| 6 | 1:	fprem | ||
| 7 | 	fnstsw %ax | ||
| 8 | 	sahf | ||
| 9 | 	jp 1b | ||
| 10 | 	fstp %st(1) | ||
| 11 | 	ret | ||
lib/libc/musl/src/math/i386/fmodl.c created+9| ... | @@ -0,0 +1,9 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long double fmodl(long double x, long double y) | ||
| 4 | { | ||
| 5 | 	unsigned short fpsr; | ||
| 6 | 	do __asm__ ("fprem; fnstsw %%ax" : "+t"(x), "=a"(fpsr) : "u"(y)); | ||
| 7 | 	while (fpsr & 0x400); | ||
| 8 | 	return x; | ||
| 9 | } | ||
lib/libc/musl/src/math/i386/fmodl.s deleted-11| ... | @@ -1,11 +0,0 @@ | ||
| 1 | .global fmodl | ||
| 2 | .type fmodl,@function | ||
| 3 | fmodl: | ||
| 4 | 	fldt 16(%esp) | ||
| 5 | 	fldt 4(%esp) | ||
| 6 | 1:	fprem | ||
| 7 | 	fnstsw %ax | ||
| 8 | 	sahf | ||
| 9 | 	jp 1b | ||
| 10 | 	fstp %st(1) | ||
| 11 | 	ret | ||
lib/libc/musl/src/math/i386/llrint.c created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long long llrint(double x) | ||
| 4 | { | ||
| 5 | 	long long r; | ||
| 6 | 	__asm__ ("fistpll %0" : "=m"(r) : "t"(x) : "st"); | ||
| 7 | 	return r; | ||
| 8 | } | ||
lib/libc/musl/src/math/i386/llrint.s deleted-8| ... | @@ -1,8 +0,0 @@ | ||
| 1 | .global llrint | ||
| 2 | .type llrint,@function | ||
| 3 | llrint: | ||
| 4 | 	fldl 4(%esp) | ||
| 5 | 	fistpll 4(%esp) | ||
| 6 | 	mov 4(%esp),%eax | ||
| 7 | 	mov 8(%esp),%edx | ||
| 8 | 	ret | ||
lib/libc/musl/src/math/i386/llrintf.c created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long long llrintf(float x) | ||
| 4 | { | ||
| 5 | 	long long r; | ||
| 6 | 	__asm__ ("fistpll %0" : "=m"(r) : "t"(x) : "st"); | ||
| 7 | 	return r; | ||
| 8 | } | ||
lib/libc/musl/src/math/i386/llrintf.s deleted-9| ... | @@ -1,9 +0,0 @@ | ||
| 1 | .global llrintf | ||
| 2 | .type llrintf,@function | ||
| 3 | llrintf: | ||
| 4 | 	sub $8,%esp | ||
| 5 | 	flds 12(%esp) | ||
| 6 | 	fistpll (%esp) | ||
| 7 | 	pop %eax | ||
| 8 | 	pop %edx | ||
| 9 | 	ret | ||
lib/libc/musl/src/math/i386/llrintl.c created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long long llrintl(long double x) | ||
| 4 | { | ||
| 5 | 	long long r; | ||
| 6 | 	__asm__ ("fistpll %0" : "=m"(r) : "t"(x) : "st"); | ||
| 7 | 	return r; | ||
| 8 | } | ||
lib/libc/musl/src/math/i386/llrintl.s deleted-8| ... | @@ -1,8 +0,0 @@ | ||
| 1 | .global llrintl | ||
| 2 | .type llrintl,@function | ||
| 3 | llrintl: | ||
| 4 | 	fldt 4(%esp) | ||
| 5 | 	fistpll 4(%esp) | ||
| 6 | 	mov 4(%esp),%eax | ||
| 7 | 	mov 8(%esp),%edx | ||
| 8 | 	ret | ||
lib/libc/musl/src/math/i386/lrint.c created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long lrint(double x) | ||
| 4 | { | ||
| 5 | 	long r; | ||
| 6 | 	__asm__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); | ||
| 7 | 	return r; | ||
| 8 | } | ||
lib/libc/musl/src/math/i386/lrint.s deleted-7| ... | @@ -1,7 +0,0 @@ | ||
| 1 | .global lrint | ||
| 2 | .type lrint,@function | ||
| 3 | lrint: | ||
| 4 | 	fldl 4(%esp) | ||
| 5 | 	fistpl 4(%esp) | ||
| 6 | 	mov 4(%esp),%eax | ||
| 7 | 	ret | ||
lib/libc/musl/src/math/i386/lrintf.c created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long lrintf(float x) | ||
| 4 | { | ||
| 5 | 	long r; | ||
| 6 | 	__asm__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); | ||
| 7 | 	return r; | ||
| 8 | } | ||
lib/libc/musl/src/math/i386/lrintf.s deleted-7| ... | @@ -1,7 +0,0 @@ | ||
| 1 | .global lrintf | ||
| 2 | .type lrintf,@function | ||
| 3 | lrintf: | ||
| 4 | 	flds 4(%esp) | ||
| 5 | 	fistpl 4(%esp) | ||
| 6 | 	mov 4(%esp),%eax | ||
| 7 | 	ret | ||
lib/libc/musl/src/math/i386/lrintl.c created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long lrintl(long double x) | ||
| 4 | { | ||
| 5 | 	long r; | ||
| 6 | 	__asm__ ("fistpl %0" : "=m"(r) : "t"(x) : "st"); | ||
| 7 | 	return r; | ||
| 8 | } | ||
lib/libc/musl/src/math/i386/lrintl.s deleted-7| ... | @@ -1,7 +0,0 @@ | ||
| 1 | .global lrintl | ||
| 2 | .type lrintl,@function | ||
| 3 | lrintl: | ||
| 4 | 	fldt 4(%esp) | ||
| 5 | 	fistpl 4(%esp) | ||
| 6 | 	mov 4(%esp),%eax | ||
| 7 | 	ret | ||
lib/libc/musl/src/math/i386/remainder.c created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | double remainder(double x, double y) | ||
| 4 | { | ||
| 5 | 	unsigned short fpsr; | ||
| 6 | 	// fprem1 does not introduce excess precision into x | ||
| 7 | 	do __asm__ ("fprem1; fnstsw %%ax" : "+t"(x), "=a"(fpsr) : "u"(y)); | ||
| 8 | 	while (fpsr & 0x400); | ||
| 9 | 	return x; | ||
| 10 | } | ||
| 11 | |||
| 12 | weak_alias(remainder, drem); | ||
lib/libc/musl/src/math/i386/remainder.s deleted-14| ... | @@ -1,14 +0,0 @@ | ||
| 1 | .global remainder | ||
| 2 | .type remainder,@function | ||
| 3 | remainder: | ||
| 4 | .weak drem | ||
| 5 | .type drem,@function | ||
| 6 | drem: | ||
| 7 | 	fldl 12(%esp) | ||
| 8 | 	fldl 4(%esp) | ||
| 9 | 1:	fprem1 | ||
| 10 | 	fnstsw %ax | ||
| 11 | 	sahf | ||
| 12 | 	jp 1b | ||
| 13 | 	fstp %st(1) | ||
| 14 | 	ret | ||
lib/libc/musl/src/math/i386/remainderf.c created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | float remainderf(float x, float y) | ||
| 4 | { | ||
| 5 | 	unsigned short fpsr; | ||
| 6 | 	// fprem1 does not introduce excess precision into x | ||
| 7 | 	do __asm__ ("fprem1; fnstsw %%ax" : "+t"(x), "=a"(fpsr) : "u"(y)); | ||
| 8 | 	while (fpsr & 0x400); | ||
| 9 | 	return x; | ||
| 10 | } | ||
| 11 | |||
| 12 | weak_alias(remainderf, dremf); | ||
lib/libc/musl/src/math/i386/remainderf.s deleted-14| ... | @@ -1,14 +0,0 @@ | ||
| 1 | .global remainderf | ||
| 2 | .type remainderf,@function | ||
| 3 | remainderf: | ||
| 4 | .weak dremf | ||
| 5 | .type dremf,@function | ||
| 6 | dremf: | ||
| 7 | 	flds 8(%esp) | ||
| 8 | 	flds 4(%esp) | ||
| 9 | 1:	fprem1 | ||
| 10 | 	fnstsw %ax | ||
| 11 | 	sahf | ||
| 12 | 	jp 1b | ||
| 13 | 	fstp %st(1) | ||
| 14 | 	ret | ||
lib/libc/musl/src/math/i386/remainderl.c created+9| ... | @@ -0,0 +1,9 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long double remainderl(long double x, long double y) | ||
| 4 | { | ||
| 5 | 	unsigned short fpsr; | ||
| 6 | 	do __asm__ ("fprem1; fnstsw %%ax" : "+t"(x), "=a"(fpsr) : "u"(y)); | ||
| 7 | 	while (fpsr & 0x400); | ||
| 8 | 	return x; | ||
| 9 | } | ||
lib/libc/musl/src/math/i386/remainderl.s deleted-11| ... | @@ -1,11 +0,0 @@ | ||
| 1 | .global remainderl | ||
| 2 | .type remainderl,@function | ||
| 3 | remainderl: | ||
| 4 | 	fldt 16(%esp) | ||
| 5 | 	fldt 4(%esp) | ||
| 6 | 1:	fprem1 | ||
| 7 | 	fnstsw %ax | ||
| 8 | 	sahf | ||
| 9 | 	jp 1b | ||
| 10 | 	fstp %st(1) | ||
| 11 | 	ret | ||
lib/libc/musl/src/math/i386/rint.c created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | double rint(double x) | ||
| 4 | { | ||
| 5 | 	__asm__ ("frndint" : "+t"(x)); | ||
| 6 | 	return x; | ||
| 7 | } | ||
lib/libc/musl/src/math/i386/rint.s deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | .global rint | ||
| 2 | .type rint,@function | ||
| 3 | rint: | ||
| 4 | 	fldl 4(%esp) | ||
| 5 | 	frndint | ||
| 6 | 	ret | ||
lib/libc/musl/src/math/i386/rintf.c created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | float rintf(float x) | ||
| 4 | { | ||
| 5 | 	__asm__ ("frndint" : "+t"(x)); | ||
| 6 | 	return x; | ||
| 7 | } | ||
lib/libc/musl/src/math/i386/rintf.s deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | .global rintf | ||
| 2 | .type rintf,@function | ||
| 3 | rintf: | ||
| 4 | 	flds 4(%esp) | ||
| 5 | 	frndint | ||
| 6 | 	ret | ||
lib/libc/musl/src/math/i386/rintl.c created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long double rintl(long double x) | ||
| 4 | { | ||
| 5 | 	__asm__ ("frndint" : "+t"(x)); | ||
| 6 | 	return x; | ||
| 7 | } | ||
lib/libc/musl/src/math/i386/rintl.s deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | .global rintl | ||
| 2 | .type rintl,@function | ||
| 3 | rintl: | ||
| 4 | 	fldt 4(%esp) | ||
| 5 | 	frndint | ||
| 6 | 	ret | ||
lib/libc/musl/src/math/i386/sqrt.c created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | #include "libm.h" | ||
| 2 | |||
| 3 | double sqrt(double x) | ||
| 4 | { | ||
| 5 | 	union ldshape ux; | ||
| 6 | 	unsigned fpsr; | ||
| 7 | 	__asm__ ("fsqrt; fnstsw %%ax": "=t"(ux.f), "=a"(fpsr) : "0"(x)); | ||
| 8 | 	if ((ux.i.m & 0x7ff) != 0x400) | ||
| 9 | 		return (double)ux.f; | ||
| 10 | 	/* Rounding to double would have encountered an exact halfway case. | ||
| 11 | 	 Adjust mantissa downwards if fsqrt rounded up, else upwards. | ||
| 12 | 	 (result of fsqrt could not have been exact) */ | ||
| 13 | 	ux.i.m ^= (fpsr & 0x200) + 0x300; | ||
| 14 | 	return (double)ux.f; | ||
| 15 | } | ||
lib/libc/musl/src/math/i386/sqrt.s deleted-21| ... | @@ -1,21 +0,0 @@ | ||
| 1 | .global sqrt | ||
| 2 | .type sqrt,@function | ||
| 3 | sqrt:	fldl 4(%esp) | ||
| 4 | 	fsqrt | ||
| 5 | 	fnstsw %ax | ||
| 6 | 	sub $12,%esp | ||
| 7 | 	fld %st(0) | ||
| 8 | 	fstpt (%esp) | ||
| 9 | 	mov (%esp),%ecx | ||
| 10 | 	and $0x7ff,%ecx | ||
| 11 | 	cmp $0x400,%ecx | ||
| 12 | 	jnz 1f | ||
| 13 | 	and $0x200,%eax | ||
| 14 | 	sub $0x100,%eax | ||
| 15 | 	sub %eax,(%esp) | ||
| 16 | 	fstp %st(0) | ||
| 17 | 	fldt (%esp) | ||
| 18 | 1:	add $12,%esp | ||
| 19 | 	fstpl 4(%esp) | ||
| 20 | 	fldl 4(%esp) | ||
| 21 | 	ret | ||
lib/libc/musl/src/math/i386/sqrtf.c created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | float sqrtf(float x) | ||
| 4 | { | ||
| 5 | 	long double t; | ||
| 6 | 	/* The long double result has sufficient precision so that | ||
| 7 | 	 * second rounding to float still keeps the returned value | ||
| 8 | 	 * correctly rounded, see Pierre Roux, "Innocuous Double | ||
| 9 | 	 * Rounding of Basic Arithmetic Operations". */ | ||
| 10 | 	__asm__ ("fsqrt" : "=t"(t) : "0"(x)); | ||
| 11 | 	return (float)t; | ||
| 12 | } | ||
lib/libc/musl/src/math/i386/sqrtf.s deleted-7| ... | @@ -1,7 +0,0 @@ | ||
| 1 | .global sqrtf | ||
| 2 | .type sqrtf,@function | ||
| 3 | sqrtf:	flds 4(%esp) | ||
| 4 | 	fsqrt | ||
| 5 | 	fstps 4(%esp) | ||
| 6 | 	flds 4(%esp) | ||
| 7 | 	ret | ||
lib/libc/musl/src/math/i386/sqrtl.c created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long double sqrtl(long double x) | ||
| 4 | { | ||
| 5 | 	__asm__ ("fsqrt" : "+t"(x)); | ||
| 6 | 	return x; | ||
| 7 | } | ||
lib/libc/musl/src/math/i386/sqrtl.s deleted-5| ... | @@ -1,5 +0,0 @@ | ||
| 1 | .global sqrtl | ||
| 2 | .type sqrtl,@function | ||
| 3 | sqrtl:	fldt 4(%esp) | ||
| 4 | 	fsqrt | ||
| 5 | 	ret | ||
lib/libc/musl/src/math/m68k/sqrtl.c created+15| ... | @@ -0,0 +1,15 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | #if __HAVE_68881__ | ||
| 4 | |||
| 5 | long double sqrtl(long double x) | ||
| 6 | { | ||
| 7 | 	__asm__ ("fsqrt.x %1,%0" : "=f"(x) : "fm"(x)); | ||
| 8 | 	return x; | ||
| 9 | } | ||
| 10 | |||
| 11 | #else | ||
| 12 | |||
| 13 | #include "../sqrtl.c" | ||
| 14 | |||
| 15 | #endif | ||
lib/libc/musl/src/math/sinh.c+1-1| ... | @@ -34,6 +34,6 @@ double sinh(double x) | ... | @@ -34,6 +34,6 @@ double sinh(double x) |
| 34 | 34 | ||
| 35 | 	/* |x| > log(DBL_MAX) or nan */ | 35 | 	/* |x| > log(DBL_MAX) or nan */ |
| 36 | 	/* note: the result is stored to handle overflow */ | 36 | 	/* note: the result is stored to handle overflow */ |
| 37 | 	t = 2*h*__expo2(absx); | 37 | 	t = __expo2(absx, 2*h); |
| 38 | 	return t; | 38 | 	return t; |
| 39 | } | 39 | } |
lib/libc/musl/src/math/sinhf.c+1-1| ... | @@ -26,6 +26,6 @@ float sinhf(float x) | ... | @@ -26,6 +26,6 @@ float sinhf(float x) |
| 26 | 	} | 26 | 	} |
| 27 | 27 | ||
| 28 | 	/* |x| > logf(FLT_MAX) or nan */ | 28 | 	/* |x| > logf(FLT_MAX) or nan */ |
| 29 | 	t = 2*h*__expo2f(absx); | 29 | 	t = __expo2f(absx, 2*h); |
| 30 | 	return t; | 30 | 	return t; |
| 31 | } | 31 | } |
lib/libc/musl/src/math/x86_64/fabs.c created+10| ... | @@ -0,0 +1,10 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | double fabs(double x) | ||
| 4 | { | ||
| 5 | 	double t; | ||
| 6 | 	__asm__ ("pcmpeqd %0, %0" : "=x"(t)); // t = ~0 | ||
| 7 | 	__asm__ ("psrlq $1, %0" : "+x"(t)); // t >>= 1 | ||
| 8 | 	__asm__ ("andps %1, %0" : "+x"(x) : "x"(t)); // x &= t | ||
| 9 | 	return x; | ||
| 10 | } | ||
lib/libc/musl/src/math/x86_64/fabs.s deleted-9| ... | @@ -1,9 +0,0 @@ | ||
| 1 | .global fabs | ||
| 2 | .type fabs,@function | ||
| 3 | fabs: | ||
| 4 | 	xor %eax,%eax | ||
| 5 | 	dec %rax | ||
| 6 | 	shr %rax | ||
| 7 | 	movq %rax,%xmm1 | ||
| 8 | 	andpd %xmm1,%xmm0 | ||
| 9 | 	ret | ||
lib/libc/musl/src/math/x86_64/fabsf.c created+10| ... | @@ -0,0 +1,10 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | float fabsf(float x) | ||
| 4 | { | ||
| 5 | 	float t; | ||
| 6 | 	__asm__ ("pcmpeqd %0, %0" : "=x"(t)); // t = ~0 | ||
| 7 | 	__asm__ ("psrld $1, %0" : "+x"(t)); // t >>= 1 | ||
| 8 | 	__asm__ ("andps %1, %0" : "+x"(x) : "x"(t)); // x &= t | ||
| 9 | 	return x; | ||
| 10 | } | ||
lib/libc/musl/src/math/x86_64/fabsf.s deleted-7| ... | @@ -1,7 +0,0 @@ | ||
| 1 | .global fabsf | ||
| 2 | .type fabsf,@function | ||
| 3 | fabsf: | ||
| 4 | 	mov $0x7fffffff,%eax | ||
| 5 | 	movq %rax,%xmm1 | ||
| 6 | 	andps %xmm1,%xmm0 | ||
| 7 | 	ret | ||
lib/libc/musl/src/math/x86_64/fabsl.c created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long double fabsl(long double x) | ||
| 4 | { | ||
| 5 | 	__asm__ ("fabs" : "+t"(x)); | ||
| 6 | 	return x; | ||
| 7 | } | ||
lib/libc/musl/src/math/x86_64/fabsl.s deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | .global fabsl | ||
| 2 | .type fabsl,@function | ||
| 3 | fabsl: | ||
| 4 | 	fldt 8(%rsp) | ||
| 5 | 	fabs | ||
| 6 | 	ret | ||
lib/libc/musl/src/math/x86_64/fmodl.c created+9| ... | @@ -0,0 +1,9 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long double fmodl(long double x, long double y) | ||
| 4 | { | ||
| 5 | 	unsigned short fpsr; | ||
| 6 | 	do __asm__ ("fprem; fnstsw %%ax" : "+t"(x), "=a"(fpsr) : "u"(y)); | ||
| 7 | 	while (fpsr & 0x400); | ||
| 8 | 	return x; | ||
| 9 | } | ||
lib/libc/musl/src/math/x86_64/fmodl.s deleted-11| ... | @@ -1,11 +0,0 @@ | ||
| 1 | .global fmodl | ||
| 2 | .type fmodl,@function | ||
| 3 | fmodl: | ||
| 4 | 	fldt 24(%rsp) | ||
| 5 | 	fldt 8(%rsp) | ||
| 6 | 1:	fprem | ||
| 7 | 	fnstsw %ax | ||
| 8 | 	testb $4,%ah | ||
| 9 | 	jnz 1b | ||
| 10 | 	fstp %st(1) | ||
| 11 | 	ret | ||
lib/libc/musl/src/math/x86_64/llrint.c created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long long llrint(double x) | ||
| 4 | { | ||
| 5 | 	long long r; | ||
| 6 | 	__asm__ ("cvtsd2si %1, %0" : "=r"(r) : "x"(x)); | ||
| 7 | 	return r; | ||
| 8 | } | ||
lib/libc/musl/src/math/x86_64/llrint.s deleted-5| ... | @@ -1,5 +0,0 @@ | ||
| 1 | .global llrint | ||
| 2 | .type llrint,@function | ||
| 3 | llrint: | ||
| 4 | 	cvtsd2si %xmm0,%rax | ||
| 5 | 	ret | ||
lib/libc/musl/src/math/x86_64/llrintf.c created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long long llrintf(float x) | ||
| 4 | { | ||
| 5 | 	long long r; | ||
| 6 | 	__asm__ ("cvtss2si %1, %0" : "=r"(r) : "x"(x)); | ||
| 7 | 	return r; | ||
| 8 | } | ||
lib/libc/musl/src/math/x86_64/llrintf.s deleted-5| ... | @@ -1,5 +0,0 @@ | ||
| 1 | .global llrintf | ||
| 2 | .type llrintf,@function | ||
| 3 | llrintf: | ||
| 4 | 	cvtss2si %xmm0,%rax | ||
| 5 | 	ret | ||
lib/libc/musl/src/math/x86_64/llrintl.c created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long long llrintl(long double x) | ||
| 4 | { | ||
| 5 | 	long long r; | ||
| 6 | 	__asm__ ("fistpll %0" : "=m"(r) : "t"(x) : "st"); | ||
| 7 | 	return r; | ||
| 8 | } | ||
lib/libc/musl/src/math/x86_64/llrintl.s deleted-7| ... | @@ -1,7 +0,0 @@ | ||
| 1 | .global llrintl | ||
| 2 | .type llrintl,@function | ||
| 3 | llrintl: | ||
| 4 | 	fldt 8(%rsp) | ||
| 5 | 	fistpll 8(%rsp) | ||
| 6 | 	mov 8(%rsp),%rax | ||
| 7 | 	ret | ||
lib/libc/musl/src/math/x86_64/lrint.c created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long lrint(double x) | ||
| 4 | { | ||
| 5 | 	long r; | ||
| 6 | 	__asm__ ("cvtsd2si %1, %0" : "=r"(r) : "x"(x)); | ||
| 7 | 	return r; | ||
| 8 | } | ||
lib/libc/musl/src/math/x86_64/lrint.s deleted-5| ... | @@ -1,5 +0,0 @@ | ||
| 1 | .global lrint | ||
| 2 | .type lrint,@function | ||
| 3 | lrint: | ||
| 4 | 	cvtsd2si %xmm0,%rax | ||
| 5 | 	ret | ||
lib/libc/musl/src/math/x86_64/lrintf.c created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long lrintf(float x) | ||
| 4 | { | ||
| 5 | 	long r; | ||
| 6 | 	__asm__ ("cvtss2si %1, %0" : "=r"(r) : "x"(x)); | ||
| 7 | 	return r; | ||
| 8 | } | ||
lib/libc/musl/src/math/x86_64/lrintf.s deleted-5| ... | @@ -1,5 +0,0 @@ | ||
| 1 | .global lrintf | ||
| 2 | .type lrintf,@function | ||
| 3 | lrintf: | ||
| 4 | 	cvtss2si %xmm0,%rax | ||
| 5 | 	ret | ||
lib/libc/musl/src/math/x86_64/lrintl.c created+8| ... | @@ -0,0 +1,8 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long lrintl(long double x) | ||
| 4 | { | ||
| 5 | 	long r; | ||
| 6 | 	__asm__ ("fistpll %0" : "=m"(r) : "t"(x) : "st"); | ||
| 7 | 	return r; | ||
| 8 | } | ||
lib/libc/musl/src/math/x86_64/lrintl.s deleted-7| ... | @@ -1,7 +0,0 @@ | ||
| 1 | .global lrintl | ||
| 2 | .type lrintl,@function | ||
| 3 | lrintl: | ||
| 4 | 	fldt 8(%rsp) | ||
| 5 | 	fistpll 8(%rsp) | ||
| 6 | 	mov 8(%rsp),%rax | ||
| 7 | 	ret | ||
lib/libc/musl/src/math/x86_64/remainderl.c created+9| ... | @@ -0,0 +1,9 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long double remainderl(long double x, long double y) | ||
| 4 | { | ||
| 5 | 	unsigned short fpsr; | ||
| 6 | 	do __asm__ ("fprem1; fnstsw %%ax" : "+t"(x), "=a"(fpsr) : "u"(y)); | ||
| 7 | 	while (fpsr & 0x400); | ||
| 8 | 	return x; | ||
| 9 | } | ||
lib/libc/musl/src/math/x86_64/remainderl.s deleted-11| ... | @@ -1,11 +0,0 @@ | ||
| 1 | .global remainderl | ||
| 2 | .type remainderl,@function | ||
| 3 | remainderl: | ||
| 4 | 	fldt 24(%rsp) | ||
| 5 | 	fldt 8(%rsp) | ||
| 6 | 1:	fprem1 | ||
| 7 | 	fnstsw %ax | ||
| 8 | 	testb $4,%ah | ||
| 9 | 	jnz 1b | ||
| 10 | 	fstp %st(1) | ||
| 11 | 	ret | ||
lib/libc/musl/src/math/x86_64/remquol.c created+32| ... | @@ -0,0 +1,32 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long double remquol(long double x, long double y, int *quo) | ||
| 4 | { | ||
| 5 | 	signed char *cx = (void *)&x, *cy = (void *)&y; | ||
| 6 | 	/* By ensuring that addresses of x and y cannot be discarded, | ||
| 7 | 	 * this empty asm guides GCC into representing extraction of | ||
| 8 | 	 * their sign bits as memory loads rather than making x and y | ||
| 9 | 	 * not-address-taken internally and using bitfield operations, | ||
| 10 | 	 * which in the end wouldn't work out, as extraction from FPU | ||
| 11 | 	 * registers needs to go through memory anyway. This way GCC | ||
| 12 | 	 * should manage to use incoming stack slots without spills. */ | ||
| 13 | 	__asm__ ("" :: "X"(cx), "X"(cy)); | ||
| 14 | |||
| 15 | 	long double t = x; | ||
| 16 | 	unsigned fpsr; | ||
| 17 | 	do __asm__ ("fprem1; fnstsw %%ax" : "+t"(t), "=a"(fpsr) : "u"(y)); | ||
| 18 | 	while (fpsr & 0x400); | ||
| 19 | 	/* C0, C1, C3 flags in x87 status word carry low bits of quotient: | ||
| 20 | 	 * 15 14 13 12 11 10 9 8 | ||
| 21 | 	 * . C3 . . . C2 C1 C0 | ||
| 22 | 	 * . b1 . . . 0 b0 b2 */ | ||
| 23 | 	unsigned char i = fpsr >> 8; | ||
| 24 | 	i = i>>4 | i<<4; | ||
| 25 | 	/* i[5:2] is now {b0 b2 ? b1}. Retrieve {0 b2 b1 b0} via | ||
| 26 | 	 * in-register table lookup. */ | ||
| 27 | 	unsigned qbits = 0x7575313164642020 >> (i & 60); | ||
| 28 | 	qbits &= 7; | ||
| 29 | |||
| 30 | 	*quo = (cx[9]^cy[9]) < 0 ? -qbits : qbits; | ||
| 31 | 	return t; | ||
| 32 | } | ||
lib/libc/musl/src/math/x86_64/rintl.c created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long double rintl(long double x) | ||
| 4 | { | ||
| 5 | 	__asm__ ("frndint" : "+t"(x)); | ||
| 6 | 	return x; | ||
| 7 | } | ||
lib/libc/musl/src/math/x86_64/rintl.s deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | .global rintl | ||
| 2 | .type rintl,@function | ||
| 3 | rintl: | ||
| 4 | 	fldt 8(%rsp) | ||
| 5 | 	frndint | ||
| 6 | 	ret | ||
lib/libc/musl/src/math/x86_64/sqrt.c created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | double sqrt(double x) | ||
| 4 | { | ||
| 5 | 	__asm__ ("sqrtsd %1, %0" : "=x"(x) : "x"(x)); | ||
| 6 | 	return x; | ||
| 7 | } | ||
lib/libc/musl/src/math/x86_64/sqrt.s deleted-4| ... | @@ -1,4 +0,0 @@ | ||
| 1 | .global sqrt | ||
| 2 | .type sqrt,@function | ||
| 3 | sqrt:	sqrtsd %xmm0, %xmm0 | ||
| 4 | 	ret | ||
lib/libc/musl/src/math/x86_64/sqrtf.c created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | float sqrtf(float x) | ||
| 4 | { | ||
| 5 | 	__asm__ ("sqrtss %1, %0" : "=x"(x) : "x"(x)); | ||
| 6 | 	return x; | ||
| 7 | } | ||
lib/libc/musl/src/math/x86_64/sqrtf.s deleted-4| ... | @@ -1,4 +0,0 @@ | ||
| 1 | .global sqrtf | ||
| 2 | .type sqrtf,@function | ||
| 3 | sqrtf: sqrtss %xmm0, %xmm0 | ||
| 4 | 	ret | ||
lib/libc/musl/src/math/x86_64/sqrtl.c created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | #include <math.h> | ||
| 2 | |||
| 3 | long double sqrtl(long double x) | ||
| 4 | { | ||
| 5 | 	__asm__ ("fsqrt" : "+t"(x)); | ||
| 6 | 	return x; | ||
| 7 | } | ||
lib/libc/musl/src/math/x86_64/sqrtl.s deleted-5| ... | @@ -1,5 +0,0 @@ | ||
| 1 | .global sqrtl | ||
| 2 | .type sqrtl,@function | ||
| 3 | sqrtl:	fldt 8(%rsp) | ||
| 4 | 	fsqrt | ||
| 5 | 	ret | ||
lib/libc/musl/src/misc/getentropy.c+1-1| ... | @@ -6,7 +6,7 @@ | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | ||
| 7 | int getentropy(void *buffer, size_t len) | 7 | int getentropy(void *buffer, size_t len) |
| 8 | { | 8 | { |
| 9 | 	int cs, ret; | 9 | 	int cs, ret = 0; |
| 10 | 	char *pos = buffer; | 10 | 	char *pos = buffer; |
| 11 | 11 | ||
| 12 | 	if (len > 256) { | 12 | 	if (len > 256) { |
lib/libc/musl/src/misc/nftw.c+18-4| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | #include <ftw.h> | 1 | #include <ftw.h> |
| 2 | #include <dirent.h> | 2 | #include <dirent.h> |
| 3 | #include <fcntl.h> | ||
| 3 | #include <sys/stat.h> | 4 | #include <sys/stat.h> |
| 4 | #include <errno.h> | 5 | #include <errno.h> |
| 5 | #include <unistd.h> | 6 | #include <unistd.h> |
| ... | @@ -26,6 +27,8 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, | ... | @@ -26,6 +27,8 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, |
| 26 | 	struct history new; | 27 | 	struct history new; |
| 27 | 	int type; | 28 | 	int type; |
| 28 | 	int r; | 29 | 	int r; |
| 30 | 	int dfd; | ||
| 31 | 	int err; | ||
| 29 | 	struct FTW lev; | 32 | 	struct FTW lev; |
| 30 | 33 | ||
| 31 | 	if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) { | 34 | 	if ((flags & FTW_PHYS) ? lstat(path, &st) : stat(path, &st) < 0) { |
| ... | @@ -34,8 +37,7 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, | ... | @@ -34,8 +37,7 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, |
| 34 | 		else if (errno != EACCES) return -1; | 37 | 		else if (errno != EACCES) return -1; |
| 35 | 		else type = FTW_NS; | 38 | 		else type = FTW_NS; |
| 36 | 	} else if (S_ISDIR(st.st_mode)) { | 39 | 	} else if (S_ISDIR(st.st_mode)) { |
| 37 | 		if (access(path, R_OK) < 0) type = FTW_DNR; | 40 | 		if (flags & FTW_DEPTH) type = FTW_DP; |
| 38 | 		else if (flags & FTW_DEPTH) type = FTW_DP; | ||
| 39 | 		else type = FTW_D; | 41 | 		else type = FTW_D; |
| 40 | 	} else if (S_ISLNK(st.st_mode)) { | 42 | 	} else if (S_ISLNK(st.st_mode)) { |
| 41 | 		if (flags & FTW_PHYS) type = FTW_SL; | 43 | 		if (flags & FTW_PHYS) type = FTW_SL; |
| ... | @@ -63,6 +65,13 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, | ... | @@ -63,6 +65,13 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, |
| 63 | 		lev.base = k; | 65 | 		lev.base = k; |
| 64 | 	} | 66 | 	} |
| 65 | 67 | ||
| 68 | 	if (type == FTW_D || type == FTW_DP) { | ||
| 69 | 		dfd = open(path, O_RDONLY); | ||
| 70 | 		err = errno; | ||
| 71 | 		if (dfd < 0 && err == EACCES) type = FTW_DNR; | ||
| 72 | 		if (!fd_limit) close(dfd); | ||
| 73 | 	} | ||
| 74 | |||
| 66 | 	if (!(flags & FTW_DEPTH) && (r=fn(path, &st, type, &lev))) | 75 | 	if (!(flags & FTW_DEPTH) && (r=fn(path, &st, type, &lev))) |
| 67 | 		return r; | 76 | 		return r; |
| 68 | 77 | ||
| ... | @@ -71,7 +80,11 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, | ... | @@ -71,7 +80,11 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, |
| 71 | 			return 0; | 80 | 			return 0; |
| 72 | 81 | ||
| 73 | 	if ((type == FTW_D || type == FTW_DP) && fd_limit) { | 82 | 	if ((type == FTW_D || type == FTW_DP) && fd_limit) { |
| 74 | 		DIR *d = opendir(path); | 83 | 		if (dfd < 0) { |
| 84 | 			errno = err; | ||
| 85 | 			return -1; | ||
| 86 | 		} | ||
| 87 | 		DIR *d = fdopendir(dfd); | ||
| 75 | 		if (d) { | 88 | 		if (d) { |
| 76 | 			struct dirent *de; | 89 | 			struct dirent *de; |
| 77 | 			while ((de = readdir(d))) { | 90 | 			while ((de = readdir(d))) { |
| ... | @@ -92,7 +105,8 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, | ... | @@ -92,7 +105,8 @@ static int do_nftw(char *path, int (*fn)(const char *, const struct stat *, int, |
| 92 | 				} | 105 | 				} |
| 93 | 			} | 106 | 			} |
| 94 | 			closedir(d); | 107 | 			closedir(d); |
| 95 | 		} else if (errno != EACCES) { | 108 | 		} else { |
| 109 | 			close(dfd); | ||
| 96 | 			return -1; | 110 | 			return -1; |
| 97 | 		} | 111 | 		} |
| 98 | 	} | 112 | 	} |
lib/libc/musl/src/network/getnameinfo.c+1| ... | @@ -158,6 +158,7 @@ int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl, | ... | @@ -158,6 +158,7 @@ int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl, |
| 158 | 			unsigned char query[18+PTR_MAX], reply[512]; | 158 | 			unsigned char query[18+PTR_MAX], reply[512]; |
| 159 | 			int qlen = __res_mkquery(0, ptr, 1, RR_PTR, | 159 | 			int qlen = __res_mkquery(0, ptr, 1, RR_PTR, |
| 160 | 				0, 0, 0, query, sizeof query); | 160 | 				0, 0, 0, query, sizeof query); |
| 161 | 			query[3] = 0; /* don't need AD flag */ | ||
| 161 | 			int rlen = __res_send(query, qlen, reply, sizeof reply); | 162 | 			int rlen = __res_send(query, qlen, reply, sizeof reply); |
| 162 | 			buf[0] = 0; | 163 | 			buf[0] = 0; |
| 163 | 			if (rlen > 0) | 164 | 			if (rlen > 0) |
lib/libc/musl/src/network/lookup_name.c+8-4| ... | @@ -149,6 +149,7 @@ static int name_from_dns(struct address buf[static MAXADDRS], char canon[static | ... | @@ -149,6 +149,7 @@ static int name_from_dns(struct address buf[static MAXADDRS], char canon[static |
| 149 | 				0, 0, 0, qbuf[nq], sizeof *qbuf); | 149 | 				0, 0, 0, qbuf[nq], sizeof *qbuf); |
| 150 | 			if (qlens[nq] == -1) | 150 | 			if (qlens[nq] == -1) |
| 151 | 				return EAI_NONAME; | 151 | 				return EAI_NONAME; |
| 152 | 			qbuf[nq][3] = 0; /* don't need AD flag */ | ||
| 152 | 			nq++; | 153 | 			nq++; |
| 153 | 		} | 154 | 		} |
| 154 | 	} | 155 | 	} |
| ... | @@ -156,14 +157,17 @@ static int name_from_dns(struct address buf[static MAXADDRS], char canon[static | ... | @@ -156,14 +157,17 @@ static int name_from_dns(struct address buf[static MAXADDRS], char canon[static |
| 156 | 	if (__res_msend_rc(nq, qp, qlens, ap, alens, sizeof *abuf, conf) < 0) | 157 | 	if (__res_msend_rc(nq, qp, qlens, ap, alens, sizeof *abuf, conf) < 0) |
| 157 | 		return EAI_SYSTEM; | 158 | 		return EAI_SYSTEM; |
| 158 | 159 | ||
| 160 | 	for (i=0; i<nq; i++) { | ||
| 161 | 		if (alens[i] < 4 || (abuf[i][3] & 15) == 2) return EAI_AGAIN; | ||
| 162 | 		if ((abuf[i][3] & 15) == 3) return 0; | ||
| 163 | 		if ((abuf[i][3] & 15) != 0) return EAI_FAIL; | ||
| 164 | 	} | ||
| 165 | |||
| 159 | 	for (i=0; i<nq; i++) | 166 | 	for (i=0; i<nq; i++) |
| 160 | 		__dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx); | 167 | 		__dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx); |
| 161 | 168 | ||
| 162 | 	if (ctx.cnt) return ctx.cnt; | 169 | 	if (ctx.cnt) return ctx.cnt; |
| 163 | 	if (alens[0] < 4 || (abuf[0][3] & 15) == 2) return EAI_AGAIN; | 170 | 	return EAI_NONAME; |
| 164 | 	if ((abuf[0][3] & 15) == 0) return EAI_NONAME; | ||
| 165 | 	if ((abuf[0][3] & 15) == 3) return 0; | ||
| 166 | 	return EAI_FAIL; | ||
| 167 | } | 171 | } |
| 168 | 172 | ||
| 169 | static int name_from_dns_search(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family) | 173 | static int name_from_dns_search(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family) |
lib/libc/musl/src/network/res_mkquery.c+1| ... | @@ -20,6 +20,7 @@ int __res_mkquery(int op, const char *dname, int class, int type, | ... | @@ -20,6 +20,7 @@ int __res_mkquery(int op, const char *dname, int class, int type, |
| 20 | 	/* Construct query template - ID will be filled later */ | 20 | 	/* Construct query template - ID will be filled later */ |
| 21 | 	memset(q, 0, n); | 21 | 	memset(q, 0, n); |
| 22 | 	q[2] = op*8 + 1; | 22 | 	q[2] = op*8 + 1; |
| 23 | 	q[3] = 32; /* AD */ | ||
| 23 | 	q[5] = 1; | 24 | 	q[5] = 1; |
| 24 | 	memcpy((char *)q+13, dname, l); | 25 | 	memcpy((char *)q+13, dname, l); |
| 25 | 	for (i=13; q[i]; i=j+1) { | 26 | 	for (i=13; q[i]; i=j+1) { |
lib/libc/musl/src/network/res_send.c+1-1| ... | @@ -3,7 +3,7 @@ | ... | @@ -3,7 +3,7 @@ |
| 3 | int __res_send(const unsigned char *msg, int msglen, unsigned char *answer, int anslen) | 3 | int __res_send(const unsigned char *msg, int msglen, unsigned char *answer, int anslen) |
| 4 | { | 4 | { |
| 5 | 	int r = __res_msend(1, &msg, &msglen, &answer, &anslen, anslen); | 5 | 	int r = __res_msend(1, &msg, &msglen, &answer, &anslen, anslen); |
| 6 | 	return r<0 ? r : anslen; | 6 | 	return r<0 || !anslen ? -1 : anslen; |
| 7 | } | 7 | } |
| 8 | 8 | ||
| 9 | weak_alias(__res_send, res_send); | 9 | weak_alias(__res_send, res_send); |
lib/libc/musl/src/network/socket.c+5-5| ... | @@ -5,17 +5,17 @@ | ... | @@ -5,17 +5,17 @@ |
| 5 | 5 | ||
| 6 | int socket(int domain, int type, int protocol) | 6 | int socket(int domain, int type, int protocol) |
| 7 | { | 7 | { |
| 8 | 	int s = socketcall(socket, domain, type, protocol, 0, 0, 0); | 8 | 	int s = __socketcall(socket, domain, type, protocol, 0, 0, 0); |
| 9 | 	if (s<0 && (errno==EINVAL || errno==EPROTONOSUPPORT) | 9 | 	if ((s==-EINVAL || s==-EPROTONOSUPPORT) |
| 10 | 	 && (type&(SOCK_CLOEXEC|SOCK_NONBLOCK))) { | 10 | 	 && (type&(SOCK_CLOEXEC|SOCK_NONBLOCK))) { |
| 11 | 		s = socketcall(socket, domain, | 11 | 		s = __socketcall(socket, domain, |
| 12 | 			type & ~(SOCK_CLOEXEC|SOCK_NONBLOCK), | 12 | 			type & ~(SOCK_CLOEXEC|SOCK_NONBLOCK), |
| 13 | 			protocol, 0, 0, 0); | 13 | 			protocol, 0, 0, 0); |
| 14 | 		if (s < 0) return s; | 14 | 		if (s < 0) return __syscall_ret(s); |
| 15 | 		if (type & SOCK_CLOEXEC) | 15 | 		if (type & SOCK_CLOEXEC) |
| 16 | 			__syscall(SYS_fcntl, s, F_SETFD, FD_CLOEXEC); | 16 | 			__syscall(SYS_fcntl, s, F_SETFD, FD_CLOEXEC); |
| 17 | 		if (type & SOCK_NONBLOCK) | 17 | 		if (type & SOCK_NONBLOCK) |
| 18 | 			__syscall(SYS_fcntl, s, F_SETFL, O_NONBLOCK); | 18 | 			__syscall(SYS_fcntl, s, F_SETFL, O_NONBLOCK); |
| 19 | 	} | 19 | 	} |
| 20 | 	return s; | 20 | 	return __syscall_ret(s); |
| 21 | } | 21 | } |
lib/libc/musl/src/process/fork.c+1| ... | @@ -30,6 +30,7 @@ pid_t fork(void) | ... | @@ -30,6 +30,7 @@ pid_t fork(void) |
| 30 | 		self->next = self->prev = self; | 30 | 		self->next = self->prev = self; |
| 31 | 		__thread_list_lock = 0; | 31 | 		__thread_list_lock = 0; |
| 32 | 		libc.threads_minus_1 = 0; | 32 | 		libc.threads_minus_1 = 0; |
| 33 | 		if (libc.need_locks) libc.need_locks = -1; | ||
| 33 | 	} | 34 | 	} |
| 34 | 	__restore_sigs(&set); | 35 | 	__restore_sigs(&set); |
| 35 | 	__fork_handler(!ret); | 36 | 	__fork_handler(!ret); |
lib/libc/musl/src/stdio/__string_read.c deleted-16| ... | @@ -1,16 +0,0 @@ | ||
| 1 | #include "stdio_impl.h" | ||
| 2 | #include <string.h> | ||
| 3 | |||
| 4 | size_t __string_read(FILE *f, unsigned char *buf, size_t len) | ||
| 5 | { | ||
| 6 | 	char *src = f->cookie; | ||
| 7 | 	size_t k = len+256; | ||
| 8 | 	char *end = memchr(src, 0, k); | ||
| 9 | 	if (end) k = end-src; | ||
| 10 | 	if (k < len) len = k; | ||
| 11 | 	memcpy(buf, src, len); | ||
| 12 | 	f->rpos = (void *)(src+len); | ||
| 13 | 	f->rend = (void *)(src+k); | ||
| 14 | 	f->cookie = src+k; | ||
| 15 | 	return len; | ||
| 16 | } | ||
lib/libc/musl/src/stdio/fmemopen.c+3-3| ... | @@ -2,6 +2,7 @@ | ... | @@ -2,6 +2,7 @@ |
| 2 | #include <errno.h> | 2 | #include <errno.h> |
| 3 | #include <string.h> | 3 | #include <string.h> |
| 4 | #include <stdlib.h> | 4 | #include <stdlib.h> |
| 5 | #include <stddef.h> | ||
| 5 | #include <inttypes.h> | 6 | #include <inttypes.h> |
| 6 | #include "libc.h" | 7 | #include "libc.h" |
| 7 | 8 | ||
| ... | @@ -95,18 +96,17 @@ FILE *fmemopen(void *restrict buf, size_t size, const char *restrict mode) | ... | @@ -95,18 +96,17 @@ FILE *fmemopen(void *restrict buf, size_t size, const char *restrict mode) |
| 95 | 96 | ||
| 96 | 	f = malloc(sizeof *f + (buf?0:size)); | 97 | 	f = malloc(sizeof *f + (buf?0:size)); |
| 97 | 	if (!f) return 0; | 98 | 	if (!f) return 0; |
| 98 | 	memset(&f->f, 0, sizeof f->f); | 99 | 	memset(f, 0, offsetof(struct mem_FILE, buf)); |
| 99 | 	f->f.cookie = &f->c; | 100 | 	f->f.cookie = &f->c; |
| 100 | 	f->f.fd = -1; | 101 | 	f->f.fd = -1; |
| 101 | 	f->f.lbf = EOF; | 102 | 	f->f.lbf = EOF; |
| 102 | 	f->f.buf = f->buf + UNGET; | 103 | 	f->f.buf = f->buf + UNGET; |
| 103 | 	f->f.buf_size = sizeof f->buf - UNGET; | 104 | 	f->f.buf_size = sizeof f->buf - UNGET; |
| 104 | 	if (!buf) { | 105 | 	if (!buf) { |
| 105 | 		buf = f->buf2;; | 106 | 		buf = f->buf2; |
| 106 | 		memset(buf, 0, size); | 107 | 		memset(buf, 0, size); |
| 107 | 	} | 108 | 	} |
| 108 | 109 | ||
| 109 | 	memset(&f->c, 0, sizeof f->c); | ||
| 110 | 	f->c.buf = buf; | 110 | 	f->c.buf = buf; |
| 111 | 	f->c.size = size; | 111 | 	f->c.size = size; |
| 112 | 	f->c.mode = *mode; | 112 | 	f->c.mode = *mode; |
lib/libc/musl/src/stdio/vdprintf.c+1-6| ... | @@ -1,14 +1,9 @@ | ... | @@ -1,14 +1,9 @@ |
| 1 | #include "stdio_impl.h" | 1 | #include "stdio_impl.h" |
| 2 | 2 | ||
| 3 | static size_t wrap_write(FILE *f, const unsigned char *buf, size_t len) | ||
| 4 | { | ||
| 5 | 	return __stdio_write(f, buf, len); | ||
| 6 | } | ||
| 7 | |||
| 8 | int vdprintf(int fd, const char *restrict fmt, va_list ap) | 3 | int vdprintf(int fd, const char *restrict fmt, va_list ap) |
| 9 | { | 4 | { |
| 10 | 	FILE f = { | 5 | 	FILE f = { |
| 11 | 		.fd = fd, .lbf = EOF, .write = wrap_write, | 6 | 		.fd = fd, .lbf = EOF, .write = __stdio_write, |
| 12 | 		.buf = (void *)fmt, .buf_size = 0, | 7 | 		.buf = (void *)fmt, .buf_size = 0, |
| 13 | 		.lock = -1 | 8 | 		.lock = -1 |
| 14 | 	}; | 9 | 	}; |
lib/libc/musl/src/stdio/vfscanf.c+4-1| ... | @@ -57,7 +57,7 @@ int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap) | ... | @@ -57,7 +57,7 @@ int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap) |
| 57 | { | 57 | { |
| 58 | 	int width; | 58 | 	int width; |
| 59 | 	int size; | 59 | 	int size; |
| 60 | 	int alloc; | 60 | 	int alloc = 0; |
| 61 | 	int base; | 61 | 	int base; |
| 62 | 	const unsigned char *p; | 62 | 	const unsigned char *p; |
| 63 | 	int c, t; | 63 | 	int c, t; |
| ... | @@ -76,6 +76,9 @@ int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap) | ... | @@ -76,6 +76,9 @@ int vfscanf(FILE *restrict f, const char *restrict fmt, va_list ap) |
| 76 | 76 | ||
| 77 | 	FLOCK(f); | 77 | 	FLOCK(f); |
| 78 | 78 | ||
| 79 | 	if (!f->rpos) __toread(f); | ||
| 80 | 	if (!f->rpos) goto input_fail; | ||
| 81 | |||
| 79 | 	for (p=(const unsigned char *)fmt; *p; p++) { | 82 | 	for (p=(const unsigned char *)fmt; *p; p++) { |
| 80 | 83 | ||
| 81 | 		alloc = 0; | 84 | 		alloc = 0; |
lib/libc/musl/src/stdio/vsscanf.c+13-3| ... | @@ -1,15 +1,25 @@ | ... | @@ -1,15 +1,25 @@ |
| 1 | #include "stdio_impl.h" | 1 | #include "stdio_impl.h" |
| 2 | #include <string.h> | ||
| 2 | 3 | ||
| 3 | static size_t do_read(FILE *f, unsigned char *buf, size_t len) | 4 | static size_t string_read(FILE *f, unsigned char *buf, size_t len) |
| 4 | { | 5 | { |
| 5 | 	return __string_read(f, buf, len); | 6 | 	char *src = f->cookie; |
| 7 | 	size_t k = len+256; | ||
| 8 | 	char *end = memchr(src, 0, k); | ||
| 9 | 	if (end) k = end-src; | ||
| 10 | 	if (k < len) len = k; | ||
| 11 | 	memcpy(buf, src, len); | ||
| 12 | 	f->rpos = (void *)(src+len); | ||
| 13 | 	f->rend = (void *)(src+k); | ||
| 14 | 	f->cookie = src+k; | ||
| 15 | 	return len; | ||
| 6 | } | 16 | } |
| 7 | 17 | ||
| 8 | int vsscanf(const char *restrict s, const char *restrict fmt, va_list ap) | 18 | int vsscanf(const char *restrict s, const char *restrict fmt, va_list ap) |
| 9 | { | 19 | { |
| 10 | 	FILE f = { | 20 | 	FILE f = { |
| 11 | 		.buf = (void *)s, .cookie = (void *)s, | 21 | 		.buf = (void *)s, .cookie = (void *)s, |
| 12 | 		.read = do_read, .lock = -1 | 22 | 		.read = string_read, .lock = -1 |
| 13 | 	}; | 23 | 	}; |
| 14 | 	return vfscanf(&f, fmt, ap); | 24 | 	return vfscanf(&f, fmt, ap); |
| 15 | } | 25 | } |
lib/libc/musl/src/stdlib/wcstod.c+1-2| ... | @@ -33,8 +33,7 @@ static long double wcstox(const wchar_t *s, wchar_t **p, int prec) | ... | @@ -33,8 +33,7 @@ static long double wcstox(const wchar_t *s, wchar_t **p, int prec) |
| 33 | 	unsigned char buf[64]; | 33 | 	unsigned char buf[64]; |
| 34 | 	FILE f = {0}; | 34 | 	FILE f = {0}; |
| 35 | 	f.flags = 0; | 35 | 	f.flags = 0; |
| 36 | 	f.rpos = f.rend = 0; | 36 | 	f.rpos = f.rend = f.buf = buf + 4; |
| 37 | 	f.buf = buf + 4; | ||
| 38 | 	f.buf_size = sizeof buf - 4; | 37 | 	f.buf_size = sizeof buf - 4; |
| 39 | 	f.lock = -1; | 38 | 	f.lock = -1; |
| 40 | 	f.read = do_read; | 39 | 	f.read = do_read; |
lib/libc/musl/src/stdlib/wcstol.c+1-2| ... | @@ -35,8 +35,7 @@ static unsigned long long wcstox(const wchar_t *s, wchar_t **p, int base, unsign | ... | @@ -35,8 +35,7 @@ static unsigned long long wcstox(const wchar_t *s, wchar_t **p, int base, unsign |
| 35 | 	unsigned char buf[64]; | 35 | 	unsigned char buf[64]; |
| 36 | 	FILE f = {0}; | 36 | 	FILE f = {0}; |
| 37 | 	f.flags = 0; | 37 | 	f.flags = 0; |
| 38 | 	f.rpos = f.rend = 0; | 38 | 	f.rpos = f.rend = f.buf = buf + 4; |
| 39 | 	f.buf = buf + 4; | ||
| 40 | 	f.buf_size = sizeof buf - 4; | 39 | 	f.buf_size = sizeof buf - 4; |
| 41 | 	f.lock = -1; | 40 | 	f.lock = -1; |
| 42 | 	f.read = do_read; | 41 | 	f.read = do_read; |
lib/libc/musl/src/string/aarch64/memcpy.S created+186| ... | @@ -0,0 +1,186 @@ | ||
| 1 | /* | ||
| 2 | * memcpy - copy memory area | ||
| 3 | * | ||
| 4 | * Copyright (c) 2012-2020, Arm Limited. | ||
| 5 | * SPDX-License-Identifier: MIT | ||
| 6 | */ | ||
| 7 | |||
| 8 | /* Assumptions: | ||
| 9 | * | ||
| 10 | * ARMv8-a, AArch64, unaligned accesses. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #define dstin x0 | ||
| 15 | #define src x1 | ||
| 16 | #define count x2 | ||
| 17 | #define dst x3 | ||
| 18 | #define srcend x4 | ||
| 19 | #define dstend x5 | ||
| 20 | #define A_l x6 | ||
| 21 | #define A_lw w6 | ||
| 22 | #define A_h x7 | ||
| 23 | #define B_l x8 | ||
| 24 | #define B_lw w8 | ||
| 25 | #define B_h x9 | ||
| 26 | #define C_l x10 | ||
| 27 | #define C_lw w10 | ||
| 28 | #define C_h x11 | ||
| 29 | #define D_l x12 | ||
| 30 | #define D_h x13 | ||
| 31 | #define E_l x14 | ||
| 32 | #define E_h x15 | ||
| 33 | #define F_l x16 | ||
| 34 | #define F_h x17 | ||
| 35 | #define G_l count | ||
| 36 | #define G_h dst | ||
| 37 | #define H_l src | ||
| 38 | #define H_h srcend | ||
| 39 | #define tmp1 x14 | ||
| 40 | |||
| 41 | /* This implementation of memcpy uses unaligned accesses and branchless | ||
| 42 | sequences to keep the code small, simple and improve performance. | ||
| 43 | |||
| 44 | Copies are split into 3 main cases: small copies of up to 32 bytes, medium | ||
| 45 | copies of up to 128 bytes, and large copies. The overhead of the overlap | ||
| 46 | check is negligible since it is only required for large copies. | ||
| 47 | |||
| 48 | Large copies use a software pipelined loop processing 64 bytes per iteration. | ||
| 49 | The destination pointer is 16-byte aligned to minimize unaligned accesses. | ||
| 50 | The loop tail is handled by always copying 64 bytes from the end. | ||
| 51 | */ | ||
| 52 | |||
| 53 | .global memcpy | ||
| 54 | .type memcpy,%function | ||
| 55 | memcpy: | ||
| 56 | 	add srcend, src, count | ||
| 57 | 	add dstend, dstin, count | ||
| 58 | 	cmp count, 128 | ||
| 59 | 	b.hi .Lcopy_long | ||
| 60 | 	cmp count, 32 | ||
| 61 | 	b.hi .Lcopy32_128 | ||
| 62 | |||
| 63 | 	/* Small copies: 0..32 bytes. */ | ||
| 64 | 	cmp count, 16 | ||
| 65 | 	b.lo .Lcopy16 | ||
| 66 | 	ldp A_l, A_h, [src] | ||
| 67 | 	ldp D_l, D_h, [srcend, -16] | ||
| 68 | 	stp A_l, A_h, [dstin] | ||
| 69 | 	stp D_l, D_h, [dstend, -16] | ||
| 70 | 	ret | ||
| 71 | |||
| 72 | 	/* Copy 8-15 bytes. */ | ||
| 73 | .Lcopy16: | ||
| 74 | 	tbz count, 3, .Lcopy8 | ||
| 75 | 	ldr A_l, [src] | ||
| 76 | 	ldr A_h, [srcend, -8] | ||
| 77 | 	str A_l, [dstin] | ||
| 78 | 	str A_h, [dstend, -8] | ||
| 79 | 	ret | ||
| 80 | |||
| 81 | 	.p2align 3 | ||
| 82 | 	/* Copy 4-7 bytes. */ | ||
| 83 | .Lcopy8: | ||
| 84 | 	tbz count, 2, .Lcopy4 | ||
| 85 | 	ldr A_lw, [src] | ||
| 86 | 	ldr B_lw, [srcend, -4] | ||
| 87 | 	str A_lw, [dstin] | ||
| 88 | 	str B_lw, [dstend, -4] | ||
| 89 | 	ret | ||
| 90 | |||
| 91 | 	/* Copy 0..3 bytes using a branchless sequence. */ | ||
| 92 | .Lcopy4: | ||
| 93 | 	cbz count, .Lcopy0 | ||
| 94 | 	lsr tmp1, count, 1 | ||
| 95 | 	ldrb A_lw, [src] | ||
| 96 | 	ldrb C_lw, [srcend, -1] | ||
| 97 | 	ldrb B_lw, [src, tmp1] | ||
| 98 | 	strb A_lw, [dstin] | ||
| 99 | 	strb B_lw, [dstin, tmp1] | ||
| 100 | 	strb C_lw, [dstend, -1] | ||
| 101 | .Lcopy0: | ||
| 102 | 	ret | ||
| 103 | |||
| 104 | 	.p2align 4 | ||
| 105 | 	/* Medium copies: 33..128 bytes. */ | ||
| 106 | .Lcopy32_128: | ||
| 107 | 	ldp A_l, A_h, [src] | ||
| 108 | 	ldp B_l, B_h, [src, 16] | ||
| 109 | 	ldp C_l, C_h, [srcend, -32] | ||
| 110 | 	ldp D_l, D_h, [srcend, -16] | ||
| 111 | 	cmp count, 64 | ||
| 112 | 	b.hi .Lcopy128 | ||
| 113 | 	stp A_l, A_h, [dstin] | ||
| 114 | 	stp B_l, B_h, [dstin, 16] | ||
| 115 | 	stp C_l, C_h, [dstend, -32] | ||
| 116 | 	stp D_l, D_h, [dstend, -16] | ||
| 117 | 	ret | ||
| 118 | |||
| 119 | 	.p2align 4 | ||
| 120 | 	/* Copy 65..128 bytes. */ | ||
| 121 | .Lcopy128: | ||
| 122 | 	ldp E_l, E_h, [src, 32] | ||
| 123 | 	ldp F_l, F_h, [src, 48] | ||
| 124 | 	cmp count, 96 | ||
| 125 | 	b.ls .Lcopy96 | ||
| 126 | 	ldp G_l, G_h, [srcend, -64] | ||
| 127 | 	ldp H_l, H_h, [srcend, -48] | ||
| 128 | 	stp G_l, G_h, [dstend, -64] | ||
| 129 | 	stp H_l, H_h, [dstend, -48] | ||
| 130 | .Lcopy96: | ||
| 131 | 	stp A_l, A_h, [dstin] | ||
| 132 | 	stp B_l, B_h, [dstin, 16] | ||
| 133 | 	stp E_l, E_h, [dstin, 32] | ||
| 134 | 	stp F_l, F_h, [dstin, 48] | ||
| 135 | 	stp C_l, C_h, [dstend, -32] | ||
| 136 | 	stp D_l, D_h, [dstend, -16] | ||
| 137 | 	ret | ||
| 138 | |||
| 139 | 	.p2align 4 | ||
| 140 | 	/* Copy more than 128 bytes. */ | ||
| 141 | .Lcopy_long: | ||
| 142 | |||
| 143 | 	/* Copy 16 bytes and then align dst to 16-byte alignment. */ | ||
| 144 | |||
| 145 | 	ldp D_l, D_h, [src] | ||
| 146 | 	and tmp1, dstin, 15 | ||
| 147 | 	bic dst, dstin, 15 | ||
| 148 | 	sub src, src, tmp1 | ||
| 149 | 	add count, count, tmp1 /* Count is now 16 too large. */ | ||
| 150 | 	ldp A_l, A_h, [src, 16] | ||
| 151 | 	stp D_l, D_h, [dstin] | ||
| 152 | 	ldp B_l, B_h, [src, 32] | ||
| 153 | 	ldp C_l, C_h, [src, 48] | ||
| 154 | 	ldp D_l, D_h, [src, 64]! | ||
| 155 | 	subs count, count, 128 + 16 /* Test and readjust count. */ | ||
| 156 | 	b.ls .Lcopy64_from_end | ||
| 157 | |||
| 158 | .Lloop64: | ||
| 159 | 	stp A_l, A_h, [dst, 16] | ||
| 160 | 	ldp A_l, A_h, [src, 16] | ||
| 161 | 	stp B_l, B_h, [dst, 32] | ||
| 162 | 	ldp B_l, B_h, [src, 32] | ||
| 163 | 	stp C_l, C_h, [dst, 48] | ||
| 164 | 	ldp C_l, C_h, [src, 48] | ||
| 165 | 	stp D_l, D_h, [dst, 64]! | ||
| 166 | 	ldp D_l, D_h, [src, 64]! | ||
| 167 | 	subs count, count, 64 | ||
| 168 | 	b.hi .Lloop64 | ||
| 169 | |||
| 170 | 	/* Write the last iteration and copy 64 bytes from the end. */ | ||
| 171 | .Lcopy64_from_end: | ||
| 172 | 	ldp E_l, E_h, [srcend, -64] | ||
| 173 | 	stp A_l, A_h, [dst, 16] | ||
| 174 | 	ldp A_l, A_h, [srcend, -48] | ||
| 175 | 	stp B_l, B_h, [dst, 32] | ||
| 176 | 	ldp B_l, B_h, [srcend, -32] | ||
| 177 | 	stp C_l, C_h, [dst, 48] | ||
| 178 | 	ldp C_l, C_h, [srcend, -16] | ||
| 179 | 	stp D_l, D_h, [dst, 64] | ||
| 180 | 	stp E_l, E_h, [dstend, -64] | ||
| 181 | 	stp A_l, A_h, [dstend, -48] | ||
| 182 | 	stp B_l, B_h, [dstend, -32] | ||
| 183 | 	stp C_l, C_h, [dstend, -16] | ||
| 184 | 	ret | ||
| 185 | |||
| 186 | .size memcpy,.-memcpy | ||
lib/libc/musl/src/string/aarch64/memset.S created+115| ... | @@ -0,0 +1,115 @@ | ||
| 1 | /* | ||
| 2 | * memset - fill memory with a constant byte | ||
| 3 | * | ||
| 4 | * Copyright (c) 2012-2020, Arm Limited. | ||
| 5 | * SPDX-License-Identifier: MIT | ||
| 6 | */ | ||
| 7 | |||
| 8 | /* Assumptions: | ||
| 9 | * | ||
| 10 | * ARMv8-a, AArch64, Advanced SIMD, unaligned accesses. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #define dstin x0 | ||
| 15 | #define val x1 | ||
| 16 | #define valw w1 | ||
| 17 | #define count x2 | ||
| 18 | #define dst x3 | ||
| 19 | #define dstend x4 | ||
| 20 | #define zva_val x5 | ||
| 21 | |||
| 22 | .global memset | ||
| 23 | .type memset,%function | ||
| 24 | memset: | ||
| 25 | |||
| 26 | 	dup v0.16B, valw | ||
| 27 | 	add dstend, dstin, count | ||
| 28 | |||
| 29 | 	cmp count, 96 | ||
| 30 | 	b.hi .Lset_long | ||
| 31 | 	cmp count, 16 | ||
| 32 | 	b.hs .Lset_medium | ||
| 33 | 	mov val, v0.D[0] | ||
| 34 | |||
| 35 | 	/* Set 0..15 bytes. */ | ||
| 36 | 	tbz count, 3, 1f | ||
| 37 | 	str val, [dstin] | ||
| 38 | 	str val, [dstend, -8] | ||
| 39 | 	ret | ||
| 40 | 	nop | ||
| 41 | 1: tbz count, 2, 2f | ||
| 42 | 	str valw, [dstin] | ||
| 43 | 	str valw, [dstend, -4] | ||
| 44 | 	ret | ||
| 45 | 2: cbz count, 3f | ||
| 46 | 	strb valw, [dstin] | ||
| 47 | 	tbz count, 1, 3f | ||
| 48 | 	strh valw, [dstend, -2] | ||
| 49 | 3: ret | ||
| 50 | |||
| 51 | 	/* Set 17..96 bytes. */ | ||
| 52 | .Lset_medium: | ||
| 53 | 	str q0, [dstin] | ||
| 54 | 	tbnz count, 6, .Lset96 | ||
| 55 | 	str q0, [dstend, -16] | ||
| 56 | 	tbz count, 5, 1f | ||
| 57 | 	str q0, [dstin, 16] | ||
| 58 | 	str q0, [dstend, -32] | ||
| 59 | 1: ret | ||
| 60 | |||
| 61 | 	.p2align 4 | ||
| 62 | 	/* Set 64..96 bytes. Write 64 bytes from the start and | ||
| 63 | 	 32 bytes from the end. */ | ||
| 64 | .Lset96: | ||
| 65 | 	str q0, [dstin, 16] | ||
| 66 | 	stp q0, q0, [dstin, 32] | ||
| 67 | 	stp q0, q0, [dstend, -32] | ||
| 68 | 	ret | ||
| 69 | |||
| 70 | 	.p2align 4 | ||
| 71 | .Lset_long: | ||
| 72 | 	and valw, valw, 255 | ||
| 73 | 	bic dst, dstin, 15 | ||
| 74 | 	str q0, [dstin] | ||
| 75 | 	cmp count, 160 | ||
| 76 | 	ccmp valw, 0, 0, hs | ||
| 77 | 	b.ne .Lno_zva | ||
| 78 | |||
| 79 | #ifndef SKIP_ZVA_CHECK | ||
| 80 | 	mrs zva_val, dczid_el0 | ||
| 81 | 	and zva_val, zva_val, 31 | ||
| 82 | 	cmp zva_val, 4 /* ZVA size is 64 bytes. */ | ||
| 83 | 	b.ne .Lno_zva | ||
| 84 | #endif | ||
| 85 | 	str q0, [dst, 16] | ||
| 86 | 	stp q0, q0, [dst, 32] | ||
| 87 | 	bic dst, dst, 63 | ||
| 88 | 	sub count, dstend, dst /* Count is now 64 too large. */ | ||
| 89 | 	sub count, count, 128 /* Adjust count and bias for loop. */ | ||
| 90 | |||
| 91 | 	.p2align 4 | ||
| 92 | .Lzva_loop: | ||
| 93 | 	add dst, dst, 64 | ||
| 94 | 	dc zva, dst | ||
| 95 | 	subs count, count, 64 | ||
| 96 | 	b.hi .Lzva_loop | ||
| 97 | 	stp q0, q0, [dstend, -64] | ||
| 98 | 	stp q0, q0, [dstend, -32] | ||
| 99 | 	ret | ||
| 100 | |||
| 101 | .Lno_zva: | ||
| 102 | 	sub count, dstend, dst /* Count is 16 too large. */ | ||
| 103 | 	sub dst, dst, 16 /* Dst is biased by -32. */ | ||
| 104 | 	sub count, count, 64 + 16 /* Adjust count and bias for loop. */ | ||
| 105 | .Lno_zva_loop: | ||
| 106 | 	stp q0, q0, [dst, 32] | ||
| 107 | 	stp q0, q0, [dst, 64]! | ||
| 108 | 	subs count, count, 64 | ||
| 109 | 	b.hi .Lno_zva_loop | ||
| 110 | 	stp q0, q0, [dstend, -64] | ||
| 111 | 	stp q0, q0, [dstend, -32] | ||
| 112 | 	ret | ||
| 113 | |||
| 114 | .size memset,.-memset | ||
| 115 | |||
lib/libc/musl/src/string/arm/memcpy.S created+479| ... | @@ -0,0 +1,479 @@ | ||
| 1 | /* | ||
| 2 | * Copyright (C) 2008 The Android Open Source Project | ||
| 3 | * All rights reserved. | ||
| 4 | * | ||
| 5 | * Redistribution and use in source and binary forms, with or without | ||
| 6 | * modification, are permitted provided that the following conditions | ||
| 7 | * are met: | ||
| 8 | * * Redistributions of source code must retain the above copyright | ||
| 9 | * notice, this list of conditions and the following disclaimer. | ||
| 10 | * * Redistributions in binary form must reproduce the above copyright | ||
| 11 | * notice, this list of conditions and the following disclaimer in | ||
| 12 | * the documentation and/or other materials provided with the | ||
| 13 | * distribution. | ||
| 14 | * | ||
| 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
| 18 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
| 19 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
| 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | ||
| 22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | ||
| 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
| 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||
| 25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
| 26 | * SUCH DAMAGE. | ||
| 27 | */ | ||
| 28 | |||
| 29 | |||
| 30 | /* | ||
| 31 | * Optimized memcpy() for ARM. | ||
| 32 | * | ||
| 33 | * note that memcpy() always returns the destination pointer, | ||
| 34 | * so we have to preserve R0. | ||
| 35 | */ | ||
| 36 | |||
| 37 | /* | ||
| 38 | * This file has been modified from the original for use in musl libc. | ||
| 39 | * The main changes are: addition of .type memcpy,%function to make the | ||
| 40 | * code safely callable from thumb mode, adjusting the return | ||
| 41 | * instructions to be compatible with pre-thumb ARM cpus, removal of | ||
| 42 | * prefetch code that is not compatible with older cpus and support for | ||
| 43 | * building as thumb 2 and big-endian. | ||
| 44 | */ | ||
| 45 | |||
| 46 | .syntax unified | ||
| 47 | |||
| 48 | .global memcpy | ||
| 49 | .type memcpy,%function | ||
| 50 | memcpy: | ||
| 51 | 	/* The stack must always be 64-bits aligned to be compliant with the | ||
| 52 | 	 * ARM ABI. Since we have to save R0, we might as well save R4 | ||
| 53 | 	 * which we can use for better pipelining of the reads below | ||
| 54 | 	 */ | ||
| 55 | 	.fnstart | ||
| 56 | 	.save {r0, r4, lr} | ||
| 57 | 	stmfd sp!, {r0, r4, lr} | ||
| 58 | 	/* Making room for r5-r11 which will be spilled later */ | ||
| 59 | 	.pad #28 | ||
| 60 | 	sub sp, sp, #28 | ||
| 61 | |||
| 62 | 	/* it simplifies things to take care of len<4 early */ | ||
| 63 | 	cmp r2, #4 | ||
| 64 | 	blo copy_last_3_and_return | ||
| 65 | |||
| 66 | 	/* compute the offset to align the source | ||
| 67 | 	 * offset = (4-(src&3))&3 = -src & 3 | ||
| 68 | 	 */ | ||
| 69 | 	rsb r3, r1, #0 | ||
| 70 | 	ands r3, r3, #3 | ||
| 71 | 	beq src_aligned | ||
| 72 | |||
| 73 | 	/* align source to 32 bits. We need to insert 2 instructions between | ||
| 74 | 	 * a ldr[b|h] and str[b|h] because byte and half-word instructions | ||
| 75 | 	 * stall 2 cycles. | ||
| 76 | 	 */ | ||
| 77 | 	movs r12, r3, lsl #31 | ||
| 78 | 	sub r2, r2, r3 /* we know that r3 <= r2 because r2 >= 4 */ | ||
| 79 | 	ldrbmi r3, [r1], #1 | ||
| 80 | 	ldrbcs r4, [r1], #1 | ||
| 81 | 	ldrbcs r12,[r1], #1 | ||
| 82 | 	strbmi r3, [r0], #1 | ||
| 83 | 	strbcs r4, [r0], #1 | ||
| 84 | 	strbcs r12,[r0], #1 | ||
| 85 | |||
| 86 | src_aligned: | ||
| 87 | |||
| 88 | 	/* see if src and dst are aligned together (congruent) */ | ||
| 89 | 	eor r12, r0, r1 | ||
| 90 | 	tst r12, #3 | ||
| 91 | 	bne non_congruent | ||
| 92 | |||
| 93 | 	/* Use post-incriment mode for stm to spill r5-r11 to reserved stack | ||
| 94 | 	 * frame. Don't update sp. | ||
| 95 | 	 */ | ||
| 96 | 	stmea sp, {r5-r11} | ||
| 97 | |||
| 98 | 	/* align the destination to a cache-line */ | ||
| 99 | 	rsb r3, r0, #0 | ||
| 100 | 	ands r3, r3, #0x1C | ||
| 101 | 	beq congruent_aligned32 | ||
| 102 | 	cmp r3, r2 | ||
| 103 | 	andhi r3, r2, #0x1C | ||
| 104 | |||
| 105 | 	/* conditionnaly copies 0 to 7 words (length in r3) */ | ||
| 106 | 	movs r12, r3, lsl #28 | ||
| 107 | 	ldmcs r1!, {r4, r5, r6, r7} /* 16 bytes */ | ||
| 108 | 	ldmmi r1!, {r8, r9} /* 8 bytes */ | ||
| 109 | 	stmcs r0!, {r4, r5, r6, r7} | ||
| 110 | 	stmmi r0!, {r8, r9} | ||
| 111 | 	tst r3, #0x4 | ||
| 112 | 	ldrne r10,[r1], #4 /* 4 bytes */ | ||
| 113 | 	strne r10,[r0], #4 | ||
| 114 | 	sub r2, r2, r3 | ||
| 115 | |||
| 116 | congruent_aligned32: | ||
| 117 | 	/* | ||
| 118 | 	 * here source is aligned to 32 bytes. | ||
| 119 | 	 */ | ||
| 120 | |||
| 121 | cached_aligned32: | ||
| 122 | 	subs r2, r2, #32 | ||
| 123 | 	blo less_than_32_left | ||
| 124 | |||
| 125 | 	/* | ||
| 126 | 	 * We preload a cache-line up to 64 bytes ahead. On the 926, this will | ||
| 127 | 	 * stall only until the requested world is fetched, but the linefill | ||
| 128 | 	 * continues in the the background. | ||
| 129 | 	 * While the linefill is going, we write our previous cache-line | ||
| 130 | 	 * into the write-buffer (which should have some free space). | ||
| 131 | 	 * When the linefill is done, the writebuffer will | ||
| 132 | 	 * start dumping its content into memory | ||
| 133 | 	 * | ||
| 134 | 	 * While all this is going, we then load a full cache line into | ||
| 135 | 	 * 8 registers, this cache line should be in the cache by now | ||
| 136 | 	 * (or partly in the cache). | ||
| 137 | 	 * | ||
| 138 | 	 * This code should work well regardless of the source/dest alignment. | ||
| 139 | 	 * | ||
| 140 | 	 */ | ||
| 141 | |||
| 142 | 	/* Align the preload register to a cache-line because the cpu does | ||
| 143 | 	 * "critical word first" (the first word requested is loaded first). | ||
| 144 | 	 */ | ||
| 145 | 	@ bic r12, r1, #0x1F | ||
| 146 | 	@ add r12, r12, #64 | ||
| 147 | |||
| 148 | 1: ldmia r1!, { r4-r11 } | ||
| 149 | 	subs r2, r2, #32 | ||
| 150 | |||
| 151 | 	/* | ||
| 152 | 	 * NOTE: if r12 is more than 64 ahead of r1, the following ldrhi | ||
| 153 | 	 * for ARM9 preload will not be safely guarded by the preceding subs. | ||
| 154 | 	 * When it is safely guarded the only possibility to have SIGSEGV here | ||
| 155 | 	 * is because the caller overstates the length. | ||
| 156 | 	 */ | ||
| 157 | 	@ ldrhi r3, [r12], #32 /* cheap ARM9 preload */ | ||
| 158 | 	stmia r0!, { r4-r11 } | ||
| 159 | 	bhs 1b | ||
| 160 | |||
| 161 | 	add r2, r2, #32 | ||
| 162 | |||
| 163 | less_than_32_left: | ||
| 164 | 	/* | ||
| 165 | 	 * less than 32 bytes left at this point (length in r2) | ||
| 166 | 	 */ | ||
| 167 | |||
| 168 | 	/* skip all this if there is nothing to do, which should | ||
| 169 | 	 * be a common case (if not executed the code below takes | ||
| 170 | 	 * about 16 cycles) | ||
| 171 | 	 */ | ||
| 172 | 	tst r2, #0x1F | ||
| 173 | 	beq 1f | ||
| 174 | |||
| 175 | 	/* conditionnaly copies 0 to 31 bytes */ | ||
| 176 | 	movs r12, r2, lsl #28 | ||
| 177 | 	ldmcs r1!, {r4, r5, r6, r7} /* 16 bytes */ | ||
| 178 | 	ldmmi r1!, {r8, r9} /* 8 bytes */ | ||
| 179 | 	stmcs r0!, {r4, r5, r6, r7} | ||
| 180 | 	stmmi r0!, {r8, r9} | ||
| 181 | 	movs r12, r2, lsl #30 | ||
| 182 | 	ldrcs r3, [r1], #4 /* 4 bytes */ | ||
| 183 | 	ldrhmi r4, [r1], #2 /* 2 bytes */ | ||
| 184 | 	strcs r3, [r0], #4 | ||
| 185 | 	strhmi r4, [r0], #2 | ||
| 186 | 	tst r2, #0x1 | ||
| 187 | 	ldrbne r3, [r1] /* last byte */ | ||
| 188 | 	strbne r3, [r0] | ||
| 189 | |||
| 190 | 	/* we're done! restore everything and return */ | ||
| 191 | 1: ldmfd sp!, {r5-r11} | ||
| 192 | 	ldmfd sp!, {r0, r4, lr} | ||
| 193 | 	bx lr | ||
| 194 | |||
| 195 | 	/********************************************************************/ | ||
| 196 | |||
| 197 | non_congruent: | ||
| 198 | 	/* | ||
| 199 | 	 * here source is aligned to 4 bytes | ||
| 200 | 	 * but destination is not. | ||
| 201 | 	 * | ||
| 202 | 	 * in the code below r2 is the number of bytes read | ||
| 203 | 	 * (the number of bytes written is always smaller, because we have | ||
| 204 | 	 * partial words in the shift queue) | ||
| 205 | 	 */ | ||
| 206 | 	cmp r2, #4 | ||
| 207 | 	blo copy_last_3_and_return | ||
| 208 | |||
| 209 | 	/* Use post-incriment mode for stm to spill r5-r11 to reserved stack | ||
| 210 | 	 * frame. Don't update sp. | ||
| 211 | 	 */ | ||
| 212 | 	stmea sp, {r5-r11} | ||
| 213 | |||
| 214 | 	/* compute shifts needed to align src to dest */ | ||
| 215 | 	rsb r5, r0, #0 | ||
| 216 | 	and r5, r5, #3 /* r5 = # bytes in partial words */ | ||
| 217 | 	mov r12, r5, lsl #3 /* r12 = right */ | ||
| 218 | 	rsb lr, r12, #32 /* lr = left */ | ||
| 219 | |||
| 220 | 	/* read the first word */ | ||
| 221 | 	ldr r3, [r1], #4 | ||
| 222 | 	sub r2, r2, #4 | ||
| 223 | |||
| 224 | 	/* write a partial word (0 to 3 bytes), such that destination | ||
| 225 | 	 * becomes aligned to 32 bits (r5 = nb of words to copy for alignment) | ||
| 226 | 	 */ | ||
| 227 | 	movs r5, r5, lsl #31 | ||
| 228 | |||
| 229 | #if __ARMEB__ | ||
| 230 | 	movmi r3, r3, ror #24 | ||
| 231 | 	strbmi	r3, [r0], #1 | ||
| 232 | 	movcs r3, r3, ror #24 | ||
| 233 | 	strbcs	r3, [r0], #1 | ||
| 234 | 	movcs r3, r3, ror #24 | ||
| 235 | 	strbcs	r3, [r0], #1 | ||
| 236 | #else | ||
| 237 | 	strbmi r3, [r0], #1 | ||
| 238 | 	movmi r3, r3, lsr #8 | ||
| 239 | 	strbcs r3, [r0], #1 | ||
| 240 | 	movcs r3, r3, lsr #8 | ||
| 241 | 	strbcs r3, [r0], #1 | ||
| 242 | 	movcs r3, r3, lsr #8 | ||
| 243 | #endif | ||
| 244 | |||
| 245 | 	cmp r2, #4 | ||
| 246 | 	blo partial_word_tail | ||
| 247 | |||
| 248 | #if __ARMEB__ | ||
| 249 | 	mov	r3, r3, lsr r12 | ||
| 250 | 	mov	r3, r3, lsl r12 | ||
| 251 | #endif | ||
| 252 | |||
| 253 | 	/* Align destination to 32 bytes (cache line boundary) */ | ||
| 254 | 1: tst r0, #0x1c | ||
| 255 | 	beq 2f | ||
| 256 | 	ldr r5, [r1], #4 | ||
| 257 | 	sub r2, r2, #4 | ||
| 258 | #if __ARMEB__ | ||
| 259 | 	mov r4, r5, lsr lr | ||
| 260 | 	orr r4, r4, r3 | ||
| 261 | 	mov r3, r5, lsl r12 | ||
| 262 | #else | ||
| 263 | 	mov r4, r5, lsl lr | ||
| 264 | 	orr r4, r4, r3 | ||
| 265 | 	mov r3, r5, lsr r12 | ||
| 266 | #endif | ||
| 267 | 	str r4, [r0], #4 | ||
| 268 | 	cmp r2, #4 | ||
| 269 | 	bhs 1b | ||
| 270 | 	blo partial_word_tail | ||
| 271 | |||
| 272 | 	/* copy 32 bytes at a time */ | ||
| 273 | 2: subs r2, r2, #32 | ||
| 274 | 	blo less_than_thirtytwo | ||
| 275 | |||
| 276 | 	/* Use immediate mode for the shifts, because there is an extra cycle | ||
| 277 | 	 * for register shifts, which could account for up to 50% of | ||
| 278 | 	 * performance hit. | ||
| 279 | 	 */ | ||
| 280 | |||
| 281 | 	cmp r12, #24 | ||
| 282 | 	beq loop24 | ||
| 283 | 	cmp r12, #8 | ||
| 284 | 	beq loop8 | ||
| 285 | |||
| 286 | loop16: | ||
| 287 | 	ldr r12, [r1], #4 | ||
| 288 | 1: mov r4, r12 | ||
| 289 | 	ldmia r1!, { r5,r6,r7, r8,r9,r10,r11} | ||
| 290 | 	subs r2, r2, #32 | ||
| 291 | 	ldrhs r12, [r1], #4 | ||
| 292 | #if __ARMEB__ | ||
| 293 | 	orr r3, r3, r4, lsr #16 | ||
| 294 | 	mov r4, r4, lsl #16 | ||
| 295 | 	orr r4, r4, r5, lsr #16 | ||
| 296 | 	mov r5, r5, lsl #16 | ||
| 297 | 	orr r5, r5, r6, lsr #16 | ||
| 298 | 	mov r6, r6, lsl #16 | ||
| 299 | 	orr r6, r6, r7, lsr #16 | ||
| 300 | 	mov r7, r7, lsl #16 | ||
| 301 | 	orr r7, r7, r8, lsr #16 | ||
| 302 | 	mov r8, r8, lsl #16 | ||
| 303 | 	orr r8, r8, r9, lsr #16 | ||
| 304 | 	mov r9, r9, lsl #16 | ||
| 305 | 	orr r9, r9, r10, lsr #16 | ||
| 306 | 	mov r10, r10, lsl #16 | ||
| 307 | 	orr r10, r10, r11, lsr #16 | ||
| 308 | 	stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10} | ||
| 309 | 	mov r3, r11, lsl #16 | ||
| 310 | #else | ||
| 311 | 	orr r3, r3, r4, lsl #16 | ||
| 312 | 	mov r4, r4, lsr #16 | ||
| 313 | 	orr r4, r4, r5, lsl #16 | ||
| 314 | 	mov r5, r5, lsr #16 | ||
| 315 | 	orr r5, r5, r6, lsl #16 | ||
| 316 | 	mov r6, r6, lsr #16 | ||
| 317 | 	orr r6, r6, r7, lsl #16 | ||
| 318 | 	mov r7, r7, lsr #16 | ||
| 319 | 	orr r7, r7, r8, lsl #16 | ||
| 320 | 	mov r8, r8, lsr #16 | ||
| 321 | 	orr r8, r8, r9, lsl #16 | ||
| 322 | 	mov r9, r9, lsr #16 | ||
| 323 | 	orr r9, r9, r10, lsl #16 | ||
| 324 | 	mov r10, r10, lsr #16 | ||
| 325 | 	orr r10, r10, r11, lsl #16 | ||
| 326 | 	stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10} | ||
| 327 | 	mov r3, r11, lsr #16 | ||
| 328 | #endif | ||
| 329 | 	bhs 1b | ||
| 330 | 	b less_than_thirtytwo | ||
| 331 | |||
| 332 | loop8: | ||
| 333 | 	ldr r12, [r1], #4 | ||
| 334 | 1: mov r4, r12 | ||
| 335 | 	ldmia r1!, { r5,r6,r7, r8,r9,r10,r11} | ||
| 336 | 	subs r2, r2, #32 | ||
| 337 | 	ldrhs r12, [r1], #4 | ||
| 338 | #if __ARMEB__ | ||
| 339 | 	orr r3, r3, r4, lsr #24 | ||
| 340 | 	mov r4, r4, lsl #8 | ||
| 341 | 	orr r4, r4, r5, lsr #24 | ||
| 342 | 	mov r5, r5, lsl #8 | ||
| 343 | 	orr r5, r5, r6, lsr #24 | ||
| 344 | 	mov r6, r6, lsl #8 | ||
| 345 | 	orr r6, r6, r7, lsr #24 | ||
| 346 | 	mov r7, r7, lsl #8 | ||
| 347 | 	orr r7, r7, r8, lsr #24 | ||
| 348 | 	mov r8, r8, lsl #8 | ||
| 349 | 	orr r8, r8, r9, lsr #24 | ||
| 350 | 	mov r9, r9, lsl #8 | ||
| 351 | 	orr r9, r9, r10, lsr #24 | ||
| 352 | 	mov r10, r10, lsl #8 | ||
| 353 | 	orr r10, r10, r11, lsr #24 | ||
| 354 | 	stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10} | ||
| 355 | 	mov r3, r11, lsl #8 | ||
| 356 | #else | ||
| 357 | 	orr r3, r3, r4, lsl #24 | ||
| 358 | 	mov r4, r4, lsr #8 | ||
| 359 | 	orr r4, r4, r5, lsl #24 | ||
| 360 | 	mov r5, r5, lsr #8 | ||
| 361 | 	orr r5, r5, r6, lsl #24 | ||
| 362 | 	mov r6, r6, lsr #8 | ||
| 363 | 	orr r6, r6, r7, lsl #24 | ||
| 364 | 	mov r7, r7, lsr #8 | ||
| 365 | 	orr r7, r7, r8, lsl #24 | ||
| 366 | 	mov r8, r8, lsr #8 | ||
| 367 | 	orr r8, r8, r9, lsl #24 | ||
| 368 | 	mov r9, r9, lsr #8 | ||
| 369 | 	orr r9, r9, r10, lsl #24 | ||
| 370 | 	mov r10, r10, lsr #8 | ||
| 371 | 	orr r10, r10, r11, lsl #24 | ||
| 372 | 	stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10} | ||
| 373 | 	mov r3, r11, lsr #8 | ||
| 374 | #endif | ||
| 375 | 	bhs 1b | ||
| 376 | 	b less_than_thirtytwo | ||
| 377 | |||
| 378 | loop24: | ||
| 379 | 	ldr r12, [r1], #4 | ||
| 380 | 1: mov r4, r12 | ||
| 381 | 	ldmia r1!, { r5,r6,r7, r8,r9,r10,r11} | ||
| 382 | 	subs r2, r2, #32 | ||
| 383 | 	ldrhs r12, [r1], #4 | ||
| 384 | #if __ARMEB__ | ||
| 385 | 	orr r3, r3, r4, lsr #8 | ||
| 386 | 	mov r4, r4, lsl #24 | ||
| 387 | 	orr r4, r4, r5, lsr #8 | ||
| 388 | 	mov r5, r5, lsl #24 | ||
| 389 | 	orr r5, r5, r6, lsr #8 | ||
| 390 | 	mov r6, r6, lsl #24 | ||
| 391 | 	orr r6, r6, r7, lsr #8 | ||
| 392 | 	mov r7, r7, lsl #24 | ||
| 393 | 	orr r7, r7, r8, lsr #8 | ||
| 394 | 	mov r8, r8, lsl #24 | ||
| 395 | 	orr r8, r8, r9, lsr #8 | ||
| 396 | 	mov r9, r9, lsl #24 | ||
| 397 | 	orr r9, r9, r10, lsr #8 | ||
| 398 | 	mov r10, r10, lsl #24 | ||
| 399 | 	orr r10, r10, r11, lsr #8 | ||
| 400 | 	stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10} | ||
| 401 | 	mov r3, r11, lsl #24 | ||
| 402 | #else | ||
| 403 | 	orr r3, r3, r4, lsl #8 | ||
| 404 | 	mov r4, r4, lsr #24 | ||
| 405 | 	orr r4, r4, r5, lsl #8 | ||
| 406 | 	mov r5, r5, lsr #24 | ||
| 407 | 	orr r5, r5, r6, lsl #8 | ||
| 408 | 	mov r6, r6, lsr #24 | ||
| 409 | 	orr r6, r6, r7, lsl #8 | ||
| 410 | 	mov r7, r7, lsr #24 | ||
| 411 | 	orr r7, r7, r8, lsl #8 | ||
| 412 | 	mov r8, r8, lsr #24 | ||
| 413 | 	orr r8, r8, r9, lsl #8 | ||
| 414 | 	mov r9, r9, lsr #24 | ||
| 415 | 	orr r9, r9, r10, lsl #8 | ||
| 416 | 	mov r10, r10, lsr #24 | ||
| 417 | 	orr r10, r10, r11, lsl #8 | ||
| 418 | 	stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10} | ||
| 419 | 	mov r3, r11, lsr #24 | ||
| 420 | #endif | ||
| 421 | 	bhs 1b | ||
| 422 | |||
| 423 | less_than_thirtytwo: | ||
| 424 | 	/* copy the last 0 to 31 bytes of the source */ | ||
| 425 | 	rsb r12, lr, #32 /* we corrupted r12, recompute it */ | ||
| 426 | 	add r2, r2, #32 | ||
| 427 | 	cmp r2, #4 | ||
| 428 | 	blo partial_word_tail | ||
| 429 | |||
| 430 | 1: ldr r5, [r1], #4 | ||
| 431 | 	sub r2, r2, #4 | ||
| 432 | #if __ARMEB__ | ||
| 433 | 	mov r4, r5, lsr lr | ||
| 434 | 	orr r4, r4, r3 | ||
| 435 | 	mov r3, r5, lsl r12 | ||
| 436 | #else | ||
| 437 | 	mov r4, r5, lsl lr | ||
| 438 | 	orr r4, r4, r3 | ||
| 439 | 	mov r3, r5, lsr r12 | ||
| 440 | #endif | ||
| 441 | 	str r4, [r0], #4 | ||
| 442 | 	cmp r2, #4 | ||
| 443 | 	bhs 1b | ||
| 444 | |||
| 445 | partial_word_tail: | ||
| 446 | 	/* we have a partial word in the input buffer */ | ||
| 447 | 	movs r5, lr, lsl #(31-3) | ||
| 448 | #if __ARMEB__ | ||
| 449 | 	movmi r3, r3, ror #24 | ||
| 450 | 	strbmi r3, [r0], #1 | ||
| 451 | 	movcs r3, r3, ror #24 | ||
| 452 | 	strbcs r3, [r0], #1 | ||
| 453 | 	movcs r3, r3, ror #24 | ||
| 454 | 	strbcs r3, [r0], #1 | ||
| 455 | #else | ||
| 456 | 	strbmi r3, [r0], #1 | ||
| 457 | 	movmi r3, r3, lsr #8 | ||
| 458 | 	strbcs r3, [r0], #1 | ||
| 459 | 	movcs r3, r3, lsr #8 | ||
| 460 | 	strbcs r3, [r0], #1 | ||
| 461 | #endif | ||
| 462 | |||
| 463 | 	/* Refill spilled registers from the stack. Don't update sp. */ | ||
| 464 | 	ldmfd sp, {r5-r11} | ||
| 465 | |||
| 466 | copy_last_3_and_return: | ||
| 467 | 	movs r2, r2, lsl #31 /* copy remaining 0, 1, 2 or 3 bytes */ | ||
| 468 | 	ldrbmi r2, [r1], #1 | ||
| 469 | 	ldrbcs r3, [r1], #1 | ||
| 470 | 	ldrbcs r12,[r1] | ||
| 471 | 	strbmi r2, [r0], #1 | ||
| 472 | 	strbcs r3, [r0], #1 | ||
| 473 | 	strbcs r12,[r0] | ||
| 474 | |||
| 475 | 	/* we're done! restore sp and spilled registers and return */ | ||
| 476 | 	add sp, sp, #28 | ||
| 477 | 	ldmfd sp!, {r0, r4, lr} | ||
| 478 | 	bx lr | ||
| 479 | |||
lib/libc/musl/src/string/arm/memcpy.c deleted-3| ... | @@ -1,3 +0,0 @@ | ||
| 1 | #if __ARMEB__ | ||
| 2 | #include "../memcpy.c" | ||
| 3 | #endif | ||
lib/libc/musl/src/string/arm/memcpy_le.S deleted-386| ... | @@ -1,386 +0,0 @@ | ||
| 1 | #if !__ARMEB__ | ||
| 2 | |||
| 3 | /* | ||
| 4 | * Copyright (C) 2008 The Android Open Source Project | ||
| 5 | * All rights reserved. | ||
| 6 | * | ||
| 7 | * Redistribution and use in source and binary forms, with or without | ||
| 8 | * modification, are permitted provided that the following conditions | ||
| 9 | * are met: | ||
| 10 | * * Redistributions of source code must retain the above copyright | ||
| 11 | * notice, this list of conditions and the following disclaimer. | ||
| 12 | * * Redistributions in binary form must reproduce the above copyright | ||
| 13 | * notice, this list of conditions and the following disclaimer in | ||
| 14 | * the documentation and/or other materials provided with the | ||
| 15 | * distribution. | ||
| 16 | * | ||
| 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 18 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 19 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | ||
| 20 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | ||
| 21 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
| 22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||
| 23 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | ||
| 24 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | ||
| 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
| 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | ||
| 27 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
| 28 | * SUCH DAMAGE. | ||
| 29 | */ | ||
| 30 | |||
| 31 | |||
| 32 | /* | ||
| 33 | * Optimized memcpy() for ARM. | ||
| 34 | * | ||
| 35 | * note that memcpy() always returns the destination pointer, | ||
| 36 | * so we have to preserve R0. | ||
| 37 | */ | ||
| 38 | |||
| 39 | /* | ||
| 40 | * This file has been modified from the original for use in musl libc. | ||
| 41 | * The main changes are: addition of .type memcpy,%function to make the | ||
| 42 | * code safely callable from thumb mode, adjusting the return | ||
| 43 | * instructions to be compatible with pre-thumb ARM cpus, removal of | ||
| 44 | * prefetch code that is not compatible with older cpus and support for | ||
| 45 | * building as thumb 2. | ||
| 46 | */ | ||
| 47 | |||
| 48 | .syntax unified | ||
| 49 | |||
| 50 | .global memcpy | ||
| 51 | .type memcpy,%function | ||
| 52 | memcpy: | ||
| 53 | 	/* The stack must always be 64-bits aligned to be compliant with the | ||
| 54 | 	 * ARM ABI. Since we have to save R0, we might as well save R4 | ||
| 55 | 	 * which we can use for better pipelining of the reads below | ||
| 56 | 	 */ | ||
| 57 | 	.fnstart | ||
| 58 | 	.save {r0, r4, lr} | ||
| 59 | 	stmfd sp!, {r0, r4, lr} | ||
| 60 | 	/* Making room for r5-r11 which will be spilled later */ | ||
| 61 | 	.pad #28 | ||
| 62 | 	sub sp, sp, #28 | ||
| 63 | |||
| 64 | 	/* it simplifies things to take care of len<4 early */ | ||
| 65 | 	cmp r2, #4 | ||
| 66 | 	blo copy_last_3_and_return | ||
| 67 | |||
| 68 | 	/* compute the offset to align the source | ||
| 69 | 	 * offset = (4-(src&3))&3 = -src & 3 | ||
| 70 | 	 */ | ||
| 71 | 	rsb r3, r1, #0 | ||
| 72 | 	ands r3, r3, #3 | ||
| 73 | 	beq src_aligned | ||
| 74 | |||
| 75 | 	/* align source to 32 bits. We need to insert 2 instructions between | ||
| 76 | 	 * a ldr[b|h] and str[b|h] because byte and half-word instructions | ||
| 77 | 	 * stall 2 cycles. | ||
| 78 | 	 */ | ||
| 79 | 	movs r12, r3, lsl #31 | ||
| 80 | 	sub r2, r2, r3 /* we know that r3 <= r2 because r2 >= 4 */ | ||
| 81 | 	ldrbmi r3, [r1], #1 | ||
| 82 | 	ldrbcs r4, [r1], #1 | ||
| 83 | 	ldrbcs r12,[r1], #1 | ||
| 84 | 	strbmi r3, [r0], #1 | ||
| 85 | 	strbcs r4, [r0], #1 | ||
| 86 | 	strbcs r12,[r0], #1 | ||
| 87 | |||
| 88 | src_aligned: | ||
| 89 | |||
| 90 | 	/* see if src and dst are aligned together (congruent) */ | ||
| 91 | 	eor r12, r0, r1 | ||
| 92 | 	tst r12, #3 | ||
| 93 | 	bne non_congruent | ||
| 94 | |||
| 95 | 	/* Use post-incriment mode for stm to spill r5-r11 to reserved stack | ||
| 96 | 	 * frame. Don't update sp. | ||
| 97 | 	 */ | ||
| 98 | 	stmea sp, {r5-r11} | ||
| 99 | |||
| 100 | 	/* align the destination to a cache-line */ | ||
| 101 | 	rsb r3, r0, #0 | ||
| 102 | 	ands r3, r3, #0x1C | ||
| 103 | 	beq congruent_aligned32 | ||
| 104 | 	cmp r3, r2 | ||
| 105 | 	andhi r3, r2, #0x1C | ||
| 106 | |||
| 107 | 	/* conditionnaly copies 0 to 7 words (length in r3) */ | ||
| 108 | 	movs r12, r3, lsl #28 | ||
| 109 | 	ldmcs r1!, {r4, r5, r6, r7} /* 16 bytes */ | ||
| 110 | 	ldmmi r1!, {r8, r9} /* 8 bytes */ | ||
| 111 | 	stmcs r0!, {r4, r5, r6, r7} | ||
| 112 | 	stmmi r0!, {r8, r9} | ||
| 113 | 	tst r3, #0x4 | ||
| 114 | 	ldrne r10,[r1], #4 /* 4 bytes */ | ||
| 115 | 	strne r10,[r0], #4 | ||
| 116 | 	sub r2, r2, r3 | ||
| 117 | |||
| 118 | congruent_aligned32: | ||
| 119 | 	/* | ||
| 120 | 	 * here source is aligned to 32 bytes. | ||
| 121 | 	 */ | ||
| 122 | |||
| 123 | cached_aligned32: | ||
| 124 | 	subs r2, r2, #32 | ||
| 125 | 	blo less_than_32_left | ||
| 126 | |||
| 127 | 	/* | ||
| 128 | 	 * We preload a cache-line up to 64 bytes ahead. On the 926, this will | ||
| 129 | 	 * stall only until the requested world is fetched, but the linefill | ||
| 130 | 	 * continues in the the background. | ||
| 131 | 	 * While the linefill is going, we write our previous cache-line | ||
| 132 | 	 * into the write-buffer (which should have some free space). | ||
| 133 | 	 * When the linefill is done, the writebuffer will | ||
| 134 | 	 * start dumping its content into memory | ||
| 135 | 	 * | ||
| 136 | 	 * While all this is going, we then load a full cache line into | ||
| 137 | 	 * 8 registers, this cache line should be in the cache by now | ||
| 138 | 	 * (or partly in the cache). | ||
| 139 | 	 * | ||
| 140 | 	 * This code should work well regardless of the source/dest alignment. | ||
| 141 | 	 * | ||
| 142 | 	 */ | ||
| 143 | |||
| 144 | 	/* Align the preload register to a cache-line because the cpu does | ||
| 145 | 	 * "critical word first" (the first word requested is loaded first). | ||
| 146 | 	 */ | ||
| 147 | 	@ bic r12, r1, #0x1F | ||
| 148 | 	@ add r12, r12, #64 | ||
| 149 | |||
| 150 | 1: ldmia r1!, { r4-r11 } | ||
| 151 | 	subs r2, r2, #32 | ||
| 152 | |||
| 153 | 	/* | ||
| 154 | 	 * NOTE: if r12 is more than 64 ahead of r1, the following ldrhi | ||
| 155 | 	 * for ARM9 preload will not be safely guarded by the preceding subs. | ||
| 156 | 	 * When it is safely guarded the only possibility to have SIGSEGV here | ||
| 157 | 	 * is because the caller overstates the length. | ||
| 158 | 	 */ | ||
| 159 | 	@ ldrhi r3, [r12], #32 /* cheap ARM9 preload */ | ||
| 160 | 	stmia r0!, { r4-r11 } | ||
| 161 | 	bhs 1b | ||
| 162 | |||
| 163 | 	add r2, r2, #32 | ||
| 164 | |||
| 165 | less_than_32_left: | ||
| 166 | 	/* | ||
| 167 | 	 * less than 32 bytes left at this point (length in r2) | ||
| 168 | 	 */ | ||
| 169 | |||
| 170 | 	/* skip all this if there is nothing to do, which should | ||
| 171 | 	 * be a common case (if not executed the code below takes | ||
| 172 | 	 * about 16 cycles) | ||
| 173 | 	 */ | ||
| 174 | 	tst r2, #0x1F | ||
| 175 | 	beq 1f | ||
| 176 | |||
| 177 | 	/* conditionnaly copies 0 to 31 bytes */ | ||
| 178 | 	movs r12, r2, lsl #28 | ||
| 179 | 	ldmcs r1!, {r4, r5, r6, r7} /* 16 bytes */ | ||
| 180 | 	ldmmi r1!, {r8, r9} /* 8 bytes */ | ||
| 181 | 	stmcs r0!, {r4, r5, r6, r7} | ||
| 182 | 	stmmi r0!, {r8, r9} | ||
| 183 | 	movs r12, r2, lsl #30 | ||
| 184 | 	ldrcs r3, [r1], #4 /* 4 bytes */ | ||
| 185 | 	ldrhmi r4, [r1], #2 /* 2 bytes */ | ||
| 186 | 	strcs r3, [r0], #4 | ||
| 187 | 	strhmi r4, [r0], #2 | ||
| 188 | 	tst r2, #0x1 | ||
| 189 | 	ldrbne r3, [r1] /* last byte */ | ||
| 190 | 	strbne r3, [r0] | ||
| 191 | |||
| 192 | 	/* we're done! restore everything and return */ | ||
| 193 | 1: ldmfd sp!, {r5-r11} | ||
| 194 | 	ldmfd sp!, {r0, r4, lr} | ||
| 195 | 	bx lr | ||
| 196 | |||
| 197 | 	/********************************************************************/ | ||
| 198 | |||
| 199 | non_congruent: | ||
| 200 | 	/* | ||
| 201 | 	 * here source is aligned to 4 bytes | ||
| 202 | 	 * but destination is not. | ||
| 203 | 	 * | ||
| 204 | 	 * in the code below r2 is the number of bytes read | ||
| 205 | 	 * (the number of bytes written is always smaller, because we have | ||
| 206 | 	 * partial words in the shift queue) | ||
| 207 | 	 */ | ||
| 208 | 	cmp r2, #4 | ||
| 209 | 	blo copy_last_3_and_return | ||
| 210 | |||
| 211 | 	/* Use post-incriment mode for stm to spill r5-r11 to reserved stack | ||
| 212 | 	 * frame. Don't update sp. | ||
| 213 | 	 */ | ||
| 214 | 	stmea sp, {r5-r11} | ||
| 215 | |||
| 216 | 	/* compute shifts needed to align src to dest */ | ||
| 217 | 	rsb r5, r0, #0 | ||
| 218 | 	and r5, r5, #3 /* r5 = # bytes in partial words */ | ||
| 219 | 	mov r12, r5, lsl #3 /* r12 = right */ | ||
| 220 | 	rsb lr, r12, #32 /* lr = left */ | ||
| 221 | |||
| 222 | 	/* read the first word */ | ||
| 223 | 	ldr r3, [r1], #4 | ||
| 224 | 	sub r2, r2, #4 | ||
| 225 | |||
| 226 | 	/* write a partial word (0 to 3 bytes), such that destination | ||
| 227 | 	 * becomes aligned to 32 bits (r5 = nb of words to copy for alignment) | ||
| 228 | 	 */ | ||
| 229 | 	movs r5, r5, lsl #31 | ||
| 230 | 	strbmi r3, [r0], #1 | ||
| 231 | 	movmi r3, r3, lsr #8 | ||
| 232 | 	strbcs r3, [r0], #1 | ||
| 233 | 	movcs r3, r3, lsr #8 | ||
| 234 | 	strbcs r3, [r0], #1 | ||
| 235 | 	movcs r3, r3, lsr #8 | ||
| 236 | |||
| 237 | 	cmp r2, #4 | ||
| 238 | 	blo partial_word_tail | ||
| 239 | |||
| 240 | 	/* Align destination to 32 bytes (cache line boundary) */ | ||
| 241 | 1: tst r0, #0x1c | ||
| 242 | 	beq 2f | ||
| 243 | 	ldr r5, [r1], #4 | ||
| 244 | 	sub r2, r2, #4 | ||
| 245 | 	mov r4, r5, lsl lr | ||
| 246 | 	orr r4, r4, r3 | ||
| 247 | 	mov r3, r5, lsr r12 | ||
| 248 | 	str r4, [r0], #4 | ||
| 249 | 	cmp r2, #4 | ||
| 250 | 	bhs 1b | ||
| 251 | 	blo partial_word_tail | ||
| 252 | |||
| 253 | 	/* copy 32 bytes at a time */ | ||
| 254 | 2: subs r2, r2, #32 | ||
| 255 | 	blo less_than_thirtytwo | ||
| 256 | |||
| 257 | 	/* Use immediate mode for the shifts, because there is an extra cycle | ||
| 258 | 	 * for register shifts, which could account for up to 50% of | ||
| 259 | 	 * performance hit. | ||
| 260 | 	 */ | ||
| 261 | |||
| 262 | 	cmp r12, #24 | ||
| 263 | 	beq loop24 | ||
| 264 | 	cmp r12, #8 | ||
| 265 | 	beq loop8 | ||
| 266 | |||
| 267 | loop16: | ||
| 268 | 	ldr r12, [r1], #4 | ||
| 269 | 1: mov r4, r12 | ||
| 270 | 	ldmia r1!, { r5,r6,r7, r8,r9,r10,r11} | ||
| 271 | 	subs r2, r2, #32 | ||
| 272 | 	ldrhs r12, [r1], #4 | ||
| 273 | 	orr r3, r3, r4, lsl #16 | ||
| 274 | 	mov r4, r4, lsr #16 | ||
| 275 | 	orr r4, r4, r5, lsl #16 | ||
| 276 | 	mov r5, r5, lsr #16 | ||
| 277 | 	orr r5, r5, r6, lsl #16 | ||
| 278 | 	mov r6, r6, lsr #16 | ||
| 279 | 	orr r6, r6, r7, lsl #16 | ||
| 280 | 	mov r7, r7, lsr #16 | ||
| 281 | 	orr r7, r7, r8, lsl #16 | ||
| 282 | 	mov r8, r8, lsr #16 | ||
| 283 | 	orr r8, r8, r9, lsl #16 | ||
| 284 | 	mov r9, r9, lsr #16 | ||
| 285 | 	orr r9, r9, r10, lsl #16 | ||
| 286 | 	mov r10, r10, lsr #16 | ||
| 287 | 	orr r10, r10, r11, lsl #16 | ||
| 288 | 	stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10} | ||
| 289 | 	mov r3, r11, lsr #16 | ||
| 290 | 	bhs 1b | ||
| 291 | 	b less_than_thirtytwo | ||
| 292 | |||
| 293 | loop8: | ||
| 294 | 	ldr r12, [r1], #4 | ||
| 295 | 1: mov r4, r12 | ||
| 296 | 	ldmia r1!, { r5,r6,r7, r8,r9,r10,r11} | ||
| 297 | 	subs r2, r2, #32 | ||
| 298 | 	ldrhs r12, [r1], #4 | ||
| 299 | 	orr r3, r3, r4, lsl #24 | ||
| 300 | 	mov r4, r4, lsr #8 | ||
| 301 | 	orr r4, r4, r5, lsl #24 | ||
| 302 | 	mov r5, r5, lsr #8 | ||
| 303 | 	orr r5, r5, r6, lsl #24 | ||
| 304 | 	mov r6, r6, lsr #8 | ||
| 305 | 	orr r6, r6, r7, lsl #24 | ||
| 306 | 	mov r7, r7, lsr #8 | ||
| 307 | 	orr r7, r7, r8, lsl #24 | ||
| 308 | 	mov r8, r8, lsr #8 | ||
| 309 | 	orr r8, r8, r9, lsl #24 | ||
| 310 | 	mov r9, r9, lsr #8 | ||
| 311 | 	orr r9, r9, r10, lsl #24 | ||
| 312 | 	mov r10, r10, lsr #8 | ||
| 313 | 	orr r10, r10, r11, lsl #24 | ||
| 314 | 	stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10} | ||
| 315 | 	mov r3, r11, lsr #8 | ||
| 316 | 	bhs 1b | ||
| 317 | 	b less_than_thirtytwo | ||
| 318 | |||
| 319 | loop24: | ||
| 320 | 	ldr r12, [r1], #4 | ||
| 321 | 1: mov r4, r12 | ||
| 322 | 	ldmia r1!, { r5,r6,r7, r8,r9,r10,r11} | ||
| 323 | 	subs r2, r2, #32 | ||
| 324 | 	ldrhs r12, [r1], #4 | ||
| 325 | 	orr r3, r3, r4, lsl #8 | ||
| 326 | 	mov r4, r4, lsr #24 | ||
| 327 | 	orr r4, r4, r5, lsl #8 | ||
| 328 | 	mov r5, r5, lsr #24 | ||
| 329 | 	orr r5, r5, r6, lsl #8 | ||
| 330 | 	mov r6, r6, lsr #24 | ||
| 331 | 	orr r6, r6, r7, lsl #8 | ||
| 332 | 	mov r7, r7, lsr #24 | ||
| 333 | 	orr r7, r7, r8, lsl #8 | ||
| 334 | 	mov r8, r8, lsr #24 | ||
| 335 | 	orr r8, r8, r9, lsl #8 | ||
| 336 | 	mov r9, r9, lsr #24 | ||
| 337 | 	orr r9, r9, r10, lsl #8 | ||
| 338 | 	mov r10, r10, lsr #24 | ||
| 339 | 	orr r10, r10, r11, lsl #8 | ||
| 340 | 	stmia r0!, {r3,r4,r5,r6, r7,r8,r9,r10} | ||
| 341 | 	mov r3, r11, lsr #24 | ||
| 342 | 	bhs 1b | ||
| 343 | |||
| 344 | less_than_thirtytwo: | ||
| 345 | 	/* copy the last 0 to 31 bytes of the source */ | ||
| 346 | 	rsb r12, lr, #32 /* we corrupted r12, recompute it */ | ||
| 347 | 	add r2, r2, #32 | ||
| 348 | 	cmp r2, #4 | ||
| 349 | 	blo partial_word_tail | ||
| 350 | |||
| 351 | 1: ldr r5, [r1], #4 | ||
| 352 | 	sub r2, r2, #4 | ||
| 353 | 	mov r4, r5, lsl lr | ||
| 354 | 	orr r4, r4, r3 | ||
| 355 | 	mov r3, r5, lsr r12 | ||
| 356 | 	str r4, [r0], #4 | ||
| 357 | 	cmp r2, #4 | ||
| 358 | 	bhs 1b | ||
| 359 | |||
| 360 | partial_word_tail: | ||
| 361 | 	/* we have a partial word in the input buffer */ | ||
| 362 | 	movs r5, lr, lsl #(31-3) | ||
| 363 | 	strbmi r3, [r0], #1 | ||
| 364 | 	movmi r3, r3, lsr #8 | ||
| 365 | 	strbcs r3, [r0], #1 | ||
| 366 | 	movcs r3, r3, lsr #8 | ||
| 367 | 	strbcs r3, [r0], #1 | ||
| 368 | |||
| 369 | 	/* Refill spilled registers from the stack. Don't update sp. */ | ||
| 370 | 	ldmfd sp, {r5-r11} | ||
| 371 | |||
| 372 | copy_last_3_and_return: | ||
| 373 | 	movs r2, r2, lsl #31 /* copy remaining 0, 1, 2 or 3 bytes */ | ||
| 374 | 	ldrbmi r2, [r1], #1 | ||
| 375 | 	ldrbcs r3, [r1], #1 | ||
| 376 | 	ldrbcs r12,[r1] | ||
| 377 | 	strbmi r2, [r0], #1 | ||
| 378 | 	strbcs r3, [r0], #1 | ||
| 379 | 	strbcs r12,[r0] | ||
| 380 | |||
| 381 | 	/* we're done! restore sp and spilled registers and return */ | ||
| 382 | 	add sp, sp, #28 | ||
| 383 | 	ldmfd sp!, {r0, r4, lr} | ||
| 384 | 	bx lr | ||
| 385 | |||
| 386 | #endif | ||
lib/libc/musl/src/string/memccpy.c+1-1| ... | @@ -29,6 +29,6 @@ void *memccpy(void *restrict dest, const void *restrict src, int c, size_t n) | ... | @@ -29,6 +29,6 @@ void *memccpy(void *restrict dest, const void *restrict src, int c, size_t n) |
| 29 | #endif | 29 | #endif |
| 30 | 	for (; n && (*d=*s)!=c; n--, s++, d++); | 30 | 	for (; n && (*d=*s)!=c; n--, s++, d++); |
| 31 | tail: | 31 | tail: |
| 32 | 	if (n && *s==c) return d+1; | 32 | 	if (n) return d+1; |
| 33 | 	return 0; | 33 | 	return 0; |
| 34 | } | 34 | } |
lib/libc/musl/src/string/memmem.c+4-4| ... | @@ -12,8 +12,8 @@ static char *twobyte_memmem(const unsigned char *h, size_t k, const unsigned cha | ... | @@ -12,8 +12,8 @@ static char *twobyte_memmem(const unsigned char *h, size_t k, const unsigned cha |
| 12 | 12 | ||
| 13 | static char *threebyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) | 13 | static char *threebyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) |
| 14 | { | 14 | { |
| 15 | 	uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8; | 15 | 	uint32_t nw = (uint32_t)n[0]<<24 | n[1]<<16 | n[2]<<8; |
| 16 | 	uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8; | 16 | 	uint32_t hw = (uint32_t)h[0]<<24 | h[1]<<16 | h[2]<<8; |
| 17 | 	for (h+=3, k-=3; k; k--, hw = (hw|*h++)<<8) | 17 | 	for (h+=3, k-=3; k; k--, hw = (hw|*h++)<<8) |
| 18 | 		if (hw == nw) return (char *)h-3; | 18 | 		if (hw == nw) return (char *)h-3; |
| 19 | 	return hw == nw ? (char *)h-3 : 0; | 19 | 	return hw == nw ? (char *)h-3 : 0; |
| ... | @@ -21,8 +21,8 @@ static char *threebyte_memmem(const unsigned char *h, size_t k, const unsigned c | ... | @@ -21,8 +21,8 @@ static char *threebyte_memmem(const unsigned char *h, size_t k, const unsigned c |
| 21 | 21 | ||
| 22 | static char *fourbyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) | 22 | static char *fourbyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) |
| 23 | { | 23 | { |
| 24 | 	uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3]; | 24 | 	uint32_t nw = (uint32_t)n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3]; |
| 25 | 	uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3]; | 25 | 	uint32_t hw = (uint32_t)h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3]; |
| 26 | 	for (h+=4, k-=4; k; k--, hw = hw<<8 | *h++) | 26 | 	for (h+=4, k-=4; k; k--, hw = hw<<8 | *h++) |
| 27 | 		if (hw == nw) return (char *)h-4; | 27 | 		if (hw == nw) return (char *)h-4; |
| 28 | 	return hw == nw ? (char *)h-4 : 0; | 28 | 	return hw == nw ? (char *)h-4 : 0; |
lib/libc/musl/src/string/strsignal.c+10| ... | @@ -31,7 +31,11 @@ static const char map[] = { | ... | @@ -31,7 +31,11 @@ static const char map[] = { |
| 31 | 	[SIGPIPE] = 13, | 31 | 	[SIGPIPE] = 13, |
| 32 | 	[SIGALRM] = 14, | 32 | 	[SIGALRM] = 14, |
| 33 | 	[SIGTERM] = 15, | 33 | 	[SIGTERM] = 15, |
| 34 | #if defined(SIGSTKFLT) | ||
| 34 | 	[SIGSTKFLT] = 16, | 35 | 	[SIGSTKFLT] = 16, |
| 36 | #elif defined(SIGEMT) | ||
| 37 | 	[SIGEMT] = 16, | ||
| 38 | #endif | ||
| 35 | 	[SIGCHLD] = 17, | 39 | 	[SIGCHLD] = 17, |
| 36 | 	[SIGCONT] = 18, | 40 | 	[SIGCONT] = 18, |
| 37 | 	[SIGSTOP] = 19, | 41 | 	[SIGSTOP] = 19, |
| ... | @@ -70,7 +74,13 @@ static const char strings[] = | ... | @@ -70,7 +74,13 @@ static const char strings[] = |
| 70 | 	"Broken pipe\0" | 74 | 	"Broken pipe\0" |
| 71 | 	"Alarm clock\0" | 75 | 	"Alarm clock\0" |
| 72 | 	"Terminated\0" | 76 | 	"Terminated\0" |
| 77 | #if defined(SIGSTKFLT) | ||
| 73 | 	"Stack fault\0" | 78 | 	"Stack fault\0" |
| 79 | #elif defined(SIGEMT) | ||
| 80 | 	"Emulator trap\0" | ||
| 81 | #else | ||
| 82 | 	"Unknown signal\0" | ||
| 83 | #endif | ||
| 74 | 	"Child process status\0" | 84 | 	"Child process status\0" |
| 75 | 	"Continued\0" | 85 | 	"Continued\0" |
| 76 | 	"Stopped (signal)\0" | 86 | 	"Stopped (signal)\0" |
lib/libc/musl/src/string/strstr.c+4-4| ... | @@ -10,16 +10,16 @@ static char *twobyte_strstr(const unsigned char *h, const unsigned char *n) | ... | @@ -10,16 +10,16 @@ static char *twobyte_strstr(const unsigned char *h, const unsigned char *n) |
| 10 | 10 | ||
| 11 | static char *threebyte_strstr(const unsigned char *h, const unsigned char *n) | 11 | static char *threebyte_strstr(const unsigned char *h, const unsigned char *n) |
| 12 | { | 12 | { |
| 13 | 	uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8; | 13 | 	uint32_t nw = (uint32_t)n[0]<<24 | n[1]<<16 | n[2]<<8; |
| 14 | 	uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8; | 14 | 	uint32_t hw = (uint32_t)h[0]<<24 | h[1]<<16 | h[2]<<8; |
| 15 | 	for (h+=2; *h && hw != nw; hw = (hw|*++h)<<8); | 15 | 	for (h+=2; *h && hw != nw; hw = (hw|*++h)<<8); |
| 16 | 	return *h ? (char *)h-2 : 0; | 16 | 	return *h ? (char *)h-2 : 0; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | static char *fourbyte_strstr(const unsigned char *h, const unsigned char *n) | 19 | static char *fourbyte_strstr(const unsigned char *h, const unsigned char *n) |
| 20 | { | 20 | { |
| 21 | 	uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3]; | 21 | 	uint32_t nw = (uint32_t)n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3]; |
| 22 | 	uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3]; | 22 | 	uint32_t hw = (uint32_t)h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3]; |
| 23 | 	for (h+=3; *h && hw != nw; hw = hw<<8 | *++h); | 23 | 	for (h+=3; *h && hw != nw; hw = hw<<8 | *++h); |
| 24 | 	return *h ? (char *)h-3 : 0; | 24 | 	return *h ? (char *)h-3 : 0; |
| 25 | } | 25 | } |
lib/libc/musl/src/thread/__lock.c+3-1| ... | @@ -18,9 +18,11 @@ | ... | @@ -18,9 +18,11 @@ |
| 18 | 18 | ||
| 19 | void __lock(volatile int *l) | 19 | void __lock(volatile int *l) |
| 20 | { | 20 | { |
| 21 | 	if (!libc.threads_minus_1) return; | 21 | 	int need_locks = libc.need_locks; |
| 22 | 	if (!need_locks) return; | ||
| 22 | 	/* fast path: INT_MIN for the lock, +1 for the congestion */ | 23 | 	/* fast path: INT_MIN for the lock, +1 for the congestion */ |
| 23 | 	int current = a_cas(l, 0, INT_MIN + 1); | 24 | 	int current = a_cas(l, 0, INT_MIN + 1); |
| 25 | 	if (need_locks < 0) libc.need_locks = 0; | ||
| 24 | 	if (!current) return; | 26 | 	if (!current) return; |
| 25 | 	/* A first spin loop, for medium congestion. */ | 27 | 	/* A first spin loop, for medium congestion. */ |
| 26 | 	for (unsigned i = 0; i < 10; ++i) { | 28 | 	for (unsigned i = 0; i < 10; ++i) { |
lib/libc/musl/src/thread/pthread_create.c+19-15| ... | @@ -72,12 +72,13 @@ _Noreturn void __pthread_exit(void *result) | ... | @@ -72,12 +72,13 @@ _Noreturn void __pthread_exit(void *result) |
| 72 | 	/* Access to target the exiting thread with syscalls that use | 72 | 	/* Access to target the exiting thread with syscalls that use |
| 73 | 	 * its kernel tid is controlled by killlock. For detached threads, | 73 | 	 * its kernel tid is controlled by killlock. For detached threads, |
| 74 | 	 * any use past this point would have undefined behavior, but for | 74 | 	 * any use past this point would have undefined behavior, but for |
| 75 | 	 * joinable threads it's a valid usage that must be handled. */ | 75 | 	 * joinable threads it's a valid usage that must be handled. |
| 76 | 	 * Signals must be blocked since pthread_kill must be AS-safe. */ | ||
| 77 | 	__block_app_sigs(&set); | ||
| 76 | 	LOCK(self->killlock); | 78 | 	LOCK(self->killlock); |
| 77 | 79 | ||
| 78 | 	/* The thread list lock must be AS-safe, and thus requires | 80 | 	/* The thread list lock must be AS-safe, and thus depends on |
| 79 | 	 * application signals to be blocked before it can be taken. */ | 81 | 	 * application signals being blocked above. */ |
| 80 | 	__block_app_sigs(&set); | ||
| 81 | 	__tl_lock(); | 82 | 	__tl_lock(); |
| 82 | 83 | ||
| 83 | 	/* If this is the only thread in the list, don't proceed with | 84 | 	/* If this is the only thread in the list, don't proceed with |
| ... | @@ -85,19 +86,12 @@ _Noreturn void __pthread_exit(void *result) | ... | @@ -85,19 +86,12 @@ _Noreturn void __pthread_exit(void *result) |
| 85 | 	 * signal state to prepare for exit to call atexit handlers. */ | 86 | 	 * signal state to prepare for exit to call atexit handlers. */ |
| 86 | 	if (self->next == self) { | 87 | 	if (self->next == self) { |
| 87 | 		__tl_unlock(); | 88 | 		__tl_unlock(); |
| 88 | 		__restore_sigs(&set); | ||
| 89 | 		UNLOCK(self->killlock); | 89 | 		UNLOCK(self->killlock); |
| 90 | 		__restore_sigs(&set); | ||
| 90 | 		exit(0); | 91 | 		exit(0); |
| 91 | 	} | 92 | 	} |
| 92 | 93 | ||
| 93 | 	/* At this point we are committed to thread termination. Unlink | 94 | 	/* At this point we are committed to thread termination. */ |
| 94 | 	 * the thread from the list. This change will not be visible | ||
| 95 | 	 * until the lock is released, which only happens after SYS_exit | ||
| 96 | 	 * has been called, via the exit futex address pointing at the lock. */ | ||
| 97 | 	libc.threads_minus_1--; | ||
| 98 | 	self->next->prev = self->prev; | ||
| 99 | 	self->prev->next = self->next; | ||
| 100 | 	self->prev = self->next = self; | ||
| 101 | 95 | ||
| 102 | 	/* Process robust list in userspace to handle non-pshared mutexes | 96 | 	/* Process robust list in userspace to handle non-pshared mutexes |
| 103 | 	 * and the detached thread case where the robust list head will | 97 | 	 * and the detached thread case where the robust list head will |
| ... | @@ -121,6 +115,16 @@ _Noreturn void __pthread_exit(void *result) | ... | @@ -121,6 +115,16 @@ _Noreturn void __pthread_exit(void *result) |
| 121 | 	__do_orphaned_stdio_locks(); | 115 | 	__do_orphaned_stdio_locks(); |
| 122 | 	__dl_thread_cleanup(); | 116 | 	__dl_thread_cleanup(); |
| 123 | 117 | ||
| 118 | 	/* Last, unlink thread from the list. This change will not be visible | ||
| 119 | 	 * until the lock is released, which only happens after SYS_exit | ||
| 120 | 	 * has been called, via the exit futex address pointing at the lock. | ||
| 121 | 	 * This needs to happen after any possible calls to LOCK() that might | ||
| 122 | 	 * skip locking if process appears single-threaded. */ | ||
| 123 | 	if (!--libc.threads_minus_1) libc.need_locks = -1; | ||
| 124 | 	self->next->prev = self->prev; | ||
| 125 | 	self->prev->next = self->next; | ||
| 126 | 	self->prev = self->next = self; | ||
| 127 | |||
| 124 | 	/* This atomic potentially competes with a concurrent pthread_detach | 128 | 	/* This atomic potentially competes with a concurrent pthread_detach |
| 125 | 	 * call; the loser is responsible for freeing thread resources. */ | 129 | 	 * call; the loser is responsible for freeing thread resources. */ |
| 126 | 	int state = a_cas(&self->detach_state, DT_JOINABLE, DT_EXITING); | 130 | 	int state = a_cas(&self->detach_state, DT_JOINABLE, DT_EXITING); |
| ... | @@ -336,7 +340,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att | ... | @@ -336,7 +340,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att |
| 336 | 		~(1UL<<((SIGCANCEL-1)%(8*sizeof(long)))); | 340 | 		~(1UL<<((SIGCANCEL-1)%(8*sizeof(long)))); |
| 337 | 341 | ||
| 338 | 	__tl_lock(); | 342 | 	__tl_lock(); |
| 339 | 	libc.threads_minus_1++; | 343 | 	if (!libc.threads_minus_1++) libc.need_locks = 1; |
| 340 | 	ret = __clone((c11 ? start_c11 : start), stack, flags, args, &new->tid, TP_ADJ(new), &__thread_list_lock); | 344 | 	ret = __clone((c11 ? start_c11 : start), stack, flags, args, &new->tid, TP_ADJ(new), &__thread_list_lock); |
| 341 | 345 | ||
| 342 | 	/* All clone failures translate to EAGAIN. If explicit scheduling | 346 | 	/* All clone failures translate to EAGAIN. If explicit scheduling |
| ... | @@ -360,7 +364,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att | ... | @@ -360,7 +364,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att |
| 360 | 		new->next->prev = new; | 364 | 		new->next->prev = new; |
| 361 | 		new->prev->next = new; | 365 | 		new->prev->next = new; |
| 362 | 	} else { | 366 | 	} else { |
| 363 | 		libc.threads_minus_1--; | 367 | 		if (!--libc.threads_minus_1) libc.need_locks = 0; |
| 364 | 	} | 368 | 	} |
| 365 | 	__tl_unlock(); | 369 | 	__tl_unlock(); |
| 366 | 	__restore_sigs(&set); | 370 | 	__restore_sigs(&set); |
lib/libc/musl/src/thread/pthread_getschedparam.c+3| ... | @@ -4,6 +4,8 @@ | ... | @@ -4,6 +4,8 @@ |
| 4 | int pthread_getschedparam(pthread_t t, int *restrict policy, struct sched_param *restrict param) | 4 | int pthread_getschedparam(pthread_t t, int *restrict policy, struct sched_param *restrict param) |
| 5 | { | 5 | { |
| 6 | 	int r; | 6 | 	int r; |
| 7 | 	sigset_t set; | ||
| 8 | 	__block_app_sigs(&set); | ||
| 7 | 	LOCK(t->killlock); | 9 | 	LOCK(t->killlock); |
| 8 | 	if (!t->tid) { | 10 | 	if (!t->tid) { |
| 9 | 		r = ESRCH; | 11 | 		r = ESRCH; |
| ... | @@ -14,5 +16,6 @@ int pthread_getschedparam(pthread_t t, int *restrict policy, struct sched_param | ... | @@ -14,5 +16,6 @@ int pthread_getschedparam(pthread_t t, int *restrict policy, struct sched_param |
| 14 | 		} | 16 | 		} |
| 15 | 	} | 17 | 	} |
| 16 | 	UNLOCK(t->killlock); | 18 | 	UNLOCK(t->killlock); |
| 19 | 	__restore_sigs(&set); | ||
| 17 | 	return r; | 20 | 	return r; |
| 18 | } | 21 | } |
lib/libc/musl/src/thread/pthread_kill.c+6| ... | @@ -4,9 +4,15 @@ | ... | @@ -4,9 +4,15 @@ |
| 4 | int pthread_kill(pthread_t t, int sig) | 4 | int pthread_kill(pthread_t t, int sig) |
| 5 | { | 5 | { |
| 6 | 	int r; | 6 | 	int r; |
| 7 | 	sigset_t set; | ||
| 8 | 	/* Block not just app signals, but internal ones too, since | ||
| 9 | 	 * pthread_kill is used to implement pthread_cancel, which | ||
| 10 | 	 * must be async-cancel-safe. */ | ||
| 11 | 	__block_all_sigs(&set); | ||
| 7 | 	LOCK(t->killlock); | 12 | 	LOCK(t->killlock); |
| 8 | 	r = t->tid ? -__syscall(SYS_tkill, t->tid, sig) | 13 | 	r = t->tid ? -__syscall(SYS_tkill, t->tid, sig) |
| 9 | 		: (sig+0U >= _NSIG ? EINVAL : 0); | 14 | 		: (sig+0U >= _NSIG ? EINVAL : 0); |
| 10 | 	UNLOCK(t->killlock); | 15 | 	UNLOCK(t->killlock); |
| 16 | 	__restore_sigs(&set); | ||
| 11 | 	return r; | 17 | 	return r; |
| 12 | } | 18 | } |
lib/libc/musl/src/thread/pthread_setschedparam.c+3| ... | @@ -4,8 +4,11 @@ | ... | @@ -4,8 +4,11 @@ |
| 4 | int pthread_setschedparam(pthread_t t, int policy, const struct sched_param *param) | 4 | int pthread_setschedparam(pthread_t t, int policy, const struct sched_param *param) |
| 5 | { | 5 | { |
| 6 | 	int r; | 6 | 	int r; |
| 7 | 	sigset_t set; | ||
| 8 | 	__block_app_sigs(&set); | ||
| 7 | 	LOCK(t->killlock); | 9 | 	LOCK(t->killlock); |
| 8 | 	r = !t->tid ? ESRCH : -__syscall(SYS_sched_setscheduler, t->tid, policy, param); | 10 | 	r = !t->tid ? ESRCH : -__syscall(SYS_sched_setscheduler, t->tid, policy, param); |
| 9 | 	UNLOCK(t->killlock); | 11 | 	UNLOCK(t->killlock); |
| 12 | 	__restore_sigs(&set); | ||
| 10 | 	return r; | 13 | 	return r; |
| 11 | } | 14 | } |
lib/libc/musl/src/thread/pthread_setschedprio.c+3| ... | @@ -4,8 +4,11 @@ | ... | @@ -4,8 +4,11 @@ |
| 4 | int pthread_setschedprio(pthread_t t, int prio) | 4 | int pthread_setschedprio(pthread_t t, int prio) |
| 5 | { | 5 | { |
| 6 | 	int r; | 6 | 	int r; |
| 7 | 	sigset_t set; | ||
| 8 | 	__block_app_sigs(&set); | ||
| 7 | 	LOCK(t->killlock); | 9 | 	LOCK(t->killlock); |
| 8 | 	r = !t->tid ? ESRCH : -__syscall(SYS_sched_setparam, t->tid, &prio); | 10 | 	r = !t->tid ? ESRCH : -__syscall(SYS_sched_setparam, t->tid, &prio); |
| 9 | 	UNLOCK(t->killlock); | 11 | 	UNLOCK(t->killlock); |
| 12 | 	__restore_sigs(&set); | ||
| 10 | 	return r; | 13 | 	return r; |
| 11 | } | 14 | } |
lib/libc/musl/src/time/__tz.c+6-6| ... | @@ -86,15 +86,15 @@ static void getname(char *d, const char **p) | ... | @@ -86,15 +86,15 @@ static void getname(char *d, const char **p) |
| 86 | 	int i; | 86 | 	int i; |
| 87 | 	if (**p == '<') { | 87 | 	if (**p == '<') { |
| 88 | 		++*p; | 88 | 		++*p; |
| 89 | 		for (i=0; (*p)[i]!='>' && i<TZNAME_MAX; i++) | 89 | 		for (i=0; (*p)[i] && (*p)[i]!='>'; i++) |
| 90 | 			d[i] = (*p)[i]; | 90 | 			if (i<TZNAME_MAX) d[i] = (*p)[i]; |
| 91 | 		++*p; | 91 | 		if ((*p)[i]) ++*p; |
| 92 | 	} else { | 92 | 	} else { |
| 93 | 		for (i=0; ((*p)[i]|32)-'a'<26U && i<TZNAME_MAX; i++) | 93 | 		for (i=0; ((*p)[i]|32)-'a'<26U; i++) |
| 94 | 			d[i] = (*p)[i]; | 94 | 			if (i<TZNAME_MAX) d[i] = (*p)[i]; |
| 95 | 	} | 95 | 	} |
| 96 | 	*p += i; | 96 | 	*p += i; |
| 97 | 	d[i] = 0; | 97 | 	d[i<TZNAME_MAX?i:TZNAME_MAX] = 0; |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | #define VEC(...) ((const unsigned char[]){__VA_ARGS__}) | 100 | #define VEC(...) ((const unsigned char[]){__VA_ARGS__}) |
src/musl.zig+49-43| ... | @@ -656,13 +656,17 @@ const src_files = [_][]const u8{ | ... | @@ -656,13 +656,17 @@ const src_files = [_][]const u8{ |
| 656 | "musl/src/locale/uselocale.c", | 656 | "musl/src/locale/uselocale.c", |
| 657 | "musl/src/locale/wcscoll.c", | 657 | "musl/src/locale/wcscoll.c", |
| 658 | "musl/src/locale/wcsxfrm.c", | 658 | "musl/src/locale/wcsxfrm.c", |
| 659 | "musl/src/malloc/aligned_alloc.c", | 659 | "musl/src/malloc/calloc.c", |
| 660 | "musl/src/malloc/expand_heap.c", | ||
| 661 | "musl/src/malloc/lite_malloc.c", | 660 | "musl/src/malloc/lite_malloc.c", |
| 662 | "musl/src/malloc/malloc.c", | 661 | "musl/src/malloc/mallocng/aligned_alloc.c", |
| 663 | "musl/src/malloc/malloc_usable_size.c", | 662 | "musl/src/malloc/mallocng/donate.c", |
| 663 | "musl/src/malloc/mallocng/free.c", | ||
| 664 | "musl/src/malloc/mallocng/malloc.c", | ||
| 665 | "musl/src/malloc/mallocng/malloc_usable_size.c", | ||
| 666 | "musl/src/malloc/mallocng/realloc.c", | ||
| 664 | "musl/src/malloc/memalign.c", | 667 | "musl/src/malloc/memalign.c", |
| 665 | "musl/src/malloc/posix_memalign.c", | 668 | "musl/src/malloc/posix_memalign.c", |
| 669 | "musl/src/malloc/replaced.c", | ||
| 666 | "musl/src/math/__cos.c", | 670 | "musl/src/math/__cos.c", |
| 667 | "musl/src/math/__cosdf.c", | 671 | "musl/src/math/__cosdf.c", |
| 668 | "musl/src/math/__cosl.c", | 672 | "musl/src/math/__cosl.c", |
| ... | @@ -834,23 +838,23 @@ const src_files = [_][]const u8{ | ... | @@ -834,23 +838,23 @@ const src_files = [_][]const u8{ |
| 834 | "musl/src/math/i386/exp_ld.s", | 838 | "musl/src/math/i386/exp_ld.s", |
| 835 | "musl/src/math/i386/expl.s", | 839 | "musl/src/math/i386/expl.s", |
| 836 | "musl/src/math/i386/expm1l.s", | 840 | "musl/src/math/i386/expm1l.s", |
| 837 | "musl/src/math/i386/fabs.s", | 841 | "musl/src/math/i386/fabs.c", |
| 838 | "musl/src/math/i386/fabsf.s", | 842 | "musl/src/math/i386/fabsf.c", |
| 839 | "musl/src/math/i386/fabsl.s", | 843 | "musl/src/math/i386/fabsl.c", |
| 840 | "musl/src/math/i386/floor.s", | 844 | "musl/src/math/i386/floor.s", |
| 841 | "musl/src/math/i386/floorf.s", | 845 | "musl/src/math/i386/floorf.s", |
| 842 | "musl/src/math/i386/floorl.s", | 846 | "musl/src/math/i386/floorl.s", |
| 843 | "musl/src/math/i386/fmod.s", | 847 | "musl/src/math/i386/fmod.c", |
| 844 | "musl/src/math/i386/fmodf.s", | 848 | "musl/src/math/i386/fmodf.c", |
| 845 | "musl/src/math/i386/fmodl.s", | 849 | "musl/src/math/i386/fmodl.c", |
| 846 | "musl/src/math/i386/hypot.s", | 850 | "musl/src/math/i386/hypot.s", |
| 847 | "musl/src/math/i386/hypotf.s", | 851 | "musl/src/math/i386/hypotf.s", |
| 848 | "musl/src/math/i386/ldexp.s", | 852 | "musl/src/math/i386/ldexp.s", |
| 849 | "musl/src/math/i386/ldexpf.s", | 853 | "musl/src/math/i386/ldexpf.s", |
| 850 | "musl/src/math/i386/ldexpl.s", | 854 | "musl/src/math/i386/ldexpl.s", |
| 851 | "musl/src/math/i386/llrint.s", | 855 | "musl/src/math/i386/llrint.c", |
| 852 | "musl/src/math/i386/llrintf.s", | 856 | "musl/src/math/i386/llrintf.c", |
| 853 | "musl/src/math/i386/llrintl.s", | 857 | "musl/src/math/i386/llrintl.c", |
| 854 | "musl/src/math/i386/log.s", | 858 | "musl/src/math/i386/log.s", |
| 855 | "musl/src/math/i386/log10.s", | 859 | "musl/src/math/i386/log10.s", |
| 856 | "musl/src/math/i386/log10f.s", | 860 | "musl/src/math/i386/log10f.s", |
| ... | @@ -863,27 +867,27 @@ const src_files = [_][]const u8{ | ... | @@ -863,27 +867,27 @@ const src_files = [_][]const u8{ |
| 863 | "musl/src/math/i386/log2l.s", | 867 | "musl/src/math/i386/log2l.s", |
| 864 | "musl/src/math/i386/logf.s", | 868 | "musl/src/math/i386/logf.s", |
| 865 | "musl/src/math/i386/logl.s", | 869 | "musl/src/math/i386/logl.s", |
| 866 | "musl/src/math/i386/lrint.s", | 870 | "musl/src/math/i386/lrint.c", |
| 867 | "musl/src/math/i386/lrintf.s", | 871 | "musl/src/math/i386/lrintf.c", |
| 868 | "musl/src/math/i386/lrintl.s", | 872 | "musl/src/math/i386/lrintl.c", |
| 869 | "musl/src/math/i386/remainder.s", | 873 | "musl/src/math/i386/remainder.c", |
| 870 | "musl/src/math/i386/remainderf.s", | 874 | "musl/src/math/i386/remainderf.c", |
| 871 | "musl/src/math/i386/remainderl.s", | 875 | "musl/src/math/i386/remainderl.c", |
| 872 | "musl/src/math/i386/remquo.s", | 876 | "musl/src/math/i386/remquo.s", |
| 873 | "musl/src/math/i386/remquof.s", | 877 | "musl/src/math/i386/remquof.s", |
| 874 | "musl/src/math/i386/remquol.s", | 878 | "musl/src/math/i386/remquol.s", |
| 875 | "musl/src/math/i386/rint.s", | 879 | "musl/src/math/i386/rint.c", |
| 876 | "musl/src/math/i386/rintf.s", | 880 | "musl/src/math/i386/rintf.c", |
| 877 | "musl/src/math/i386/rintl.s", | 881 | "musl/src/math/i386/rintl.c", |
| 878 | "musl/src/math/i386/scalbln.s", | 882 | "musl/src/math/i386/scalbln.s", |
| 879 | "musl/src/math/i386/scalblnf.s", | 883 | "musl/src/math/i386/scalblnf.s", |
| 880 | "musl/src/math/i386/scalblnl.s", | 884 | "musl/src/math/i386/scalblnl.s", |
| 881 | "musl/src/math/i386/scalbn.s", | 885 | "musl/src/math/i386/scalbn.s", |
| 882 | "musl/src/math/i386/scalbnf.s", | 886 | "musl/src/math/i386/scalbnf.s", |
| 883 | "musl/src/math/i386/scalbnl.s", | 887 | "musl/src/math/i386/scalbnl.s", |
| 884 | "musl/src/math/i386/sqrt.s", | 888 | "musl/src/math/i386/sqrt.c", |
| 885 | "musl/src/math/i386/sqrtf.s", | 889 | "musl/src/math/i386/sqrtf.c", |
| 886 | "musl/src/math/i386/sqrtl.s", | 890 | "musl/src/math/i386/sqrtl.c", |
| 887 | "musl/src/math/i386/trunc.s", | 891 | "musl/src/math/i386/trunc.s", |
| 888 | "musl/src/math/i386/truncf.s", | 892 | "musl/src/math/i386/truncf.s", |
| 889 | "musl/src/math/i386/truncl.s", | 893 | "musl/src/math/i386/truncl.s", |
| ... | @@ -935,6 +939,7 @@ const src_files = [_][]const u8{ | ... | @@ -935,6 +939,7 @@ const src_files = [_][]const u8{ |
| 935 | "musl/src/math/lround.c", | 939 | "musl/src/math/lround.c", |
| 936 | "musl/src/math/lroundf.c", | 940 | "musl/src/math/lroundf.c", |
| 937 | "musl/src/math/lroundl.c", | 941 | "musl/src/math/lroundl.c", |
| 942 | "musl/src/math/m68k/sqrtl.c", | ||
| 938 | "musl/src/math/mips/fabs.c", | 943 | "musl/src/math/mips/fabs.c", |
| 939 | "musl/src/math/mips/fabsf.c", | 944 | "musl/src/math/mips/fabsf.c", |
| 940 | "musl/src/math/mips/sqrt.c", | 945 | "musl/src/math/mips/sqrt.c", |
| ... | @@ -1113,28 +1118,29 @@ const src_files = [_][]const u8{ | ... | @@ -1113,28 +1118,29 @@ const src_files = [_][]const u8{ |
| 1113 | "musl/src/math/x86_64/exp2l.s", | 1118 | "musl/src/math/x86_64/exp2l.s", |
| 1114 | "musl/src/math/x86_64/expl.s", | 1119 | "musl/src/math/x86_64/expl.s", |
| 1115 | "musl/src/math/x86_64/expm1l.s", | 1120 | "musl/src/math/x86_64/expm1l.s", |
| 1116 | "musl/src/math/x86_64/fabs.s", | 1121 | "musl/src/math/x86_64/fabs.c", |
| 1117 | "musl/src/math/x86_64/fabsf.s", | 1122 | "musl/src/math/x86_64/fabsf.c", |
| 1118 | "musl/src/math/x86_64/fabsl.s", | 1123 | "musl/src/math/x86_64/fabsl.c", |
| 1119 | "musl/src/math/x86_64/floorl.s", | 1124 | "musl/src/math/x86_64/floorl.s", |
| 1120 | "musl/src/math/x86_64/fma.c", | 1125 | "musl/src/math/x86_64/fma.c", |
| 1121 | "musl/src/math/x86_64/fmaf.c", | 1126 | "musl/src/math/x86_64/fmaf.c", |
| 1122 | "musl/src/math/x86_64/fmodl.s", | 1127 | "musl/src/math/x86_64/fmodl.c", |
| 1123 | "musl/src/math/x86_64/llrint.s", | 1128 | "musl/src/math/x86_64/llrint.c", |
| 1124 | "musl/src/math/x86_64/llrintf.s", | 1129 | "musl/src/math/x86_64/llrintf.c", |
| 1125 | "musl/src/math/x86_64/llrintl.s", | 1130 | "musl/src/math/x86_64/llrintl.c", |
| 1126 | "musl/src/math/x86_64/log10l.s", | 1131 | "musl/src/math/x86_64/log10l.s", |
| 1127 | "musl/src/math/x86_64/log1pl.s", | 1132 | "musl/src/math/x86_64/log1pl.s", |
| 1128 | "musl/src/math/x86_64/log2l.s", | 1133 | "musl/src/math/x86_64/log2l.s", |
| 1129 | "musl/src/math/x86_64/logl.s", | 1134 | "musl/src/math/x86_64/logl.s", |
| 1130 | "musl/src/math/x86_64/lrint.s", | 1135 | "musl/src/math/x86_64/lrint.c", |
| 1131 | "musl/src/math/x86_64/lrintf.s", | 1136 | "musl/src/math/x86_64/lrintf.c", |
| 1132 | "musl/src/math/x86_64/lrintl.s", | 1137 | "musl/src/math/x86_64/lrintl.c", |
| 1133 | "musl/src/math/x86_64/remainderl.s", | 1138 | "musl/src/math/x86_64/remainderl.c", |
| 1134 | "musl/src/math/x86_64/rintl.s", | 1139 | "musl/src/math/x86_64/remquol.c", |
| 1135 | "musl/src/math/x86_64/sqrt.s", | 1140 | "musl/src/math/x86_64/rintl.c", |
| 1136 | "musl/src/math/x86_64/sqrtf.s", | 1141 | "musl/src/math/x86_64/sqrt.c", |
| 1137 | "musl/src/math/x86_64/sqrtl.s", | 1142 | "musl/src/math/x86_64/sqrtf.c", |
| 1143 | "musl/src/math/x86_64/sqrtl.c", | ||
| 1138 | "musl/src/math/x86_64/truncl.s", | 1144 | "musl/src/math/x86_64/truncl.s", |
| 1139 | "musl/src/misc/a64l.c", | 1145 | "musl/src/misc/a64l.c", |
| 1140 | "musl/src/misc/basename.c", | 1146 | "musl/src/misc/basename.c", |
| ... | @@ -1528,7 +1534,6 @@ const src_files = [_][]const u8{ | ... | @@ -1528,7 +1534,6 @@ const src_files = [_][]const u8{ |
| 1528 | "musl/src/stdio/__stdio_seek.c", | 1534 | "musl/src/stdio/__stdio_seek.c", |
| 1529 | "musl/src/stdio/__stdio_write.c", | 1535 | "musl/src/stdio/__stdio_write.c", |
| 1530 | "musl/src/stdio/__stdout_write.c", | 1536 | "musl/src/stdio/__stdout_write.c", |
| 1531 | "musl/src/stdio/__string_read.c", | ||
| 1532 | "musl/src/stdio/__toread.c", | 1537 | "musl/src/stdio/__toread.c", |
| 1533 | "musl/src/stdio/__towrite.c", | 1538 | "musl/src/stdio/__towrite.c", |
| 1534 | "musl/src/stdio/__uflow.c", | 1539 | "musl/src/stdio/__uflow.c", |
| ... | @@ -1654,10 +1659,11 @@ const src_files = [_][]const u8{ | ... | @@ -1654,10 +1659,11 @@ const src_files = [_][]const u8{ |
| 1654 | "musl/src/stdlib/strtol.c", | 1659 | "musl/src/stdlib/strtol.c", |
| 1655 | "musl/src/stdlib/wcstod.c", | 1660 | "musl/src/stdlib/wcstod.c", |
| 1656 | "musl/src/stdlib/wcstol.c", | 1661 | "musl/src/stdlib/wcstol.c", |
| 1662 | "musl/src/string/aarch64/memcpy.S", | ||
| 1663 | "musl/src/string/aarch64/memset.S", | ||
| 1657 | "musl/src/string/arm/__aeabi_memcpy.s", | 1664 | "musl/src/string/arm/__aeabi_memcpy.s", |
| 1658 | "musl/src/string/arm/__aeabi_memset.s", | 1665 | "musl/src/string/arm/__aeabi_memset.s", |
| 1659 | "musl/src/string/arm/memcpy.c", | 1666 | "musl/src/string/arm/memcpy.S", |
| 1660 | "musl/src/string/arm/memcpy_le.S", | ||
| 1661 | "musl/src/string/bcmp.c", | 1667 | "musl/src/string/bcmp.c", |
| 1662 | "musl/src/string/bcopy.c", | 1668 | "musl/src/string/bcopy.c", |
| 1663 | "musl/src/string/bzero.c", | 1669 | "musl/src/string/bzero.c", |