diff --git a/Makefile b/Makefile index fd1083b72..e9e61b85e 100644 --- a/Makefile +++ b/Makefile @@ -206,7 +206,7 @@ depend: o/$(MODE)/depend tags: TAGS HTAGS o/$(MODE)/.x: - @$(MKDIR) $(@D) && touch $@ + @mkdir -p $(@D) && touch $@ o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x)))) $(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x))) diff --git a/build/bootstrap/compile.com b/build/bootstrap/compile.com index ff0c7a674..8d185afef 100755 Binary files a/build/bootstrap/compile.com and b/build/bootstrap/compile.com differ diff --git a/build/definitions.mk b/build/definitions.mk index 32a8e11d1..96f22072b 100644 --- a/build/definitions.mk +++ b/build/definitions.mk @@ -46,11 +46,6 @@ V ?= 1 LC_ALL = C SOURCE_DATE_EPOCH = 0 -DD ?= /bin/dd -CP ?= /bin/cp -f -RM ?= /bin/rm -f -SED ?= /bin/sed -MKDIR ?= /bin/mkdir -p TAGS ?= /usr/bin/ctags # emacs source builds or something breaks it ARFLAGS = rcsD ZFLAGS ?= @@ -83,41 +78,14 @@ PWD := $(shell pwd) IMAGE_BASE_VIRTUAL ?= 0x400000 HELLO := $(shell build/hello) TMPDIR := $(shell build/findtmp) -COMPILE := $(shell build/getcompile) -CCVERSION := $(shell build/getccversion $(CC)) +COMPILE := $(shell build/getcompile) -V$(shell build/getccversion $(CC)) export ADDR2LINE -export CCVERSION -export COMPILE -export CP -export DD -export GZ -export IMAGE_BASE_VIRTUAL export LC_ALL -export LOGFMT -export MKDIR export MODE -export OBJDUMP -export RM -export SED export SOURCE_DATE_EPOCH export TMPDIR export V -export ZFLAGS - -unexport COMPILER_PATH -unexport CPATH -unexport CPLUS_INCLUDE_PATH -unexport C_INCLUDE_PATH -unexport DEPENDENCIES_OUTPUT -unexport GCC_COMPARE_DEBUG -unexport GCC_EXEC_PREFIX -unexport LANG -unexport LC_CTYPE -unexport LC_MESSAGES -unexport LIBRARY_PATH -unexport OBJC_INCLUDE_PATH -unexport SUNPRO_DEPENDENCIES FTRACE = \ -pg diff --git a/examples/examples.mk b/examples/examples.mk index 1374b63a4..c011a62aa 100644 --- a/examples/examples.mk +++ b/examples/examples.mk @@ -130,7 +130,7 @@ o/$(MODE)/examples/nesemu1.com.dbg: \ $(EXAMPLES_OBJS): examples/examples.mk usr/share/dict/words: usr/share/dict/words.gz - @$(MKDIR) $(dir $@) + @mkdir -p $(@D) @$(GZ) $(ZFLAGS) -d <$< >$@ .PHONY: o/$(MODE)/examples diff --git a/libc/runtime/exit.c b/libc/runtime/exit.c index 694bc000e..6cfa3cdd9 100644 --- a/libc/runtime/exit.c +++ b/libc/runtime/exit.c @@ -39,8 +39,8 @@ wontreturn void exit(int exitcode) { if (weaken(__cxa_finalize)) { weaken(__cxa_finalize)(NULL); } - for (p = *weaken(__fini_array_end); p-- > *weaken(__fini_array_start);) { - ((void (*)(void))p)(); + for (p = *weaken(__fini_array_end); p > *weaken(__fini_array_start);) { + ((void (*)(void))(*--p))(); } _Exit(exitcode); } diff --git a/libc/runtime/finddebugbinary.c b/libc/runtime/finddebugbinary.c index 29dc83e65..3b5a37d85 100644 --- a/libc/runtime/finddebugbinary.c +++ b/libc/runtime/finddebugbinary.c @@ -35,7 +35,9 @@ const char *FindDebugBinary(void) { unsigned i, len; char buf[2][PATH_MAX]; static char res[PATH_MAX]; - const char *bins[4], *pwd; + const char *bins[4], *pwd, *comdbg; + if (res[0]) return res; + if ((comdbg = emptytonull(getenv("COMDBG")))) return comdbg; if (res[0]) return res; bins[0] = program_invocation_name; bins[1] = (const char *)getauxval(AT_EXECFN); diff --git a/tool/build/compile.c b/tool/build/compile.c index 92bfb75c4..d7c1023f3 100644 --- a/tool/build/compile.c +++ b/tool/build/compile.c @@ -63,12 +63,13 @@ FLAGS\n\ \n\ -A ACTION specifies short command name for V=0 logging\n\ -T TARGET specifies target name for V=0 logging\n\ + -V NUMBER specifies compiler version\n\ -t touch target on success\n\ -n do nothing (used to prime the executable)\n\ -? print help\n\ \n" -struct Flags { +struct Args { size_t n; char **p; }; @@ -92,6 +93,7 @@ bool wantubsan; bool touchtarget; char *cmd; +char *comdbg; char *cachedcmd; char *originalcmd; char *colorflag; @@ -106,9 +108,18 @@ int columns; sigset_t mask; sigset_t savemask; -struct Flags flags; +struct Args env; +struct Args args; struct Command command; +const char *const kSafeEnv[] = { + "ADDR2LINE", // needed by GetAddr2linePath + "MAKEFLAGS", // needed by IsRunningUnderMake + "PWD", // just seems plain needed + "TERM", // needed by IsTerminalInarticulate + "TMPDIR", // needed by compiler +}; + const char *const kGccOnlyFlags[] = { "--nocompress-debug-sections", "--noexecstack", @@ -173,6 +184,27 @@ char *DescribeCommand(void) { return basename(cmd); } +bool IsSafeEnv(const char *s) { + const char *p; + int n, m, l, r, x; + p = strchr(s, '='); + n = p ? p - s : -1; + l = 0; + r = ARRAYLEN(kSafeEnv) - 1; + while (l <= r) { + m = (l + r) >> 1; + x = strncmp(s, kSafeEnv[m], n); + if (x < 0) { + r = m - 1; + } else if (x > 0) { + l = m + 1; + } else { + return true; + } + } + return false; +} + bool IsGccOnlyFlag(const char *s) { int m, l, r, x; l = 0; @@ -201,10 +233,24 @@ bool IsGccOnlyFlag(const char *s) { return false; } -void AddFlag(char *s) { +bool FileExistsAndIsNewerThan(const char *filepath, const char *thanpath) { + struct stat st1, st2; + if (stat(filepath, &st1) == -1) return false; + if (stat(thanpath, &st2) == -1) return false; + if (st1.st_mtim.tv_sec < st2.st_mtim.tv_sec) return false; + if (st1.st_mtim.tv_sec > st2.st_mtim.tv_sec) return true; + return st1.st_mtim.tv_nsec >= st2.st_mtim.tv_nsec; +} + +void AddEnv(char *s) { + env.p = realloc(env.p, ++env.n * sizeof(*env.p)); + env.p[env.n - 1] = s; +} + +void AddArg(char *s) { size_t n; - flags.p = realloc(flags.p, ++flags.n * sizeof(*flags.p)); - flags.p[flags.n - 1] = s; + args.p = realloc(args.p, ++args.n * sizeof(*args.p)); + args.p[args.n - 1] = s; if (s) { n = strlen(s); if (command.n) { @@ -229,7 +275,7 @@ int Launch(void) { if ((pid = vfork()) == -1) exit(errno); if (!pid) { sigprocmask(SIG_SETMASK, &savemask, NULL); - execv(cmd, flags.p); + execve(cmd, args.p, env.p); _exit(127); } while (waitpid(pid, &ws, 0) == -1) { @@ -239,14 +285,14 @@ int Launch(void) { } int main(int argc, char *argv[]) { - char *p; size_t n; + char *p, **envp; int i, ws, rc, opt; /* * parse prefix arguments */ - while ((opt = getopt(argc, argv, "?hntA:T:")) != -1) { + while ((opt = getopt(argc, argv, "?hntA:T:V:")) != -1) { switch (opt) { case 'n': exit(0); @@ -259,6 +305,9 @@ int main(int argc, char *argv[]) { case 'T': target = optarg; break; + case 'V': + ccversion = atoi(optarg); + break; case '?': case 'h': write(1, MANUAL, sizeof(MANUAL) - 1); @@ -278,39 +327,38 @@ int main(int argc, char *argv[]) { if (!(cmd = commandv(cmd, ccpath))) exit(127); } - ccversion = atoi(firstnonnull(emptytonull(getenv("CCVERSION")), "4")); isgcc = !!strstr(basename(cmd), "gcc"); isclang = !!strstr(basename(cmd), "clang"); iscc = isgcc | isclang; /* - * ingest flag arguments + * ingest arguments */ for (i = optind; i < argc; ++i) { if (argv[i][0] != '-') { - AddFlag(argv[i]); + AddArg(argv[i]); continue; } if (!strcmp(argv[i], "-o")) { - AddFlag(argv[i]); - AddFlag((outpath = argv[++i])); + AddArg(argv[i]); + AddArg((outpath = argv[++i])); continue; } if (!iscc) { - AddFlag(argv[i]); + AddArg(argv[i]); continue; } if (isclang && IsGccOnlyFlag(argv[i])) { continue; } if (!strcmp(argv[i], "-w")) { - AddFlag(argv[i]); - AddFlag("-D__W__"); + AddArg(argv[i]); + AddArg("-D__W__"); } else if (!strcmp(argv[i], "-Oz")) { if (isclang) { - AddFlag(argv[i]); + AddArg(argv[i]); } else { - AddFlag("-Os"); + AddArg("-Os"); } } else if (!strcmp(argv[i], "-pg")) { wantpg = true; @@ -328,17 +376,17 @@ int main(int argc, char *argv[]) { wantframe = false; } else if (!strcmp(argv[i], "-mno-vzeroupper")) { if (isgcc) { - AddFlag("-Wa,-msse2avx"); - AddFlag("-D__MNO_VZEROUPPER__"); + AddArg("-Wa,-msse2avx"); + AddArg("-D__MNO_VZEROUPPER__"); } else if (isclang) { - AddFlag("-mllvm"); - AddFlag("-x86-use-vzeroupper=0"); + AddArg("-mllvm"); + AddArg("-x86-use-vzeroupper=0"); } } else if (!strcmp(argv[i], "-msse2avx")) { if (isgcc) { - AddFlag(argv[i]); + AddArg(argv[i]); } else if (isclang) { - AddFlag("-Wa,-msse2avx"); + AddArg("-Wa,-msse2avx"); } } else if (!strcmp(argv[i], "-fsanitize=address")) { if (isgcc && ccversion >= 6) wantasan = true; @@ -353,7 +401,7 @@ int main(int argc, char *argv[]) { wantubsan = false; } else if (startswith(argv[i], "-fsanitize=implicit") && strstr(argv[i], "integer")) { - if (isgcc) AddFlag(argv[i]); + if (isgcc) AddArg(argv[i]); } else if (startswith(argv[i], "-fvect-cost") || startswith(argv[i], "-mstringop") || startswith(argv[i], "-gz") || @@ -362,18 +410,18 @@ int main(int argc, char *argv[]) { startswith(argv[i], "-fvect-cost") || startswith(argv[i], "-fvect-cost")) { if (isgcc && ccversion >= 6) { - AddFlag(argv[i]); + AddArg(argv[i]); } } else if (startswith(argv[i], "-fdiagnostic-color=")) { colorflag = argv[i]; } else if (startswith(argv[i], "-R") || !strcmp(argv[i], "-fsave-optimization-record")) { - if (isclang) AddFlag(argv[i]); + if (isclang) AddArg(argv[i]); } else if (isclang && startswith(argv[i], "--debug-prefix-map")) { /* llvm doesn't provide a gas interface so simulate w/ clang */ - AddFlag(xasprintf("-f%s", argv[i] + 2)); + AddArg(xasprintf("-f%s", argv[i] + 2)); } else { - AddFlag(argv[i]); + AddArg(argv[i]); } } if (!outpath) { @@ -381,51 +429,62 @@ int main(int argc, char *argv[]) { } /* - * append special flags + * append special args */ if (iscc) { if (isclang) { - /* AddFlag("-fno-integrated-as"); */ - AddFlag("-Wno-unused-command-line-argument"); - AddFlag("-Wno-incompatible-pointer-types-discards-qualifiers"); + /* AddArg("-fno-integrated-as"); */ + AddArg("-Wno-unused-command-line-argument"); + AddArg("-Wno-incompatible-pointer-types-discards-qualifiers"); } - AddFlag("-no-canonical-prefixes"); + AddArg("-no-canonical-prefixes"); if (!IsTerminalInarticulate()) { - AddFlag(firstnonnull(colorflag, "-fdiagnostics-color=always")); + AddArg(firstnonnull(colorflag, "-fdiagnostics-color=always")); } if (wantpg && !wantnopg) { - AddFlag("-pg"); - AddFlag("-D__PG__"); + AddArg("-pg"); + AddArg("-D__PG__"); if (wantnop && !isclang) { - AddFlag("-mnop-mcount"); - AddFlag("-D__MNOP_MCOUNT__"); + AddArg("-mnop-mcount"); + AddArg("-D__MNOP_MCOUNT__"); } if (wantrecord) { - AddFlag("-mrecord-mcount"); - AddFlag("-D__MRECORD_MCOUNT__"); + AddArg("-mrecord-mcount"); + AddArg("-D__MRECORD_MCOUNT__"); } if (wantfentry) { - AddFlag("-mfentry"); - AddFlag("-D__MFENTRY__"); + AddArg("-mfentry"); + AddArg("-D__MFENTRY__"); } } if (wantasan) { - AddFlag("-fsanitize=address"); - AddFlag("-D__FSANITIZE_ADDRESS__"); + AddArg("-fsanitize=address"); + AddArg("-D__FSANITIZE_ADDRESS__"); } if (wantubsan) { - AddFlag("-fsanitize=undefined"); - AddFlag("-fno-data-sections"); + AddArg("-fsanitize=undefined"); + AddArg("-fno-data-sections"); } if (wantframe) { - AddFlag("-fno-omit-frame-pointer"); + AddArg("-fno-omit-frame-pointer"); } } /* - * terminate argument list passed to subprocess + * terminate args */ - AddFlag(NULL); + AddArg(NULL); + + /* + * scrub environment for determinism and great justice + */ + for (envp = environ; *envp; ++envp) { + if (IsSafeEnv(*envp)) { + AddEnv(*envp); + } + } + AddEnv("LC_ALL=C"); + AddEnv("SOURCE_DATE_EPOCH=0"); /* * ensure output directory exists @@ -463,10 +522,15 @@ int main(int argc, char *argv[]) { /* * create temporary copy when launching APE binaries + * and we help FindDebugBinary to find debug symbols */ if (!IsWindows() && endswith(cmd, ".com")) { + comdbg = xasprintf("%s.dbg", cmd); cachedcmd = xasprintf("o/%s", cmd); - if (fileexists(cachedcmd)) { + if (fileexists(comdbg)) { + AddEnv(xasprintf("COMDBG=%s", comdbg)); + } + if (FileExistsAndIsNewerThan(cachedcmd, cmd)) { cmd = cachedcmd; } else { if (startswith(cmd, "o/")) { @@ -478,6 +542,11 @@ int main(int argc, char *argv[]) { } } + /* + * terminate environment + */ + AddEnv(NULL); + /* * launch command */ diff --git a/tool/build/package.c b/tool/build/package.c index ce8742be5..9d9671aa9 100644 --- a/tool/build/package.c +++ b/tool/build/package.c @@ -351,8 +351,10 @@ void OpenObject(struct Package *pkg, struct Object *obj, int mode, int prot, CHECK_NE(-1, (fd = open(&pkg->strings.p[obj->path], (obj->mode = mode))), "path=%`'s", &pkg->strings.p[obj->path]); CHECK_NE(-1, fstat(fd, &st)); - CHECK_NE(MAP_FAILED, (obj->elf = mmap(NULL, (obj->size = st.st_size), prot, - flags, fd, 0))); + CHECK_NE( + MAP_FAILED, + (obj->elf = mmap(NULL, (obj->size = st.st_size), prot, flags, fd, 0)), + "path=%`'s", &pkg->strings.p[obj->path]); CHECK_NE(-1, close(fd)); CHECK(IsElf64Binary(obj->elf, obj->size), "path=%`'s", &pkg->strings.p[obj->path]);