mirror of
				https://github.com/jart/cosmopolitan.git
				synced 2025-10-26 11:10:58 +00:00 
			
		
		
		
	Make improvements
- Implement openpty() - Add `--assimilate` flag to APE bootloader - Restore Linux vDSO clock_gettime() support - Use `$(APE_NO_MODIFY_SELF)` on more programs
This commit is contained in:
		
							parent
							
								
									cef50f2a6b
								
							
						
					
					
						commit
						d44ff6ce1f
					
				
					 33 changed files with 600 additions and 251 deletions
				
			
		
							
								
								
									
										50
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										50
									
								
								README.md
									
										
									
									
									
								
							|  | @ -28,21 +28,57 @@ printf 'main() { printf("hello world\\n"); }\n' >hello.c | ||||||
| gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \ | gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \ | ||||||
|   -fno-omit-frame-pointer -pg -mnop-mcount \ |   -fno-omit-frame-pointer -pg -mnop-mcount \ | ||||||
|   -o hello.com.dbg hello.c -fuse-ld=bfd -Wl,-T,ape.lds \ |   -o hello.com.dbg hello.c -fuse-ld=bfd -Wl,-T,ape.lds \ | ||||||
|   -include cosmopolitan.h crt.o ape.o cosmopolitan.a |   -include cosmopolitan.h crt.o ape-no-modify-self.o cosmopolitan.a | ||||||
| objcopy -S -O binary hello.com.dbg hello.com | objcopy -S -O binary hello.com.dbg hello.com | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| You now have a portable program. Please note that your APE binary will | You now have a portable program. | ||||||
| assimilate itself as a conventional resident of your platform after the |  | ||||||
| first run, so it can be fast and efficient for subsequent executions. |  | ||||||
| 
 | 
 | ||||||
| ```sh | ```sh | ||||||
| ./hello.com | ./hello.com | ||||||
| bash -c './hello.com'  # zsh/fish workaround (we upstreamed patches) | bash -c './hello.com'  # zsh/fish workaround (we patched them in 2021) | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| So if you intend to copy the binary to Windows or Mac then please do | Since we used the `ape-no-modify-self.o` bootloader (rather than | ||||||
| that before you run it, not after. | `ape.o`) your executable will not modify itself when it's run. What | ||||||
|  | it'll instead do, is extract a 4kb program to `${TMPDIR:-/tmp}` that | ||||||
|  | maps your program into memory without needing to copy it. It's possible | ||||||
|  | to install the APE loader systemwide as follows. | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | # (1) linux systems that want binfmt_misc | ||||||
|  | ape/apeinstall.sh | ||||||
|  | 
 | ||||||
|  | # (2) for linux/freebsd/netbsd/openbsd systems | ||||||
|  | cp build/bootstrap/ape.elf /usr/bin/ape | ||||||
|  | 
 | ||||||
|  | # (3) for mac os x systems | ||||||
|  | cp build/bootstrap/ape.macho /usr/bin/ape | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | If you followed steps (2) and (3) then there's going to be a slight | ||||||
|  | constant-time startup latency each time you run an APE binary. Your | ||||||
|  | system might also prevent your APE program from being installed to a | ||||||
|  | system directory as a setuid binary or a script interpreter. To solve | ||||||
|  | that, you can use the following flag to turn your binary into the | ||||||
|  | platform local format (ELF or Mach-O): | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | ./hello.com --assimilate | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | There's also some other useful flags that get baked into your binary by | ||||||
|  | default: | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | ./hello.com --strace | ||||||
|  | ./hello.com --ftrace | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | If you want your `hello.com` program to be much tinier, more on the | ||||||
|  | order of 16kb rather than 60kb, then all you have to do is use | ||||||
|  | <https://justine.lol/cosmopolitan/cosmopolitan-tiny.zip> instead. See | ||||||
|  | <https://justine.lol/cosmopolitan/download.html>. | ||||||
| 
 | 
 | ||||||
| ### MacOS | ### MacOS | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -542,6 +542,7 @@ apesh:	.ascii	"'\n#'\"\n"			# sixth edition shebang | ||||||
| //	present two choices. | //	present two choices. | ||||||
| 	.ascii	"o=\"$(command -v \"$0\")\"\n" | 	.ascii	"o=\"$(command -v \"$0\")\"\n" | ||||||
| //	Try to use a system-wide APE loader. | //	Try to use a system-wide APE loader. | ||||||
|  | 	.ascii	"[ x\"$1\" != x--assimilate ] && " | ||||||
| 	.ascii	  "type ape >/dev/null 2>&1 && " | 	.ascii	  "type ape >/dev/null 2>&1 && " | ||||||
| 	.ascii	    "exec ape \"$o\" \"$@\"\n"
 | 	.ascii	    "exec ape \"$o\" \"$@\"\n"
 | ||||||
| #ifdef APE_LOADER | #ifdef APE_LOADER | ||||||
|  | @ -549,6 +550,7 @@ apesh:	.ascii	"'\n#'\"\n"			# sixth edition shebang | ||||||
| //	embedded inside the APE. So if the system is not MacOs, | //	embedded inside the APE. So if the system is not MacOs, | ||||||
| //	extract the loader into a temp folder, and use it to | //	extract the loader into a temp folder, and use it to | ||||||
| //	load the APE without modifying it. | //	load the APE without modifying it. | ||||||
|  | 	.ascii	"[ x\"$1\" != x--assimilate ] && {\n" | ||||||
| 	.ascii	  "t=\"${TMPDIR:-/tmp}/ape\"\n" | 	.ascii	  "t=\"${TMPDIR:-/tmp}/ape\"\n" | ||||||
| 	.ascii	  "[ -x \"$t\" ] || {\n" | 	.ascii	  "[ -x \"$t\" ] || {\n" | ||||||
| 	.ascii	    "dd if=\"$o\" of=\"$t.$$\" skip=\"" | 	.ascii	    "dd if=\"$o\" of=\"$t.$$\" skip=\"" | ||||||
|  | @ -570,6 +572,7 @@ apesh:	.ascii	"'\n#'\"\n"			# sixth edition shebang | ||||||
| 	.ascii	    "mv -f \"$t.$$\" \"$t\"\n" | 	.ascii	    "mv -f \"$t.$$\" \"$t\"\n" | ||||||
| 	.ascii	  "}\n" | 	.ascii	  "}\n" | ||||||
| 	.ascii	  "exec \"$t\" \"$o\" \"$@\"\n"
 | 	.ascii	  "exec \"$t\" \"$o\" \"$@\"\n"
 | ||||||
|  | 	.ascii	"}\n" | ||||||
| #endif /* APE_LOADER */ | #endif /* APE_LOADER */ | ||||||
| #ifndef APE_NO_MODIFY_SELF | #ifndef APE_NO_MODIFY_SELF | ||||||
| //	The default behavior is: to overwrite the header in place. | //	The default behavior is: to overwrite the header in place. | ||||||
|  | @ -590,11 +593,13 @@ apesh:	.ascii	"'\n#'\"\n"			# sixth edition shebang | ||||||
| //	since only root is able to set the sticky bit, which can | //	since only root is able to set the sticky bit, which can | ||||||
| //	be addressed simply by overriding the TMPDIR environment | //	be addressed simply by overriding the TMPDIR environment | ||||||
| 	.ascii	"t=\"${TMPDIR:-/tmp}/$0\"\n" | 	.ascii	"t=\"${TMPDIR:-/tmp}/$0\"\n" | ||||||
| 	.ascii	"[ -e \"$t\" ] || {\n" | 	.ascii	"[ x\"$1\" != x--assimilate ] || [ ! -e \"$t\" ] && {\n" | ||||||
|  | 	.ascii	  "[ x\"$1\" != x--assimilate ] && {\n" | ||||||
| 	.ascii	    "mkdir -p \"${t%/*}\" 2>/dev/null\n" | 	.ascii	    "mkdir -p \"${t%/*}\" 2>/dev/null\n" | ||||||
| 	.ascii	    "cp -f \"$o\" \"$t.$$\" &&\n" | 	.ascii	    "cp -f \"$o\" \"$t.$$\" &&\n" | ||||||
| 	.ascii	    "mv -f \"$t.$$\" \"$t\" || exit 120\n" | 	.ascii	    "mv -f \"$t.$$\" \"$t\" || exit 120\n" | ||||||
| 	.ascii	    "o=\"$t\"\n" | 	.ascii	    "o=\"$t\"\n" | ||||||
|  | 	.ascii	  "}\n" | ||||||
| #endif /* APE_NO_MODIFY_SELF */ | #endif /* APE_NO_MODIFY_SELF */ | ||||||
| 	.ascii	"exec 7<> \"$o\" || exit 121\n" | 	.ascii	"exec 7<> \"$o\" || exit 121\n" | ||||||
| 	.ascii	"printf '" | 	.ascii	"printf '" | ||||||
|  | @ -632,6 +637,7 @@ apesh:	.ascii	"'\n#'\"\n"			# sixth edition shebang | ||||||
| 	.shstub	    ape_macho_dd_count,2 | 	.shstub	    ape_macho_dd_count,2 | ||||||
| 	.ascii	    "\" conv=notrunc 2>/dev/null\n" | 	.ascii	    "\" conv=notrunc 2>/dev/null\n" | ||||||
| #endif /* XNU */ | #endif /* XNU */ | ||||||
|  | 	.ascii	"[ x\"$1\" = x--assimilate ] && exit 0\n" | ||||||
| #ifndef APE_NO_MODIFY_SELF | #ifndef APE_NO_MODIFY_SELF | ||||||
| 	.ascii	"exec \"$0\" \"$@\"\n"		# try to preserve argv[0]
 | 	.ascii	"exec \"$0\" \"$@\"\n"		# try to preserve argv[0]
 | ||||||
| #else | #else | ||||||
|  |  | ||||||
|  | @ -112,6 +112,14 @@ o/$(MODE)/examples/nomodifyself.com.dbg:					\ | ||||||
| 		$(APE_NO_MODIFY_SELF) | 		$(APE_NO_MODIFY_SELF) | ||||||
| 	@$(APELINK) | 	@$(APELINK) | ||||||
| 
 | 
 | ||||||
|  | o/$(MODE)/examples/greenbean.com.dbg:						\ | ||||||
|  | 		$(EXAMPLES_DEPS)						\
 | ||||||
|  | 		o/$(MODE)/examples/greenbean.o					\
 | ||||||
|  | 		o/$(MODE)/examples/examples.pkg					\
 | ||||||
|  | 		$(CRT)								\
 | ||||||
|  | 		$(APE_NO_MODIFY_SELF) | ||||||
|  | 	@$(APELINK) | ||||||
|  | 
 | ||||||
| o/$(MODE)/examples/hellolua.com.dbg:						\ | o/$(MODE)/examples/hellolua.com.dbg:						\ | ||||||
| 		$(EXAMPLES_DEPS)						\
 | 		$(EXAMPLES_DEPS)						\
 | ||||||
| 		o/$(MODE)/examples/hellolua.o					\
 | 		o/$(MODE)/examples/hellolua.o					\
 | ||||||
|  | @ -162,4 +170,5 @@ usr/share/dict/words: usr/share/dict/words.gz | ||||||
| .PHONY: o/$(MODE)/examples | .PHONY: o/$(MODE)/examples | ||||||
| o/$(MODE)/examples:								\ | o/$(MODE)/examples:								\ | ||||||
| 		o/$(MODE)/examples/package					\
 | 		o/$(MODE)/examples/package					\
 | ||||||
|  | 		o/$(MODE)/examples/pyapp					\
 | ||||||
| 		$(EXAMPLES_BINS) | 		$(EXAMPLES_BINS) | ||||||
|  |  | ||||||
|  | @ -70,20 +70,20 @@ | ||||||
|  * Like redbean, greenbean has superior performance too, with an |  * Like redbean, greenbean has superior performance too, with an | ||||||
|  * advantage on benchmarks biased towards high connection counts |  * advantage on benchmarks biased towards high connection counts | ||||||
|  * |  * | ||||||
|  *     $ sudo wrk -c 300 -t 32 --latency http://10.10.10.124:8080/
 |  *     $ wrk -c 300 -t 32 --latency http://10.10.10.124:8080/
 | ||||||
|  *     Running 10s test @ http://10.10.10.124:8080/
 |  *     Running 10s test @ http://10.10.10.124:8080/
 | ||||||
|  *       32 threads and 300 connections |  *       32 threads and 300 connections | ||||||
|  *         Thread Stats   Avg      Stdev     Max   +/- Stdev |  *         Thread Stats   Avg      Stdev     Max   +/- Stdev | ||||||
|  *         Latency     1.07ms    8.27ms 138.55ms   98.58% |  *         Latency   661.06us    5.11ms  96.22ms   98.85% | ||||||
|  *         Req/Sec    37.98k    12.61k  117.65k    80.11% |  *         Req/Sec    42.38k     8.90k   90.47k    84.65% | ||||||
|  *       Latency Distribution |  *       Latency Distribution | ||||||
|  *          50%  200.00us |  *          50%  184.00us | ||||||
|  *          75%  227.00us |  *          75%  201.00us | ||||||
|  *          90%  303.00us |  *          90%  224.00us | ||||||
|  *          99%   32.46ms |  *          99%   11.99ms | ||||||
|  *       10033090 requests in 8.31s, 2.96GB read |  *       10221978 requests in 7.60s, 3.02GB read | ||||||
|  *     Requests/sec: 1207983.58 |  *     Requests/sec: 1345015.69 | ||||||
|  *     Transfer/sec:    365.19MB |  *     Transfer/sec:    406.62MB | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | @ -97,6 +97,7 @@ | ||||||
|   "Referrer-Policy: origin\r\n"   \ |   "Referrer-Policy: origin\r\n"   \ | ||||||
|   "Cache-Control: private; max-age=0\r\n" |   "Cache-Control: private; max-age=0\r\n" | ||||||
| 
 | 
 | ||||||
|  | int threads; | ||||||
| _Atomic(int) workers; | _Atomic(int) workers; | ||||||
| _Atomic(int) messages; | _Atomic(int) messages; | ||||||
| _Atomic(int) listening; | _Atomic(int) listening; | ||||||
|  | @ -114,7 +115,9 @@ int Worker(void *id) { | ||||||
| 
 | 
 | ||||||
|   server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); |   server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); | ||||||
|   if (server == -1) { |   if (server == -1) { | ||||||
|     if (LOGGING) kprintf("%s() failed %m\n", "socket"); |     kprintf("socket() failed %m\n" | ||||||
|  |             "  try running: sudo prlimit --pid=$$ --nofile=%d\n", | ||||||
|  |             threads * 2); | ||||||
|     goto WorkerFinished; |     goto WorkerFinished; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -127,8 +130,8 @@ int Worker(void *id) { | ||||||
|   errno = 0; |   errno = 0; | ||||||
| 
 | 
 | ||||||
|   if (bind(server, &addr, sizeof(addr)) == -1) { |   if (bind(server, &addr, sizeof(addr)) == -1) { | ||||||
|     if (LOGGING) kprintf("%s() failed %m\n", "socket"); |     kprintf("%s() failed %m\n", "socket"); | ||||||
|     goto WorkerFinished; |     goto CloseWorker; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   listen(server, 1); |   listen(server, 1); | ||||||
|  | @ -246,8 +249,9 @@ int Worker(void *id) { | ||||||
|   --listening; |   --listening; | ||||||
| 
 | 
 | ||||||
|   // inform the parent that this clone has finished
 |   // inform the parent that this clone has finished
 | ||||||
| WorkerFinished: | CloseWorker: | ||||||
|   close(server); |   close(server); | ||||||
|  | WorkerFinished: | ||||||
|   --workers; |   --workers; | ||||||
|   return 0; |   return 0; | ||||||
| } | } | ||||||
|  | @ -267,9 +271,9 @@ void PrintStatus(void) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int main(int argc, char *argv[]) { | int main(int argc, char *argv[]) { | ||||||
|  |   int i; | ||||||
|   char **tls; |   char **tls; | ||||||
|   char **stack; |   char **stack; | ||||||
|   int i, threads; |  | ||||||
|   uint32_t *hostips; |   uint32_t *hostips; | ||||||
|   // ShowCrashReports();
 |   // ShowCrashReports();
 | ||||||
| 
 | 
 | ||||||
|  | @ -295,7 +299,6 @@ int main(int argc, char *argv[]) { | ||||||
|   if ((1 <= threads && threads <= INT_MAX) && |   if ((1 <= threads && threads <= INT_MAX) && | ||||||
|       (tls = malloc(threads * sizeof(*tls))) && |       (tls = malloc(threads * sizeof(*tls))) && | ||||||
|       (stack = malloc(threads * sizeof(*stack)))) { |       (stack = malloc(threads * sizeof(*stack)))) { | ||||||
|     if (!threads) threads = GetCpuCount(); |  | ||||||
|     for (i = 0; i < threads; ++i) { |     for (i = 0; i < threads; ++i) { | ||||||
|       if ((tls[i] = __initialize_tls(malloc(64))) && |       if ((tls[i] = __initialize_tls(malloc(64))) && | ||||||
|           (stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, |           (stack[i] = mmap(0, GetStackSize(), PROT_READ | PROT_WRITE, | ||||||
|  |  | ||||||
|  | @ -21,7 +21,7 @@ | ||||||
| int main(int argc, char *argv[]) { | int main(int argc, char *argv[]) { | ||||||
|   if (_base[0] == 'M' && _base[1] == 'Z') { |   if (_base[0] == 'M' && _base[1] == 'Z') { | ||||||
|     printf("success: %s spawned without needing to modify its " |     printf("success: %s spawned without needing to modify its " | ||||||
|            "executable header, thanks to APE loader\n", |            "executable header", | ||||||
|            argv[0]); |            argv[0]); | ||||||
|     if (!IsWindows()) { |     if (!IsWindows()) { | ||||||
|       printf(", thanks to APE loader!\n"); |       printf(", thanks to APE loader!\n"); | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | /*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8     -*-│
 | ||||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | │vi: set et ft=asm ts=8 tw=8 fenc=utf-8                                     :vi│ | ||||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||||
| │ Copyright 2022 Justine Alexandra Roberts Tunney                              │ | │ Copyright 2022 Justine Alexandra Roberts Tunney                              │ | ||||||
| │                                                                              │ | │                                                                              │ | ||||||
|  | @ -16,36 +16,15 @@ | ||||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||||
| #include "libc/calls/calls.h" | #include "libc/macros.internal.h" | ||||||
| #include "libc/dce.h" |  | ||||||
| #include "libc/log/check.h" |  | ||||||
| #include "libc/runtime/runtime.h" |  | ||||||
| #include "libc/testlib/testlib.h" |  | ||||||
| 
 | 
 | ||||||
| void SetUp(void) { | 	.initbss 201,_init___clock_gettime | ||||||
|   if (getenv("_WEIRDENV")) { | __clock_gettime: | ||||||
|     for (char **e = environ; *e; ++e) {
 | 	.quad	0
 | ||||||
|       if (!strcmp(*e, "WEIRD")) { | 	.endobj	__clock_gettime,globl,hidden | ||||||
|         exit(0);
 | 	.previous | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     exit(7);
 |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| TEST(execve, testWeirdEnvironmentVariable) { | 	.init.start 201,_init___clock_gettime | ||||||
|   char *prog;
 | 	ezlea	__clock_gettime_init,ax | ||||||
|   int pid, ws;
 | 	stosq | ||||||
|   if (IsWindows()) return;
 | 	.init.end 201,_init___clock_gettime | ||||||
|   if (IsOpenbsd()) return;
 |  | ||||||
|   prog = GetProgramExecutableName();
 |  | ||||||
|   ASSERT_NE(-1, (pid = fork()));
 |  | ||||||
|   if (!pid) { |  | ||||||
|     execve(prog, (char *const[]){prog, 0}, |  | ||||||
|            (char *const[]){"_WEIRDENV=1", "WEIRD", 0});
 |  | ||||||
|     _Exit(127);
 |  | ||||||
|   } |  | ||||||
|   ASSERT_NE(-1, wait(&ws));
 |  | ||||||
|   EXPECT_TRUE(WIFEXITED(ws));
 |  | ||||||
|   EXPECT_EQ(0, WEXITSTATUS(ws));
 |  | ||||||
| } |  | ||||||
							
								
								
									
										19
									
								
								libc/calls/asan.internal.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								libc/calls/asan.internal.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,19 @@ | ||||||
|  | #ifndef COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_ | ||||||
|  | #define COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_ | ||||||
|  | #include "libc/bits/asmflag.h" | ||||||
|  | #include "libc/calls/struct/timespec.h" | ||||||
|  | #if !(__ASSEMBLER__ + __LINKER__ + 0) | ||||||
|  | COSMOPOLITAN_C_START_ | ||||||
|  | 
 | ||||||
|  | forceinline bool __asan_is_valid_timespec(const struct timespec *ts) { | ||||||
|  |   bool zf; | ||||||
|  |   asm(ZFLAG_ASM("cmpw\t$0,0x7fff8000(%1)") | ||||||
|  |       : ZFLAG_CONSTRAINT(zf) | ||||||
|  |       : "r"((intptr_t)ts >> 3) | ||||||
|  |       : "memory"); | ||||||
|  |   return zf; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | COSMOPOLITAN_C_END_ | ||||||
|  | #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ | ||||||
|  | #endif /* COSMOPOLITAN_LIBC_CALLS_ASAN_INTERNAL_H_ */ | ||||||
|  | @ -27,6 +27,7 @@ textwindows int sys_clock_gettime_nt(int clockid, struct timespec *ts) { | ||||||
|   struct timespec res; |   struct timespec res; | ||||||
|   struct NtFileTime ft; |   struct NtFileTime ft; | ||||||
|   static struct timespec mono; |   static struct timespec mono; | ||||||
|  |   if (!ts) return efault(); | ||||||
|   if (clockid == CLOCK_REALTIME) { |   if (clockid == CLOCK_REALTIME) { | ||||||
|     GetSystemTimeAsFileTime(&ft); |     GetSystemTimeAsFileTime(&ft); | ||||||
|     *ts = FileTimeToTimeSpec(ft); |     *ts = FileTimeToTimeSpec(ft); | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||||
| │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||||
| ╞══════════════════════════════════════════════════════════════════════════════╡ | ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||||
| │ Copyright 2021 Justine Alexandra Roberts Tunney                              │ | │ Copyright 2022 Justine Alexandra Roberts Tunney                              │ | ||||||
| │                                                                              │ | │                                                                              │ | ||||||
| │ Permission to use, copy, modify, and/or distribute this software for         │ | │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||||
| │ any purpose with or without fee is hereby granted, provided that the         │ | │ any purpose with or without fee is hereby granted, provided that the         │ | ||||||
|  | @ -16,24 +16,20 @@ | ||||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||||
| #include "libc/calls/struct/timespec.h" | #include "libc/calls/calls.h" | ||||||
| #include "libc/nexgen32e/rdtscp.h" | #include "libc/calls/internal.h" | ||||||
| #include "libc/sysv/consts/clock.h" |  | ||||||
| #include "libc/testlib/ezbench.h" |  | ||||||
| #include "libc/testlib/testlib.h" |  | ||||||
| #include "libc/time/time.h" |  | ||||||
| 
 | 
 | ||||||
| TEST(nowl, testIsMonotonic) { | int sys_clock_gettime_xnu(int clockid, struct timespec *ts) { | ||||||
|   long double a = nowl(); |   axdx_t ad; | ||||||
|   long double b = nowl(); |   ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL); | ||||||
|   EXPECT_TRUE(b > a); |   if (ad.ax != -1) { | ||||||
|  |     if (ad.ax) { | ||||||
|  |       ts->tv_sec = ad.ax; | ||||||
|  |       ts->tv_nsec = ad.dx; | ||||||
|  |     } | ||||||
|  |     ts->tv_nsec *= 1000; | ||||||
|  |     return 0; | ||||||
|  |   } else { | ||||||
|  |     return -1; | ||||||
|   } |   } | ||||||
| 
 |  | ||||||
| BENCH(nowl, bench) { |  | ||||||
|   volatile int64_t c; |  | ||||||
|   volatile long double x; |  | ||||||
|   volatile struct timespec ts; |  | ||||||
|   EZBENCH2("rdtsc", donothing, c = rdtsc()); |  | ||||||
|   EZBENCH2("nowl", donothing, x = nowl()); |  | ||||||
|   EZBENCH2("clock_gettime", donothing, clock_gettime(CLOCK_MONOTONIC, &ts)); |  | ||||||
| } | } | ||||||
|  | @ -17,6 +17,10 @@ | ||||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||||
| #include "libc/assert.h" | #include "libc/assert.h" | ||||||
|  | #include "libc/bits/asmflag.h" | ||||||
|  | #include "libc/bits/bits.h" | ||||||
|  | #include "libc/calls/asan.internal.h" | ||||||
|  | #include "libc/calls/clock_gettime.h" | ||||||
| #include "libc/calls/internal.h" | #include "libc/calls/internal.h" | ||||||
| #include "libc/calls/state.internal.h" | #include "libc/calls/state.internal.h" | ||||||
| #include "libc/calls/strace.internal.h" | #include "libc/calls/strace.internal.h" | ||||||
|  | @ -26,11 +30,10 @@ | ||||||
| #include "libc/fmt/conv.h" | #include "libc/fmt/conv.h" | ||||||
| #include "libc/intrin/asan.internal.h" | #include "libc/intrin/asan.internal.h" | ||||||
| #include "libc/intrin/describeflags.internal.h" | #include "libc/intrin/describeflags.internal.h" | ||||||
|  | #include "libc/mem/alloca.h" | ||||||
| #include "libc/nt/synchronization.h" | #include "libc/nt/synchronization.h" | ||||||
| #include "libc/sysv/errfuns.h" | #include "libc/sysv/errfuns.h" | ||||||
| 
 | 
 | ||||||
| static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime; |  | ||||||
| 
 |  | ||||||
| /**
 | /**
 | ||||||
|  * Returns nanosecond time. |  * Returns nanosecond time. | ||||||
|  * |  * | ||||||
|  | @ -38,6 +41,13 @@ static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime; | ||||||
|  * time. Among the more popular is CLOCK_MONOTONIC. This function has a |  * time. Among the more popular is CLOCK_MONOTONIC. This function has a | ||||||
|  * zero syscall implementation of that on modern x86. |  * zero syscall implementation of that on modern x86. | ||||||
|  * |  * | ||||||
|  |  *     nowl                l:        45𝑐        15𝑛𝑠 | ||||||
|  |  *     rdtsc               l:        13𝑐         4𝑛𝑠 | ||||||
|  |  *     gettimeofday        l:        44𝑐        14𝑛𝑠 | ||||||
|  |  *     clock_gettime       l:        40𝑐        13𝑛𝑠 | ||||||
|  |  *     __clock_gettime     l:        35𝑐        11𝑛𝑠 | ||||||
|  |  *     sys_clock_gettime   l:       220𝑐        71𝑛𝑠 | ||||||
|  |  * | ||||||
|  * @param clockid can be CLOCK_REALTIME, CLOCK_MONOTONIC, etc. |  * @param clockid can be CLOCK_REALTIME, CLOCK_MONOTONIC, etc. | ||||||
|  * @param ts is where the result is stored |  * @param ts is where the result is stored | ||||||
|  * @return 0 on success, or -1 w/ errno |  * @return 0 on success, or -1 w/ errno | ||||||
|  | @ -46,54 +56,49 @@ static typeof(sys_clock_gettime) *__clock_gettime = sys_clock_gettime; | ||||||
|  * @asyncsignalsafe |  * @asyncsignalsafe | ||||||
|  */ |  */ | ||||||
| noinstrument int clock_gettime(int clockid, struct timespec *ts) { | noinstrument int clock_gettime(int clockid, struct timespec *ts) { | ||||||
|   int rc, e; |   int rc; | ||||||
|   axdx_t ad; |   char *buf; | ||||||
|   char buf[45]; |   if (IsAsan() && !__asan_is_valid_timespec(ts)) { | ||||||
|   if (!ts) { |  | ||||||
|     rc = efault(); |     rc = efault(); | ||||||
|   } else if (IsAsan() && !__asan_is_valid(ts, sizeof(*ts))) { |  | ||||||
|     rc = efault(); |  | ||||||
|   } else if (clockid == -1) { |  | ||||||
|     rc = einval(); |  | ||||||
|   } else if (!IsWindows()) { |  | ||||||
|     e = errno; |  | ||||||
|     if ((rc = __clock_gettime(clockid, ts))) { |  | ||||||
|       errno = e; |  | ||||||
|       ad = sys_gettimeofday((struct timeval *)ts, NULL, NULL); |  | ||||||
|       assert(ad.ax != -1); |  | ||||||
|       if (SupportsXnu() && ad.ax) { |  | ||||||
|         ts->tv_sec = ad.ax; |  | ||||||
|         ts->tv_nsec = ad.dx; |  | ||||||
|       } |  | ||||||
|       ts->tv_nsec *= 1000; |  | ||||||
|       rc = 0; |  | ||||||
|     } |  | ||||||
|   } else { |   } else { | ||||||
|     rc = sys_clock_gettime_nt(clockid, ts); |     rc = __clock_gettime(clockid, ts); | ||||||
|   } |   } | ||||||
|  | #if SYSDEBUG | ||||||
|   if (!__time_critical) { |   if (!__time_critical) { | ||||||
|  |     buf = alloca(45); | ||||||
|     STRACE("clock_gettime(%d, [%s]) → %d% m", clockid, |     STRACE("clock_gettime(%d, [%s]) → %d% m", clockid, | ||||||
|            DescribeTimespec(buf, sizeof(buf), rc, ts), rc); |            DescribeTimespec(buf, 45, rc, ts), rc); | ||||||
|   } |   } | ||||||
|  | #endif | ||||||
|   return rc; |   return rc; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Returns fast system clock_gettime() if it exists. |  * Returns pointer to fastest clock_gettime(). | ||||||
|  */ |  */ | ||||||
| void *__get_clock_gettime(void) { | clock_gettime_f *__get_clock_gettime(bool *opt_out_isfast) { | ||||||
|   void *vdso; |   bool isfast; | ||||||
|   static bool once; |   clock_gettime_f *res; | ||||||
|   static void *result; |   if (IsLinux() && (res = __vdsosym("LINUX_2.6", "__vdso_clock_gettime"))) { | ||||||
|   if (!once) { |     isfast = true; | ||||||
|     if ((vdso = __vdsofunc("__vdso_clock_gettime"))) { |   } else if (IsXnu()) { | ||||||
|       __clock_gettime = result = vdso; |     isfast = false; | ||||||
|  |     res = sys_clock_gettime_xnu; | ||||||
|  |   } else if (IsWindows()) { | ||||||
|  |     isfast = true; | ||||||
|  |     res = sys_clock_gettime_nt; | ||||||
|  |   } else { | ||||||
|  |     isfast = false; | ||||||
|  |     res = sys_clock_gettime; | ||||||
|   } |   } | ||||||
|     once = true; |   if (opt_out_isfast) { | ||||||
|  |     *opt_out_isfast = isfast; | ||||||
|   } |   } | ||||||
|   return result; |   return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const void *const __clock_gettime_ctor[] initarray = { | hidden int __clock_gettime_init(int clockid, struct timespec *ts) { | ||||||
|     __get_clock_gettime, |   clock_gettime_f *gettime; | ||||||
| }; |   __clock_gettime = gettime = __get_clock_gettime(0); | ||||||
|  |   return gettime(clockid, ts); | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										15
									
								
								libc/calls/clock_gettime.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								libc/calls/clock_gettime.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | ||||||
|  | #ifndef COSMOPOLITAN_LIBC_CALLS_CLOCK_GETTIME_H_ | ||||||
|  | #define COSMOPOLITAN_LIBC_CALLS_CLOCK_GETTIME_H_ | ||||||
|  | #include "libc/calls/struct/timespec.h" | ||||||
|  | #if !(__ASSEMBLER__ + __LINKER__ + 0) | ||||||
|  | COSMOPOLITAN_C_START_ | ||||||
|  | 
 | ||||||
|  | typedef int clock_gettime_f(int, struct timespec *); | ||||||
|  | 
 | ||||||
|  | extern clock_gettime_f *__clock_gettime; | ||||||
|  | hidden clock_gettime_f __clock_gettime_init; | ||||||
|  | hidden clock_gettime_f *__get_clock_gettime(bool *); | ||||||
|  | 
 | ||||||
|  | COSMOPOLITAN_C_END_ | ||||||
|  | #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ | ||||||
|  | #endif /* COSMOPOLITAN_LIBC_CALLS_CLOCK_GETTIME_H_ */ | ||||||
|  | @ -59,7 +59,7 @@ int gettimeofday(struct timeval *tv, struct timezone *tz) { | ||||||
| 
 | 
 | ||||||
| static textstartup void __gettimeofday_init(void) { | static textstartup void __gettimeofday_init(void) { | ||||||
|   void *vdso; |   void *vdso; | ||||||
|   if ((vdso = __vdsofunc("__vdso_gettimeofday"))) { |   if ((vdso = __vdsosym("LINUX_2.6", "__vdso_gettimeofday"))) { | ||||||
|     __gettimeofday = vdso; |     __gettimeofday = vdso; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -118,6 +118,7 @@ i32 __sys_sigprocmask(i32, const sigset *, sigset *, u64) hidden; | ||||||
| i32 __sys_utimensat(i32, const char *, const struct timespec *, i32) hidden; | i32 __sys_utimensat(i32, const char *, const struct timespec *, i32) hidden; | ||||||
| i32 __sys_wait4(i32, i32 *, i32, struct rusage *) hidden; | i32 __sys_wait4(i32, i32 *, i32, struct rusage *) hidden; | ||||||
| i32 sys_clock_gettime(i32, struct timespec *) hidden; | i32 sys_clock_gettime(i32, struct timespec *) hidden; | ||||||
|  | i32 sys_clock_gettime_xnu(i32, struct timespec *) hidden; | ||||||
| i32 sys_fstat(i32, struct stat *) hidden; | i32 sys_fstat(i32, struct stat *) hidden; | ||||||
| i32 sys_fstatat(i32, const char *, struct stat *, i32) hidden; | i32 sys_fstatat(i32, const char *, struct stat *, i32) hidden; | ||||||
| i32 sys_futimes(i32, const struct timeval *) hidden; | i32 sys_futimes(i32, const struct timeval *) hidden; | ||||||
|  |  | ||||||
|  | @ -83,7 +83,7 @@ noasan textreal uint64_t *__get_virtual(struct mman *mm, uint64_t *t, | ||||||
| /**
 | /**
 | ||||||
|  * Sorts, rounds, and filters BIOS memory map. |  * Sorts, rounds, and filters BIOS memory map. | ||||||
|  */ |  */ | ||||||
| static noasan texthead void __normalize_e820(struct mman *mm) { | static noasan textreal void __normalize_e820(struct mman *mm) { | ||||||
|   uint64_t a, b; |   uint64_t a, b; | ||||||
|   uint64_t x, y; |   uint64_t x, y; | ||||||
|   unsigned i, j, n; |   unsigned i, j, n; | ||||||
|  | @ -113,7 +113,7 @@ static noasan texthead void __normalize_e820(struct mman *mm) { | ||||||
| /**
 | /**
 | ||||||
|  * Identity maps all usable physical memory to its negative address. |  * Identity maps all usable physical memory to its negative address. | ||||||
|  */ |  */ | ||||||
| static noasan texthead void __invert_memory(struct mman *mm, uint64_t *pml4t) { | static noasan textreal void __invert_memory(struct mman *mm, uint64_t *pml4t) { | ||||||
|   uint64_t i, j, *m, p, pe; |   uint64_t i, j, *m, p, pe; | ||||||
|   for (i = 0; i < mm->e820n; ++i) { |   for (i = 0; i < mm->e820n; ++i) { | ||||||
|     for (p = mm->e820[i].addr, pe = mm->e820[i].addr + mm->e820[i].size; |     for (p = mm->e820[i].addr, pe = mm->e820[i].addr + mm->e820[i].size; | ||||||
|  | @ -126,7 +126,7 @@ static noasan texthead void __invert_memory(struct mman *mm, uint64_t *pml4t) { | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| noasan texthead void __setup_mman(struct mman *mm, uint64_t *pml4t) { | noasan textreal void __setup_mman(struct mman *mm, uint64_t *pml4t) { | ||||||
|   __normalize_e820(mm); |   __normalize_e820(mm); | ||||||
|   __invert_memory(mm, pml4t); |   __invert_memory(mm, pml4t); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ | ||||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||||
|  | #include "libc/calls/asan.internal.h" | ||||||
| #include "libc/calls/calls.h" | #include "libc/calls/calls.h" | ||||||
| #include "libc/calls/internal.h" | #include "libc/calls/internal.h" | ||||||
| #include "libc/calls/state.internal.h" | #include "libc/calls/state.internal.h" | ||||||
|  | @ -31,7 +32,8 @@ | ||||||
| noinstrument int nanosleep(const struct timespec *req, struct timespec *rem) { | noinstrument int nanosleep(const struct timespec *req, struct timespec *rem) { | ||||||
|   int rc; |   int rc; | ||||||
|   char buf[2][45]; |   char buf[2][45]; | ||||||
|   if (!req) { |   if (!req || (IsAsan() && (!__asan_is_valid_timespec(req) || | ||||||
|  |                             (rem && !__asan_is_valid_timespec(rem))))) { | ||||||
|     rc = efault(); |     rc = efault(); | ||||||
|   } else if (req->tv_sec < 0 || |   } else if (req->tv_sec < 0 || | ||||||
|              !(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) { |              !(0 <= req->tv_nsec && req->tv_nsec <= 999999999)) { | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ | ||||||
| #include "libc/bits/initializer.internal.h" | #include "libc/bits/initializer.internal.h" | ||||||
| #include "libc/bits/safemacros.internal.h" | #include "libc/bits/safemacros.internal.h" | ||||||
| #include "libc/calls/calls.h" | #include "libc/calls/calls.h" | ||||||
|  | #include "libc/calls/clock_gettime.h" | ||||||
| #include "libc/calls/internal.h" | #include "libc/calls/internal.h" | ||||||
| #include "libc/calls/state.internal.h" | #include "libc/calls/state.internal.h" | ||||||
| #include "libc/calls/strace.internal.h" | #include "libc/calls/strace.internal.h" | ||||||
|  | @ -32,10 +33,11 @@ | ||||||
| #include "libc/sysv/consts/clock.h" | #include "libc/sysv/consts/clock.h" | ||||||
| #include "libc/time/time.h" | #include "libc/time/time.h" | ||||||
| 
 | 
 | ||||||
|  | static clock_gettime_f *__gettime; | ||||||
|  | 
 | ||||||
| static struct Now { | static struct Now { | ||||||
|   uint64_t k0; |   uint64_t k0; | ||||||
|   long double r0, cpn; |   long double r0, cpn; | ||||||
|   typeof(sys_clock_gettime) *clock_gettime; |  | ||||||
| } g_now; | } g_now; | ||||||
| 
 | 
 | ||||||
| static long double GetTimeSample(void) { | static long double GetTimeSample(void) { | ||||||
|  | @ -90,7 +92,7 @@ static long double nowl_art(void) { | ||||||
| static long double nowl_vdso(void) { | static long double nowl_vdso(void) { | ||||||
|   long double secs; |   long double secs; | ||||||
|   struct timespec tv; |   struct timespec tv; | ||||||
|   g_now.clock_gettime(CLOCK_REALTIME, &tv); |   __gettime(CLOCK_REALTIME, &tv); | ||||||
|   secs = tv.tv_nsec; |   secs = tv.tv_nsec; | ||||||
|   secs *= 1 / 1e9L; |   secs *= 1 / 1e9L; | ||||||
|   secs += tv.tv_sec; |   secs += tv.tv_sec; | ||||||
|  | @ -98,9 +100,10 @@ static long double nowl_vdso(void) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| long double nowl_setup(void) { | long double nowl_setup(void) { | ||||||
|  |   bool isfast; | ||||||
|   uint64_t ticks; |   uint64_t ticks; | ||||||
|   if (0 && (g_now.clock_gettime = __get_clock_gettime())) { |   __gettime = __get_clock_gettime(&isfast); | ||||||
|     // TODO(jart): Re-enable this.
 |   if (isfast) { | ||||||
|     nowl = nowl_vdso; |     nowl = nowl_vdso; | ||||||
|   } else if (X86_HAVE(INVTSC)) { |   } else if (X86_HAVE(INVTSC)) { | ||||||
|     RefreshTime(); |     RefreshTime(); | ||||||
|  |  | ||||||
|  | @ -17,33 +17,44 @@ | ||||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||||
| #include "libc/calls/calls.h" | #include "libc/calls/calls.h" | ||||||
|  | #include "libc/calls/ioctl.h" | ||||||
| #include "libc/calls/termios.h" | #include "libc/calls/termios.h" | ||||||
|  | #include "libc/fmt/itoa.h" | ||||||
| #include "libc/sysv/consts/o.h" | #include "libc/sysv/consts/o.h" | ||||||
| #include "libc/sysv/consts/pty.h" | #include "libc/sysv/consts/pty.h" | ||||||
|  | #include "libc/sysv/consts/termios.h" | ||||||
| #include "libc/sysv/errfuns.h" | #include "libc/sysv/errfuns.h" | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Opens new pseudo teletypewriter. |  * Opens new pseudo teletypewriter. | ||||||
|  * |  * | ||||||
|  * @param ilduce receives controlling tty rw fd on success |  * @param mfd receives controlling tty rw fd on success | ||||||
|  * @param aworker receives subordinate tty rw fd on success |  * @param sfd receives subordinate tty rw fd on success | ||||||
|  * @param termp may be passed to tune a century of legacy behaviors |  * @param tio may be passed to tune a century of legacy behaviors | ||||||
|  * @param winp may be passed to set terminal display dimensions |  * @param wsz may be passed to set terminal display dimensions | ||||||
|  * @params flags is usually O_RDWR|O_NOCTTY |  * @params flags is usually O_RDWR|O_NOCTTY | ||||||
|  * @return file descriptor, or -1 w/ errno |  * @return 0 on success, or -1 w/ errno | ||||||
|  */ |  */ | ||||||
| int openpty(int *ilduce, int *aworker, char *name, const struct termios *termp, | int openpty(int *mfd, int *sfd, char *name, const struct termios *tio, | ||||||
|             const struct winsize *winp) { |             const struct winsize *wsz) { | ||||||
|   return enosys(); |   int m, s, n; | ||||||
|   /* TODO(jart) */ |   char buf[20]; | ||||||
|   /* int fd, flags; */ |   if ((m = open("/dev/ptmx", O_RDWR | O_NOCTTY)) != -1) { | ||||||
|   /* flags = O_RDWR | O_NOCTTY; */ |     n = 0; | ||||||
|   /* if ((fd = posix_openpt(flags)) != -1) { */ |     if (!ioctl(m, TIOCSPTLCK, &n) || !ioctl(m, TIOCGPTN, &n)) { | ||||||
|   /*   if (ioctl(m, TIOCSPTLCK, &n) || ioctl(m, TIOCGPTN, &n)) { */ |       if (!name) name = buf; | ||||||
|   /*   } else { */ |       name[0] = '/', name[1] = 'd', name[2] = 'e', name[3] = 'v'; | ||||||
|   /*     close(fd); */ |       name[4] = '/', name[5] = 'p', name[6] = 't', name[7] = 's'; | ||||||
|   /*   } */ |       name[8] = '/', FormatInt32(name + 9, n); | ||||||
|   /* } else { */ |       if ((s = open(name, O_RDWR | O_NOCTTY)) != -1) { | ||||||
|   /*   return -1; */ |         if (tio) ioctl(s, TCSETS, tio); | ||||||
|   /* } */ |         if (wsz) ioctl(s, TIOCSWINSZ, wsz); | ||||||
|  |         *mfd = m; | ||||||
|  |         *sfd = s; | ||||||
|  |         return 0; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     close(m); | ||||||
|  |   } | ||||||
|  |   return -1; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -12,8 +12,7 @@ int __notziposat(int, const char *); | ||||||
| int gethostname_bsd(char *, size_t) hidden; | int gethostname_bsd(char *, size_t) hidden; | ||||||
| int gethostname_linux(char *, size_t) hidden; | int gethostname_linux(char *, size_t) hidden; | ||||||
| int gethostname_nt(char *, size_t, int) hidden; | int gethostname_nt(char *, size_t, int) hidden; | ||||||
| void *__get_clock_gettime(void) hidden; | void *__vdsosym(const char *, const char *) hidden; | ||||||
| void *__vdsofunc(const char *) hidden; |  | ||||||
| void __onfork(void) hidden; | void __onfork(void) hidden; | ||||||
| void __restore_rt() hidden; | void __restore_rt() hidden; | ||||||
| void __restore_rt_netbsd(void) hidden; | void __restore_rt_netbsd(void) hidden; | ||||||
|  |  | ||||||
|  | @ -17,6 +17,7 @@ | ||||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||||
| #include "libc/bits/weaken.h" | #include "libc/bits/weaken.h" | ||||||
|  | #include "libc/calls/asan.internal.h" | ||||||
| #include "libc/calls/calls.h" | #include "libc/calls/calls.h" | ||||||
| #include "libc/calls/internal.h" | #include "libc/calls/internal.h" | ||||||
| #include "libc/calls/strace.internal.h" | #include "libc/calls/strace.internal.h" | ||||||
|  | @ -39,7 +40,8 @@ int utimensat(int dirfd, const char *path, const struct timespec ts[2], | ||||||
|   int rc; |   int rc; | ||||||
|   char buf[12]; |   char buf[12]; | ||||||
|   if (IsAsan() && (!__asan_is_valid(path, 1) || |   if (IsAsan() && (!__asan_is_valid(path, 1) || | ||||||
|                    (ts && !__asan_is_valid(ts, sizeof(struct timespec) * 2)))) { |                    (ts && (!__asan_is_valid_timespec(ts + 0) || | ||||||
|  |                            !__asan_is_valid_timespec(ts + 1))))) { | ||||||
|     rc = efault(); |     rc = efault(); | ||||||
|   } else if (weaken(__zipos_notat) && (rc = __zipos_notat(dirfd, path)) == -1) { |   } else if (weaken(__zipos_notat) && (rc = __zipos_notat(dirfd, path)) == -1) { | ||||||
|     STRACE("zipos mkdirat not supported yet"); |     STRACE("zipos mkdirat not supported yet"); | ||||||
|  |  | ||||||
|  | @ -18,76 +18,136 @@ | ||||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||||
| #include "libc/bits/bits.h" | #include "libc/bits/bits.h" | ||||||
| #include "libc/calls/calls.h" | #include "libc/calls/calls.h" | ||||||
|  | #include "libc/calls/strace.internal.h" | ||||||
| #include "libc/elf/scalar.h" | #include "libc/elf/scalar.h" | ||||||
| #include "libc/elf/struct/ehdr.h" | #include "libc/elf/struct/ehdr.h" | ||||||
|  | #include "libc/elf/struct/phdr.h" | ||||||
| #include "libc/elf/struct/shdr.h" | #include "libc/elf/struct/shdr.h" | ||||||
| #include "libc/elf/struct/sym.h" | #include "libc/elf/struct/sym.h" | ||||||
| #include "libc/log/libfatal.internal.h" | #include "libc/elf/struct/verdaux.h" | ||||||
|  | #include "libc/elf/struct/verdef.h" | ||||||
|  | #include "libc/intrin/kprintf.h" | ||||||
| #include "libc/runtime/runtime.h" | #include "libc/runtime/runtime.h" | ||||||
| #include "libc/sysv/consts/auxv.h" | #include "libc/sysv/consts/auxv.h" | ||||||
| 
 | 
 | ||||||
| #define LAZY_RHEL7_RELOCATION 0xfffff | static inline int CompareStrings(const char *l, const char *r) { | ||||||
|  |   size_t i = 0; | ||||||
|  |   while (l[i] == r[i] && r[i]) ++i; | ||||||
|  |   return (l[i] & 255) - (r[i] & 255); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| #define GetStr(tab, rva)     ((char *)(tab) + (rva)) | static inline int CheckDsoSymbolVersion(Elf64_Verdef *vd, int sym, | ||||||
| #define GetSection(e, s)     ((void *)((intptr_t)(e) + (size_t)(s)->sh_offset)) |                                         const char *name, char *strtab) { | ||||||
| #define GetShstrtab(e)       GetSection(e, GetShdr(e, (e)->e_shstrndx)) |   Elf64_Verdaux *aux; | ||||||
| #define GetSectionName(e, s) GetStr(GetShstrtab(e), (s)->sh_name) |   for (;; vd = (Elf64_Verdef *)((char *)vd + vd->vd_next)) { | ||||||
| #define GetPhdr(e, i)                            \ |     if (!(vd->vd_flags & VER_FLG_BASE) && | ||||||
|   ((Elf64_Phdr *)((intptr_t)(e) + (e)->e_phoff + \ |         (vd->vd_ndx & 0x7fff) == (sym & 0x7fff)) { | ||||||
|                   (size_t)(e)->e_phentsize * (i))) |       aux = (Elf64_Verdaux *)((char *)vd + vd->vd_aux); | ||||||
| #define GetShdr(e, i)                            \ |       return !CompareStrings(name, strtab + aux->vda_name); | ||||||
|   ((Elf64_Shdr *)((intptr_t)(e) + (e)->e_shoff + \ |  | ||||||
|                   (size_t)(e)->e_shentsize * (i))) |  | ||||||
| 
 |  | ||||||
| static char *GetDynamicStringTable(Elf64_Ehdr *e, size_t *n) { |  | ||||||
|   char *name; |  | ||||||
|   Elf64_Half i; |  | ||||||
|   Elf64_Shdr *shdr; |  | ||||||
|   for (i = 0; i < e->e_shnum; ++i) { |  | ||||||
|     shdr = GetShdr(e, i); |  | ||||||
|     name = GetSectionName(e, GetShdr(e, i)); |  | ||||||
|     if (shdr->sh_type == SHT_STRTAB) { |  | ||||||
|       name = GetSectionName(e, GetShdr(e, i)); |  | ||||||
|       if (name && READ64LE(name) == READ64LE(".dynstr")) { |  | ||||||
|         if (n) *n = shdr->sh_size; |  | ||||||
|         return GetSection(e, shdr); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     } |     } | ||||||
|  |     if (!vd->vd_next) { | ||||||
|       return 0; |       return 0; | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| static Elf64_Sym *GetDynamicSymbolTable(Elf64_Ehdr *e, Elf64_Xword *n) { |  | ||||||
|   Elf64_Half i; |  | ||||||
|   Elf64_Shdr *shdr; |  | ||||||
|   for (i = e->e_shnum; i > 0; --i) { |  | ||||||
|     shdr = GetShdr(e, i - 1); |  | ||||||
|     if (shdr->sh_type == SHT_DYNSYM) { |  | ||||||
|       if (shdr->sh_entsize != sizeof(Elf64_Sym)) continue; |  | ||||||
|       if (n) *n = shdr->sh_size / shdr->sh_entsize; |  | ||||||
|       return GetSection(e, shdr); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Returns Linux Kernel Virtual Dynamic Shared Object function address. |  * Returns address of vDSO function. | ||||||
|  */ |  */ | ||||||
| void *__vdsofunc(const char *name) { | void *__vdsosym(const char *version, const char *name) { | ||||||
|   size_t m; |   void *p; | ||||||
|   char *names; |   size_t i; | ||||||
|   Elf64_Ehdr *ehdr; |   Elf64_Ehdr *ehdr; | ||||||
|   Elf64_Xword i, n; |   Elf64_Phdr *phdr; | ||||||
|   Elf64_Sym *symtab, *sym; |   char *strtab = 0; | ||||||
|   if ((ehdr = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR)) && |   size_t *dyn, base; | ||||||
|       (names = GetDynamicStringTable(ehdr, &m)) && |   unsigned long *ap; | ||||||
|       (symtab = GetDynamicSymbolTable(ehdr, &n))) { |   Elf64_Sym *symtab = 0; | ||||||
|     for (i = 0; i < n; ++i) { |   uint16_t *versym = 0; | ||||||
|       if (!__strcmp(names + symtab[i].st_name, name)) { |   Elf_Symndx *hashtab = 0; | ||||||
|         return (char *)ehdr + (symtab[i].st_value & LAZY_RHEL7_RELOCATION); |   Elf64_Verdef *verdef = 0; | ||||||
|       } | 
 | ||||||
|  |   for (ehdr = 0, ap = __auxv; ap[0]; ap += 2) { | ||||||
|  |     if (ap[0] == AT_SYSINFO_EHDR) { | ||||||
|  |       ehdr = (void *)ap[1]; | ||||||
|  |       break; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |   if (!ehdr || READ32LE(ehdr->e_ident) != READ32LE("\177ELF")) { | ||||||
|  |     KERNTRACE("__vdsosym() → AT_SYSINFO_EHDR ELF not found"); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   phdr = (void *)((char *)ehdr + ehdr->e_phoff); | ||||||
|  |   for (base = -1, dyn = 0, i = 0; i < ehdr->e_phnum; | ||||||
|  |        i++, phdr = (void *)((char *)phdr + ehdr->e_phentsize)) { | ||||||
|  |     switch (phdr->p_type) { | ||||||
|  |       case PT_LOAD: | ||||||
|  |         // modern linux uses the base address zero, but elders
 | ||||||
|  |         // e.g. rhel7 uses the base address 0xffffffffff700000
 | ||||||
|  |         base = (size_t)ehdr + phdr->p_offset - phdr->p_vaddr; | ||||||
|  |         break; | ||||||
|  |       case PT_DYNAMIC: | ||||||
|  |         dyn = (void *)((char *)ehdr + phdr->p_offset); | ||||||
|  |         break; | ||||||
|  |       default: | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (!dyn || base == -1) { | ||||||
|  |     KERNTRACE("__vdsosym() → missing program headers"); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   for (i = 0; dyn[i]; i += 2) { | ||||||
|  |     p = (void *)(base + dyn[i + 1]); | ||||||
|  |     switch (dyn[i]) { | ||||||
|  |       case DT_STRTAB: | ||||||
|  |         strtab = p; | ||||||
|  |         break; | ||||||
|  |       case DT_SYMTAB: | ||||||
|  |         symtab = p; | ||||||
|  |         break; | ||||||
|  |       case DT_HASH: | ||||||
|  |         hashtab = p; | ||||||
|  |         break; | ||||||
|  |       case DT_VERSYM: | ||||||
|  |         versym = p; | ||||||
|  |         break; | ||||||
|  |       case DT_VERDEF: | ||||||
|  |         verdef = p; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (!strtab || !symtab || !hashtab) { | ||||||
|  |     KERNTRACE("__vdsosym() → tables not found"); | ||||||
|  |     return 0; | ||||||
|  |   } | ||||||
|  |   if (!verdef) { | ||||||
|  |     versym = 0; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   for (i = 0; i < hashtab[1]; i++) { | ||||||
|  |     if (ELF64_ST_TYPE(symtab[i].st_info) != STT_FUNC && | ||||||
|  |         ELF64_ST_TYPE(symtab[i].st_info) != STT_OBJECT && | ||||||
|  |         ELF64_ST_TYPE(symtab[i].st_info) != STT_NOTYPE) { | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |     if (ELF64_ST_BIND(symtab[i].st_info) != STB_GLOBAL) { | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |     if (!symtab[i].st_shndx) { | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |     if (CompareStrings(name, strtab + symtab[i].st_name)) { | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |     if (versym && !CheckDsoSymbolVersion(verdef, versym[i], version, strtab)) { | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |     return (void *)(base + symtab[i].st_value); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   KERNTRACE("__vdsosym() → symbol not found"); | ||||||
|   return 0; |   return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -17,12 +17,16 @@ | ||||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||||
| #include "libc/elf/elf.h" | #include "libc/elf/elf.h" | ||||||
|  | #include "libc/intrin/kprintf.h" | ||||||
| #include "libc/runtime/runtime.h" | #include "libc/runtime/runtime.h" | ||||||
| 
 | 
 | ||||||
| void CheckElfAddress(const Elf64_Ehdr *elf, size_t mapsize, intptr_t addr, | void CheckElfAddress(const Elf64_Ehdr *elf, size_t mapsize, intptr_t addr, | ||||||
|                      size_t addrsize) { |                      size_t addrsize) { | ||||||
| #if !(TRUSTWORTHY + ELF_TRUSTWORTHY + 0) || ELF_UNTRUSTWORTHY + 0 | #if !(TRUSTWORTHY + ELF_TRUSTWORTHY + 0) || ELF_UNTRUSTWORTHY + 0 | ||||||
|   if (addr < (intptr_t)elf || addr + addrsize > (intptr_t)elf + mapsize) { |   if (addr < (intptr_t)elf || addr + addrsize > (intptr_t)elf + mapsize) { | ||||||
|  |     /* kprintf("%p-%p falls outside interval %p-%p",  // */ | ||||||
|  |     /*         addr, addr + addrsize,                 // */ | ||||||
|  |     /*         elf, (char *)elf + mapsize);           // */ | ||||||
|     abort(); |     abort(); | ||||||
|   } |   } | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | @ -2,15 +2,16 @@ | ||||||
| #define COSMOPOLITAN_LIBC_ELF_SCALAR_H_ | #define COSMOPOLITAN_LIBC_ELF_SCALAR_H_ | ||||||
| #if !(__ASSEMBLER__ + __LINKER__ + 0) | #if !(__ASSEMBLER__ + __LINKER__ + 0) | ||||||
| 
 | 
 | ||||||
| #define Elf64_Half uint16_t |  | ||||||
| #define Elf64_Word uint32_t |  | ||||||
| #define Elf64_Sword int32_t |  | ||||||
| #define Elf64_Xword uint64_t |  | ||||||
| #define Elf64_Sxword int64_t |  | ||||||
| #define Elf64_Addr    uint64_t | #define Elf64_Addr    uint64_t | ||||||
|  | #define Elf64_Half    uint16_t | ||||||
| #define Elf64_Off     uint64_t | #define Elf64_Off     uint64_t | ||||||
| #define Elf64_Section uint16_t | #define Elf64_Section uint16_t | ||||||
|  | #define Elf64_Sword   int32_t | ||||||
|  | #define Elf64_Sxword  int64_t | ||||||
| #define Elf64_Versym  Elf64_Half | #define Elf64_Versym  Elf64_Half | ||||||
|  | #define Elf64_Word    uint32_t | ||||||
|  | #define Elf64_Xword   uint64_t | ||||||
|  | #define Elf_Symndx    uint32_t | ||||||
| 
 | 
 | ||||||
| #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ | #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ | ||||||
| #endif /* COSMOPOLITAN_LIBC_ELF_SCALAR_H_ */ | #endif /* COSMOPOLITAN_LIBC_ELF_SCALAR_H_ */ | ||||||
|  |  | ||||||
|  | @ -1323,7 +1323,6 @@ syscon	termios	TIOCSETD				0x5423			0x8004741b		0x8004741b		0x8004741b		0x800474 | ||||||
| syscon	termios	TIOCSIG					0x40045436		0x2000745f		0x2004745f		0x8004745f		0x8004745f		0			# boop | syscon	termios	TIOCSIG					0x40045436		0x2000745f		0x2004745f		0x8004745f		0x8004745f		0			# boop | ||||||
| syscon	termios	TIOCSPGRP				0x5410			0x80047476		0x80047476		0x80047476		0x80047476		0			# boop | syscon	termios	TIOCSPGRP				0x5410			0x80047476		0x80047476		0x80047476		0x80047476		0			# boop | ||||||
| syscon	termios	TIOCSTI					0x5412			0x80017472		0x80017472		0			0			0			# boop | syscon	termios	TIOCSTI					0x5412			0x80017472		0x80017472		0			0			0			# boop | ||||||
| syscon	termios	TIOCGPTN				0x80045430		0			0x4004740f		0			0			0			# boop |  | ||||||
| syscon	termios	TIOCGSID				0x5429			0x40047463		0x40047463		0x40047463		0x40047463		0			# boop | syscon	termios	TIOCGSID				0x5429			0x40047463		0x40047463		0x40047463		0x40047463		0			# boop | ||||||
| syscon	termios	TABLDISC				0			0x3			0			0x3			0x3			0			# boop | syscon	termios	TABLDISC				0			0x3			0			0x3			0x3			0			# boop | ||||||
| syscon	termios	SLIPDISC				0			0x4			0x4			0x4			0x4			0			# boop | syscon	termios	SLIPDISC				0			0x4			0x4			0x4			0x4			0			# boop | ||||||
|  | @ -1508,6 +1507,8 @@ syscon	termios	CSTOP					19			19			19			19			19			0			# unix consensus | ||||||
| #	Pseudoteletypewriter Control | #	Pseudoteletypewriter Control | ||||||
| # | # | ||||||
| #	group	name					GNU/Systemd		XNU's Not UNIX!		FreeBSD			OpenBSD			NetBSD			The New Technology	Commentary | #	group	name					GNU/Systemd		XNU's Not UNIX!		FreeBSD			OpenBSD			NetBSD			The New Technology	Commentary | ||||||
|  | syscon	pty	TIOCGPTN				0x80045430		0			0x4004740f		0			0			0			# boop | ||||||
|  | syscon	pty	TIOCSPTLCK				0x40045431		0			0			0			0			0			# boop | ||||||
| syscon	pty	TIOCPKT					0x5420			0x80047470		0x80047470		0x80047470		0x80047470		-1			# boop | syscon	pty	TIOCPKT					0x5420			0x80047470		0x80047470		0x80047470		0x80047470		-1			# boop | ||||||
| syscon	pty	TIOCPKT_DATA				0			0			0			0			0			0			# consensus | syscon	pty	TIOCPKT_DATA				0			0			0			0			0			0			# consensus | ||||||
| syscon	pty	TIOCPKT_FLUSHREAD			1			1			1			1			1			1			# unix consensus | syscon	pty	TIOCPKT_FLUSHREAD			1			1			1			1			1			1			# unix consensus | ||||||
|  | @ -1517,7 +1518,6 @@ syscon	pty	TIOCPKT_START				8			8			8			8			8			8			# unix consensus | ||||||
| syscon	pty	TIOCPKT_NOSTOP				16			16			16			16			16			16			# unix consensus | syscon	pty	TIOCPKT_NOSTOP				16			16			16			16			16			16			# unix consensus | ||||||
| syscon	pty	TIOCPKT_DOSTOP				32			32			32			32			32			32			# unix consensus | syscon	pty	TIOCPKT_DOSTOP				32			32			32			32			32			32			# unix consensus | ||||||
| syscon	pty	TIOCPKT_IOCTL				64			64			64			64			64			64			# unix consensus | syscon	pty	TIOCPKT_IOCTL				64			64			64			64			64			64			# unix consensus | ||||||
| syscon	pty	TIOCSPTLCK				0x40045431		0			0			0			0			-1			# boop |  | ||||||
| syscon	pty	PTMGET					0			0			0			0x40287401		0x40287401		-1			# for /dev/ptm | syscon	pty	PTMGET					0			0			0			0x40287401		0x40287401		-1			# for /dev/ptm | ||||||
| 
 | 
 | ||||||
| #	Modem Control | #	Modem Control | ||||||
|  |  | ||||||
|  | @ -157,7 +157,10 @@ intptr_t ehwpoison(void) relegated; | ||||||
| #define __ERRFUN(FUNC)               \ | #define __ERRFUN(FUNC)               \ | ||||||
|   ({                                 \ |   ({                                 \ | ||||||
|     intptr_t NegOne;                 \ |     intptr_t NegOne;                 \ | ||||||
|     asm("call\t" FUNC : "=a"(NegOne), "=m"(errno)); \ |     asm volatile("call\t" FUNC       \ | ||||||
|  |                  : "=a"(NegOne)      \ | ||||||
|  |                  : /* no outputs */  \ | ||||||
|  |                  : "rcx", "memory"); \ | ||||||
|     NegOne;                          \ |     NegOne;                          \ | ||||||
|   }) |   }) | ||||||
| #define einval()          __ERRFUN("einval") | #define einval()          __ERRFUN("einval") | ||||||
|  |  | ||||||
|  | @ -16,14 +16,40 @@ | ||||||
| │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||||
| │ PERFORMANCE OF THIS SOFTWARE.                                                │ | │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||||
| #include "libc/calls/calls.h" | #include "libc/calls/clock_gettime.h" | ||||||
|  | #include "libc/calls/internal.h" | ||||||
| #include "libc/calls/struct/timespec.h" | #include "libc/calls/struct/timespec.h" | ||||||
| #include "libc/sysv/consts/clock.h" | #include "libc/calls/struct/timeval.h" | ||||||
|  | #include "libc/calls/syscall_support-sysv.internal.h" | ||||||
|  | #include "libc/nexgen32e/rdtsc.h" | ||||||
|  | #include "libc/runtime/runtime.h" | ||||||
|  | #include "libc/sysv/consts/auxv.h" | ||||||
| #include "libc/testlib/ezbench.h" | #include "libc/testlib/ezbench.h" | ||||||
| #include "libc/testlib/testlib.h" | #include "libc/testlib/testlib.h" | ||||||
|  | #include "libc/time/time.h" | ||||||
|  | 
 | ||||||
|  | TEST(clock_gettime, test) { | ||||||
|  |   bool isfast; | ||||||
|  |   struct timespec ts = {0}; | ||||||
|  |   ASSERT_EQ(0, clock_gettime(0, &ts)); | ||||||
|  |   ASSERT_NE(0, ts.tv_sec); | ||||||
|  |   ASSERT_NE(0, ts.tv_nsec); | ||||||
|  |   if (__is_linux_2_6_23()) { | ||||||
|  |     ASSERT_GT((intptr_t)__get_clock_gettime(&isfast), | ||||||
|  |               getauxval(AT_SYSINFO_EHDR)); | ||||||
|  |     ASSERT_TRUE(isfast); | ||||||
|  |   } | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| BENCH(clock_gettime, bench) { | BENCH(clock_gettime, bench) { | ||||||
|  |   struct timeval tv; | ||||||
|   struct timespec ts; |   struct timespec ts; | ||||||
|  |   gettimeofday(&tv, 0);   // trigger init
 | ||||||
|  |   clock_gettime(0, &ts);  // trigger init
 | ||||||
|   EZBENCH2("nowl", donothing, nowl()); |   EZBENCH2("nowl", donothing, nowl()); | ||||||
|   EZBENCH2("clock_gettime", donothing, clock_gettime(CLOCK_REALTIME, &ts)); |   EZBENCH2("rdtsc", donothing, rdtsc()); | ||||||
|  |   EZBENCH2("gettimeofday", donothing, gettimeofday(&tv, 0)); | ||||||
|  |   EZBENCH2("clock_gettime", donothing, clock_gettime(0, &ts)); | ||||||
|  |   EZBENCH2("__clock_gettime", donothing, __clock_gettime(0, &ts)); | ||||||
|  |   EZBENCH2("sys_clock_gettime", donothing, sys_clock_gettime(0, &ts)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ | ||||||
| #include "libc/calls/sigbits.h" | #include "libc/calls/sigbits.h" | ||||||
| #include "libc/calls/struct/sigaction.h" | #include "libc/calls/struct/sigaction.h" | ||||||
| #include "libc/errno.h" | #include "libc/errno.h" | ||||||
|  | #include "libc/intrin/kprintf.h" | ||||||
| #include "libc/mem/io.h" | #include "libc/mem/io.h" | ||||||
| #include "libc/runtime/runtime.h" | #include "libc/runtime/runtime.h" | ||||||
| #include "libc/sysv/consts/o.h" | #include "libc/sysv/consts/o.h" | ||||||
|  |  | ||||||
							
								
								
									
										4
									
								
								third_party/bzip2/bzip2.mk
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								third_party/bzip2/bzip2.mk
									
										
									
									
										vendored
									
									
								
							|  | @ -51,7 +51,7 @@ o/$(MODE)/third_party/bzip2/bzip2.com.dbg:			\ | ||||||
| 		o/$(MODE)/third_party/bzip2/bzip2.o		\
 | 		o/$(MODE)/third_party/bzip2/bzip2.o		\
 | ||||||
| 		o/$(MODE)/third_party/bzip2/bzip2.a.pkg		\
 | 		o/$(MODE)/third_party/bzip2/bzip2.a.pkg		\
 | ||||||
| 		$(CRT)						\
 | 		$(CRT)						\
 | ||||||
| 		$(APE) | 		$(APE_NO_MODIFY_SELF) | ||||||
| 	@$(APELINK) | 	@$(APELINK) | ||||||
| 
 | 
 | ||||||
| o/$(MODE)/third_party/bzip2/bzip2recover.com.dbg:		\ | o/$(MODE)/third_party/bzip2/bzip2recover.com.dbg:		\ | ||||||
|  | @ -59,7 +59,7 @@ o/$(MODE)/third_party/bzip2/bzip2recover.com.dbg:		\ | ||||||
| 		o/$(MODE)/third_party/bzip2/bzip2recover.o	\
 | 		o/$(MODE)/third_party/bzip2/bzip2recover.o	\
 | ||||||
| 		o/$(MODE)/third_party/bzip2/bzip2.a.pkg		\
 | 		o/$(MODE)/third_party/bzip2/bzip2.a.pkg		\
 | ||||||
| 		$(CRT)						\
 | 		$(CRT)						\
 | ||||||
| 		$(APE) | 		$(APE_NO_MODIFY_SELF) | ||||||
| 	@$(APELINK) | 	@$(APELINK) | ||||||
| 
 | 
 | ||||||
| $(THIRD_PARTY_BZIP2_A_OBJS):					\ | $(THIRD_PARTY_BZIP2_A_OBJS):					\ | ||||||
|  |  | ||||||
							
								
								
									
										4
									
								
								third_party/lua/lua.mk
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								third_party/lua/lua.mk
									
										
									
									
										vendored
									
									
								
							|  | @ -59,7 +59,7 @@ o/$(MODE)/third_party/lua/lua.com.dbg:						\ | ||||||
| 		$(THIRD_PARTY_LUA_A).pkg					\
 | 		$(THIRD_PARTY_LUA_A).pkg					\
 | ||||||
| 		o/$(MODE)/third_party/lua/lua.main.o				\
 | 		o/$(MODE)/third_party/lua/lua.main.o				\
 | ||||||
| 		$(CRT)								\
 | 		$(CRT)								\
 | ||||||
| 		$(APE) | 		$(APE_NO_MODIFY_SELF) | ||||||
| 	@$(APELINK) | 	@$(APELINK) | ||||||
| 
 | 
 | ||||||
| o/$(MODE)/third_party/lua/luac.com.dbg:						\ | o/$(MODE)/third_party/lua/luac.com.dbg:						\ | ||||||
|  | @ -68,7 +68,7 @@ o/$(MODE)/third_party/lua/luac.com.dbg:						\ | ||||||
| 		$(THIRD_PARTY_LUA_A).pkg					\
 | 		$(THIRD_PARTY_LUA_A).pkg					\
 | ||||||
| 		o/$(MODE)/third_party/lua/luac.main.o				\
 | 		o/$(MODE)/third_party/lua/luac.main.o				\
 | ||||||
| 		$(CRT)								\
 | 		$(CRT)								\
 | ||||||
| 		$(APE) | 		$(APE_NO_MODIFY_SELF) | ||||||
| 	@$(APELINK) | 	@$(APELINK) | ||||||
| 
 | 
 | ||||||
| o/$(MODE)/third_party/lua/lua.com:						\ | o/$(MODE)/third_party/lua/lua.com:						\ | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								third_party/lz4cli/lz4cli.mk
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								third_party/lz4cli/lz4cli.mk
									
										
									
									
										vendored
									
									
								
							|  | @ -56,7 +56,7 @@ o/$(MODE)/third_party/lz4cli/lz4cli.com.dbg:		\ | ||||||
| 		$(THIRD_PARTY_LZ4CLI_DEPS)		\
 | 		$(THIRD_PARTY_LZ4CLI_DEPS)		\
 | ||||||
| 		$(THIRD_PARTY_LZ4CLI_OBJS)		\
 | 		$(THIRD_PARTY_LZ4CLI_OBJS)		\
 | ||||||
| 		$(CRT)					\
 | 		$(CRT)					\
 | ||||||
| 		$(APE) | 		$(APE_NO_MODIFY_SELF) | ||||||
| 	@$(APELINK) | 	@$(APELINK) | ||||||
| 
 | 
 | ||||||
| $(THIRD_PARTY_LZ4CLI_OBJS):				\ | $(THIRD_PARTY_LZ4CLI_OBJS):				\ | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								third_party/mbedtls/ecp.c
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								third_party/mbedtls/ecp.c
									
										
									
									
										vendored
									
									
								
							|  | @ -512,6 +512,7 @@ int mbedtls_ecp_check_budget( const mbedtls_ecp_group *grp, | ||||||
|  *     SECP384R1  192       IANA, NIST, FRANCE, GERMANY, NSA |  *     SECP384R1  192       IANA, NIST, FRANCE, GERMANY, NSA | ||||||
|  *     X25519     112-128   IANA |  *     X25519     112-128   IANA | ||||||
|  *     X448       224       IANA |  *     X448       224       IANA | ||||||
|  |  *     SECP256K1  128       BITCOIN | ||||||
|  *     BP384R1              GERMANY |  *     BP384R1              GERMANY | ||||||
|  *     SECP521R1            FRANCE |  *     SECP521R1            FRANCE | ||||||
|  *     GC512A               RUSSIA |  *     GC512A               RUSSIA | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								third_party/quickjs/quickjs.mk
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								third_party/quickjs/quickjs.mk
									
										
									
									
										vendored
									
									
								
							|  | @ -145,7 +145,7 @@ o/$(MODE)/third_party/quickjs/qjs.com.dbg:					\ | ||||||
| 		o/$(MODE)/third_party/quickjs/repl.o				\
 | 		o/$(MODE)/third_party/quickjs/repl.o				\
 | ||||||
| 		o/$(MODE)/third_party/quickjs/qjscalc.o				\
 | 		o/$(MODE)/third_party/quickjs/qjscalc.o				\
 | ||||||
| 		$(CRT)								\
 | 		$(CRT)								\
 | ||||||
| 		$(APE) | 		$(APE_NO_MODIFY_SELF) | ||||||
| 	@$(APELINK) | 	@$(APELINK) | ||||||
| 
 | 
 | ||||||
| o/$(MODE)/third_party/quickjs/qjs.com:						\ | o/$(MODE)/third_party/quickjs/qjs.com:						\ | ||||||
|  |  | ||||||
|  | @ -157,7 +157,8 @@ static void printelfsectionheader(int i, char *shstrtab) { | ||||||
| 
 | 
 | ||||||
| static void printelfsectionheaders(void) { | static void printelfsectionheaders(void) { | ||||||
|   Elf64_Half i; |   Elf64_Half i; | ||||||
|   char *shstrtab = GetElfSectionNameStringTable(elf, st->st_size); |   char *shstrtab; | ||||||
|  |   shstrtab = GetElfSectionNameStringTable(elf, st->st_size); | ||||||
|   if (shstrtab) { |   if (shstrtab) { | ||||||
|     printf("\n"); |     printf("\n"); | ||||||
|     printf("\t.org\t%#x\n", elf->e_shoff); |     printf("\t.org\t%#x\n", elf->e_shoff); | ||||||
|  | @ -341,7 +342,6 @@ int main(int argc, char *argv[]) { | ||||||
|     fprintf(stderr, "error: not an elf executable: %'s\n", path); |     fprintf(stderr, "error: not an elf executable: %'s\n", path); | ||||||
|     exit(1); |     exit(1); | ||||||
|   } |   } | ||||||
|   elf = (Elf64_Ehdr *)getauxval(AT_SYSINFO_EHDR); |  | ||||||
|   startfile(); |   startfile(); | ||||||
|   printelfehdr(); |   printelfehdr(); | ||||||
|   printelfsegmentheaders(); |   printelfsegmentheaders(); | ||||||
|  |  | ||||||
							
								
								
									
										166
									
								
								tool/viz/vdsosyms.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								tool/viz/vdsosyms.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,166 @@ | ||||||
|  | /*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
 | ||||||
|  | │vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :vi│ | ||||||
|  | ╞══════════════════════════════════════════════════════════════════════════════╡ | ||||||
|  | │ Copyright 2022 Justine Alexandra Roberts Tunney                              │ | ||||||
|  | │                                                                              │ | ||||||
|  | │ Permission to use, copy, modify, and/or distribute this software for         │ | ||||||
|  | │ any purpose with or without fee is hereby granted, provided that the         │ | ||||||
|  | │ above copyright notice and this permission notice appear in all copies.      │ | ||||||
|  | │                                                                              │ | ||||||
|  | │ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                │ | ||||||
|  | │ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                │ | ||||||
|  | │ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             │ | ||||||
|  | │ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         │ | ||||||
|  | │ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        │ | ||||||
|  | │ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               │ | ||||||
|  | │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │ | ||||||
|  | │ PERFORMANCE OF THIS SOFTWARE.                                                │ | ||||||
|  | ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||||
|  | #include "libc/calls/strace.internal.h" | ||||||
|  | #include "libc/elf/def.h" | ||||||
|  | #include "libc/elf/scalar.h" | ||||||
|  | #include "libc/elf/struct/ehdr.h" | ||||||
|  | #include "libc/elf/struct/phdr.h" | ||||||
|  | #include "libc/elf/struct/sym.h" | ||||||
|  | #include "libc/elf/struct/verdaux.h" | ||||||
|  | #include "libc/elf/struct/verdef.h" | ||||||
|  | #include "libc/intrin/kprintf.h" | ||||||
|  | #include "libc/runtime/runtime.h" | ||||||
|  | #include "libc/sysv/consts/auxv.h" | ||||||
|  | 
 | ||||||
|  | static inline void PrintDsoSymbolVersions(Elf64_Verdef *vd, int sym, | ||||||
|  |                                           char *strtab) { | ||||||
|  |   Elf64_Verdaux *aux; | ||||||
|  |   for (;; vd = (Elf64_Verdef *)((char *)vd + vd->vd_next)) { | ||||||
|  |     if (!(vd->vd_flags & VER_FLG_BASE) && | ||||||
|  |         (vd->vd_ndx & 0x7fff) == (sym & 0x7fff)) { | ||||||
|  |       aux = (Elf64_Verdaux *)((char *)vd + vd->vd_aux); | ||||||
|  |       kprintf(" %s", strtab + aux->vda_name); | ||||||
|  |     } | ||||||
|  |     if (!vd->vd_next) { | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int PrintVdsoSymbols(void) { | ||||||
|  |   void *p; | ||||||
|  |   size_t i; | ||||||
|  |   Elf64_Ehdr *ehdr; | ||||||
|  |   Elf64_Phdr *phdr; | ||||||
|  |   char *strtab = 0; | ||||||
|  |   size_t *dyn, base; | ||||||
|  |   unsigned long *ap; | ||||||
|  |   Elf64_Sym *symtab = 0; | ||||||
|  |   uint16_t *versym = 0; | ||||||
|  |   Elf_Symndx *hashtab = 0; | ||||||
|  |   Elf64_Verdef *verdef = 0; | ||||||
|  |   const char *typename, *bindname; | ||||||
|  | 
 | ||||||
|  |   for (ehdr = 0, ap = __auxv; ap[0]; ap += 2) { | ||||||
|  |     if (ap[0] == AT_SYSINFO_EHDR) { | ||||||
|  |       ehdr = (void *)ap[1]; | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (!ehdr) { | ||||||
|  |     kprintf("error: AT_SYSINFO_EHDR not found\n"); | ||||||
|  |     return 1; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   phdr = (void *)((char *)ehdr + ehdr->e_phoff); | ||||||
|  |   for (base = -1, dyn = 0, i = 0; i < ehdr->e_phnum; | ||||||
|  |        i++, phdr = (void *)((char *)phdr + ehdr->e_phentsize)) { | ||||||
|  |     switch (phdr->p_type) { | ||||||
|  |       case PT_LOAD: | ||||||
|  |         // modern linux uses the base address zero, but elders
 | ||||||
|  |         // e.g. rhel7 uses the base address 0xffffffffff700000
 | ||||||
|  |         base = (size_t)ehdr + phdr->p_offset - phdr->p_vaddr; | ||||||
|  |         break; | ||||||
|  |       case PT_DYNAMIC: | ||||||
|  |         dyn = (void *)((char *)ehdr + phdr->p_offset); | ||||||
|  |         break; | ||||||
|  |       default: | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (!dyn || base == -1) { | ||||||
|  |     kprintf("error: missing program headers\n"); | ||||||
|  |     return 2; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   for (i = 0; dyn[i]; i += 2) { | ||||||
|  |     p = (void *)(base + dyn[i + 1]); | ||||||
|  |     switch (dyn[i]) { | ||||||
|  |       case DT_STRTAB: | ||||||
|  |         strtab = p; | ||||||
|  |         break; | ||||||
|  |       case DT_SYMTAB: | ||||||
|  |         symtab = p; | ||||||
|  |         break; | ||||||
|  |       case DT_HASH: | ||||||
|  |         hashtab = p; | ||||||
|  |         break; | ||||||
|  |       case DT_VERSYM: | ||||||
|  |         versym = p; | ||||||
|  |         break; | ||||||
|  |       case DT_VERDEF: | ||||||
|  |         verdef = p; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (!verdef) { | ||||||
|  |     versym = 0; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (!strtab || !symtab || !hashtab) { | ||||||
|  |     kprintf("error: strtab/symtab/hashtab not found\n"); | ||||||
|  |     return 3; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   for (i = 0; i < hashtab[1]; i++) { | ||||||
|  |     if (!symtab[i].st_shndx) { | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     switch (ELF64_ST_BIND(symtab[i].st_info)) { | ||||||
|  |       case STB_LOCAL: | ||||||
|  |         bindname = "locl"; | ||||||
|  |         break; | ||||||
|  |       case STB_GLOBAL: | ||||||
|  |         bindname = "glob"; | ||||||
|  |         break; | ||||||
|  |       case STB_WEAK: | ||||||
|  |         bindname = "weak"; | ||||||
|  |         break; | ||||||
|  |       default: | ||||||
|  |         bindname = "????"; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     switch (ELF64_ST_TYPE(symtab[i].st_info)) { | ||||||
|  |       case STT_FUNC: | ||||||
|  |         typename = "func"; | ||||||
|  |         break; | ||||||
|  |       case STT_OBJECT: | ||||||
|  |         typename = " obj"; | ||||||
|  |         break; | ||||||
|  |       case STT_NOTYPE: | ||||||
|  |         typename = "none"; | ||||||
|  |         break; | ||||||
|  |       default: | ||||||
|  |         typename = "????"; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     kprintf("%s %s %-40s", bindname, typename, strtab + symtab[i].st_name); | ||||||
|  |     PrintDsoSymbolVersions(verdef, versym[i], strtab); | ||||||
|  |     kprintf("\n"); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int main(int argc, char *argv[]) { | ||||||
|  |   return PrintVdsoSymbols(); | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue