Make improvements

- Introduce portable sched_getcpu() api
- Support GCC's __target_clones__ feature
- Make fma() go faster on x86 in default mode
- Remove some asan checks from core libraries
- WinMain() now ensures $HOME and $USER are defined
This commit is contained in:
Justine Tunney 2024-02-01 03:39:46 -08:00
parent d5225a693b
commit 2ab9e9f7fd
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
192 changed files with 2809 additions and 932 deletions

View file

@ -226,65 +226,6 @@ const char *const kSafeEnv[] = {
"SYSTEMROOT", // needed by socket()
};
const char *const kGccOnlyFlags[] = {
"--nocompress-debug-sections",
"--noexecstack",
"-Wa,--nocompress-debug-sections",
"-Wa,--noexecstack",
"-Wa,-msse2avx",
"-Wno-unused-but-set-variable",
"-Wunsafe-loop-optimizations",
"-fbranch-target-load-optimize",
"-fcx-limited-range",
"-fdelete-dead-exceptions",
"-femit-struct-debug-baseonly",
"-ffp-int-builtin-inexact",
"-finline-functions-called-once",
"-fipa-pta",
"-fivopts",
"-flimit-function-alignment",
"-fmerge-constants",
"-fmodulo-sched",
"-fmodulo-sched-allow-regmoves",
"-fno-align-jumps",
"-fno-align-labels",
"-fno-align-loops",
"-fno-cx-limited-range",
"-fno-fp-int-builtin-inexact",
"-fno-gnu-unique",
"-fno-gnu-unique",
"-fno-inline-functions-called-once",
"-fno-instrument-functions",
"-fno-schedule-insns2",
"-fno-whole-program",
"-fopt-info-vec",
"-fopt-info-vec-missed",
"-freg-struct-return",
"-freschedule-modulo-scheduled-loops",
"-frounding-math",
"-fsched2-use-superblocks",
"-fschedule-insns",
"-fschedule-insns2",
"-fshrink-wrap",
"-fshrink-wrap-separate",
"-fsignaling-nans",
"-fstack-clash-protection",
"-ftracer",
"-ftrapv",
"-ftree-loop-im",
"-ftree-loop-vectorize",
"-funsafe-loop-optimizations",
"-fversion-loops-for-strides",
"-fwhole-program",
"-gdescribe-dies",
"-gstabs",
"-mcall-ms2sysv-xlogues",
"-mdispatch-scheduler",
"-mfpmath=sse+387",
"-mmitigate-rop",
"-mno-fentry",
};
void OnAlrm(int sig) {
++gotalrm;
}
@ -400,21 +341,38 @@ bool IsSafeEnv(const char *s) {
return false;
}
bool IsGccOnlyFlag(const char *s) {
int m, l, r, x;
l = 0;
r = ARRAYLEN(kGccOnlyFlags) - 1;
while (l <= r) {
m = (l & r) + ((l ^ r) >> 1); // floor((a+b)/2)
x = strcmp(s, kGccOnlyFlags[m]);
if (x < 0) {
r = m - 1;
} else if (x > 0) {
l = m + 1;
} else {
return true;
char *Slurp(const char *path) {
int fd;
char *res = 0;
if ((fd = open(path, O_RDONLY)) != -1) {
ssize_t size;
if ((size = lseek(fd, 0, SEEK_END)) != -1) {
char *buf;
if ((buf = calloc(1, size + 1))) {
if (pread(fd, buf, size, 0) == size) {
res = buf;
} else {
free(buf);
}
}
}
close(fd);
}
return res;
}
bool HasFlag(const char *flags, const char *s) {
char buf[256];
size_t n = strlen(s);
if (!flags) return false;
if (n + 2 > sizeof(buf)) return false;
memcpy(buf, s, n);
buf[n] = '\n';
buf[n + 1] = 0;
return !!strstr(flags, buf);
}
bool IsGccOnlyFlag(const char *s) {
if (s[0] == '-') {
if (s[1] == 'f') {
if (startswith(s, "-ffixed-")) return true;
@ -428,8 +386,25 @@ bool IsGccOnlyFlag(const char *s) {
if (startswith(s, "-mstringop-strategy=")) return true;
if (startswith(s, "-mpreferred-stack-boundary=")) return true;
if (startswith(s, "-Wframe-larger-than=")) return true;
if (startswith(s, "-Walloca-larger-than=")) return true;
}
return false;
static bool once;
static char *gcc_only_flags;
if (!once) {
gcc_only_flags = Slurp("build/bootstrap/gcc-only-flags.txt");
once = true;
}
return HasFlag(gcc_only_flags, s);
}
bool IsClangOnlyFlag(const char *s) {
static bool once;
static char *clang_only_flags;
if (!once) {
clang_only_flags = Slurp("build/bootstrap/clang-only-flags.txt");
once = true;
}
return HasFlag(clang_only_flags, s);
}
bool FileExistsAndIsNewerThan(const char *filepath, const char *thanpath) {
@ -926,12 +901,12 @@ int main(int argc, char *argv[]) {
}
s = basename(strdup(cmd));
if (strstr(s, "gcc") || strstr(s, "g++")) {
iscc = true;
isgcc = true;
} else if (strstr(s, "clang") || strstr(s, "clang++")) {
if (strstr(s, "clang") || strstr(s, "clang++")) {
iscc = true;
isclang = true;
} else if (strstr(s, "gcc") || strstr(s, "g++")) {
iscc = true;
isgcc = true;
} else if (strstr(s, "ld.bfd")) {
isbfd = true;
} else if (strstr(s, "ar.com")) {
@ -990,6 +965,9 @@ int main(int argc, char *argv[]) {
AddArg(argv[i]);
continue;
}
if (isgcc && IsClangOnlyFlag(argv[i])) {
continue;
}
if (isclang && IsGccOnlyFlag(argv[i])) {
continue;
}
@ -1188,7 +1166,9 @@ int main(int argc, char *argv[]) {
!strcmp(argv[i], "-O3"))) {
/* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97623 */
AddArg(argv[i]);
AddArg("-fno-code-hoisting");
if (!isclang) {
AddArg("-fno-code-hoisting");
}
} else {
AddArg(argv[i]);
}

64
tool/build/findape.c Normal file
View file

@ -0,0 +1,64 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 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/calls.h"
#include "libc/runtime/runtime.h"
#include "libc/serialize.h"
#include "libc/stdio/ftw.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h"
// finds ape executables
// usage: findelf PATH...
static int OnFile(const char *fpath, const struct stat *st, int typeflag,
struct FTW *ftwbuf) {
if (typeflag == FTW_F) {
char buf[8] = {0};
int fd = open(fpath, O_RDONLY);
if (fd != -1) {
pread(fd, buf, sizeof(buf), 0);
close(fd);
if (READ64LE(buf) == READ64LE("MZqFpD='") ||
READ64LE(buf) == READ64LE("jartsr='") ||
READ64LE(buf) == READ64LE("APEDBG='")) {
tinyprint(1, fpath, "\n", NULL);
}
} else {
perror(fpath);
}
}
return 0;
}
static void HandleArg(const char *path) {
if (nftw(path, OnFile, 128, FTW_PHYS | FTW_DEPTH)) {
perror(path);
exit(1);
}
}
int main(int argc, char *argv[]) {
if (argc <= 1) {
HandleArg(".");
} else {
for (int i = 1; i < argc; ++i) {
HandleArg(argv[i]);
}
}
}

65
tool/build/findelf.c Normal file
View file

@ -0,0 +1,65 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2023 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/calls.h"
#include "libc/elf/def.h"
#include "libc/elf/struct/ehdr.h"
#include "libc/runtime/runtime.h"
#include "libc/serialize.h"
#include "libc/stdio/ftw.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/o.h"
// finds elf executables
// usage: findelf PATH...
static int OnFile(const char *fpath, const struct stat *st, int typeflag,
struct FTW *ftwbuf) {
if (typeflag == FTW_F && (st->st_mode & 0111)) {
Elf64_Ehdr ehdr = {0};
int fd = open(fpath, O_RDONLY);
if (fd != -1) {
pread(fd, &ehdr, sizeof(ehdr), 0);
close(fd);
if (READ32LE(ehdr.e_ident) == READ32LE(ELFMAG) && ehdr.e_type != ET_REL) {
tinyprint(1, fpath, "\n", NULL);
}
} else {
perror(fpath);
}
}
return 0;
}
static void HandleArg(const char *path) {
if (nftw(path, OnFile, 128, FTW_PHYS | FTW_DEPTH)) {
perror(path);
exit(1);
}
}
int main(int argc, char *argv[]) {
if (argc <= 1) {
HandleArg(".");
} else {
for (int i = 1; i < argc; ++i) {
HandleArg(argv[i]);
}
}
}

View file

@ -22,6 +22,9 @@
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/o.h"
// finds portable executables (and actually portable executable)
// usage: findelf PATH...
static int OnFile(const char *fpath, const struct stat *st, int typeflag,
struct FTW *ftwbuf) {
if (typeflag == FTW_F) {

View file

@ -29,13 +29,16 @@
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/limits.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.h"
#include "libc/runtime/runtime.h"
#include "libc/serialize.h"
#include "libc/stdalign.internal.h"
#include "libc/stdckdint.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/msync.h"
@ -48,8 +51,10 @@
* @fileoverview GCC Codegen Fixer-Upper.
*/
#define COSMO_TLS_REG 28
#define MRS_TPIDR_EL0 0xd53bd040u
#define COSMO_TLS_REG 28
#define MRS_TPIDR_EL0 0xd53bd040u
#define IFUNC_SECTION ".init.202.ifunc"
#define MOV_REG(DST, SRC) (0xaa0003e0u | (SRC) << 16 | (DST))
static int mode;
@ -365,6 +370,203 @@ static void RelinkZipFiles(void) {
eocd = foot;
}
// when __attribute__((__target_clones__(...))) is used, the compiler
// will generate multiple implementations of a function for different
// microarchitectures as well as a resolver function that tells which
// function is appropriate to call. however the compiler doesn't make
// code for the actual function. it also doesn't record where resolve
// functions are located in the binary so we've reverse eng'd it here
static void GenerateIfuncInit(void) {
char *name, *s;
long code_i = 0;
long relas_i = 0;
static char code[16384];
static Elf64_Rela relas[1024];
Elf64_Shdr *symtab_shdr = GetElfSymbolTable(elf, esize, SHT_SYMTAB, 0);
if (!symtab_shdr) Die("symbol table section header not found");
Elf64_Word symtab_shdr_index =
((char *)symtab_shdr - ((char *)elf + elf->e_shoff)) / elf->e_shentsize;
for (Elf64_Xword i = 0; i < symcount; ++i) {
if (syms[i].st_shndx == SHN_UNDEF) continue;
if (syms[i].st_shndx >= SHN_LORESERVE) continue;
if (ELF64_ST_TYPE(syms[i].st_info) != STT_GNU_IFUNC) continue;
if (!(name = GetElfString(elf, esize, symstrs, syms[i].st_name)))
Die("could not get symbol name of ifunc");
static char resolver_name[65536];
strlcpy(resolver_name, name, sizeof(resolver_name));
if (strlcat(resolver_name, ".resolver", sizeof(resolver_name)) >=
sizeof(resolver_name))
Die("ifunc name too long");
Elf64_Xword function_sym_index = i;
Elf64_Xword resolver_sym_index = -1;
for (Elf64_Xword i = 0; i < symcount; ++i) {
if (syms[i].st_shndx == SHN_UNDEF) continue;
if (syms[i].st_shndx >= SHN_LORESERVE) continue;
if (ELF64_ST_TYPE(syms[i].st_info) != STT_FUNC) continue;
if (!(s = GetElfString(elf, esize, symstrs, syms[i].st_name))) continue;
if (strcmp(s, resolver_name)) continue;
resolver_sym_index = i;
break;
}
if (resolver_sym_index == -1)
// this can happen if a function with __target_clones() also has a
// __weak_reference() defined, in which case GCC shall only create
// one resolver function for the two of them so we can ignore this
// HOWEVER the GOT will still have an entry for each two functions
continue;
// call the resolver (using cosmo's special .init abi)
static const char chunk1[] = {
0x57, // push %rdi
0x56, // push %rsi
0xe8, 0x00, 0x00, 0x00, 0x00, // call f.resolver
};
if (code_i + sizeof(chunk1) > sizeof(code) || relas_i + 1 > ARRAYLEN(relas))
Die("too many ifuncs");
memcpy(code + code_i, chunk1, sizeof(chunk1));
relas[relas_i].r_info = ELF64_R_INFO(resolver_sym_index, R_X86_64_PLT32);
relas[relas_i].r_offset = code_i + 1 + 1 + 1;
relas[relas_i].r_addend = -4;
code_i += sizeof(chunk1);
relas_i += 1;
// move the resolved function address into the GOT slot. it's very
// important that this happen, because the linker by default makes
// self-referencing PLT functions whose execution falls through oh
// no. we need to repeat this process for any aliases this defines
static const char chunk2[] = {
0x48, 0x89, 0x05, 0x00, 0x00, 0x00, 0x00, // mov %rax,f@gotpcrel(%rip)
};
for (Elf64_Xword i = 0; i < symcount; ++i) {
if (i == function_sym_index ||
(ELF64_ST_TYPE(syms[i].st_info) == STT_GNU_IFUNC &&
syms[i].st_shndx == syms[function_sym_index].st_shndx &&
syms[i].st_value == syms[function_sym_index].st_value)) {
if (code_i + sizeof(chunk2) > sizeof(code) ||
relas_i + 1 > ARRAYLEN(relas))
Die("too many ifuncs");
memcpy(code + code_i, chunk2, sizeof(chunk2));
relas[relas_i].r_info = ELF64_R_INFO(i, R_X86_64_GOTPCREL);
relas[relas_i].r_offset = code_i + 3;
relas[relas_i].r_addend = -4;
code_i += sizeof(chunk2);
relas_i += 1;
}
}
static const char chunk3[] = {
0x5e, // pop %rsi
0x5f, // pop %rdi
};
if (code_i + sizeof(chunk3) > sizeof(code)) Die("too many ifuncs");
memcpy(code + code_i, chunk3, sizeof(chunk3));
code_i += sizeof(chunk3);
}
if (!code_i) return;
// prepare to mutate elf
// remap file so it has more space
if (elf->e_shnum + 2 > 65535) Die("too many sections");
size_t reserve_size = esize + 32 * 1024 * 1024;
if (ftruncate(fildes, reserve_size)) SysExit("ifunc ftruncate #1");
elf = mmap((char *)elf, reserve_size, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, fildes, 0);
if (elf == MAP_FAILED) SysExit("ifunc mmap");
// duplicate section name strings table to end of file
Elf64_Shdr *shdrstr_shdr = (Elf64_Shdr *)((char *)elf + elf->e_shoff +
elf->e_shstrndx * elf->e_shentsize);
memcpy((char *)elf + esize, (char *)elf + shdrstr_shdr->sh_offset,
shdrstr_shdr->sh_size);
shdrstr_shdr->sh_offset = esize;
esize += shdrstr_shdr->sh_size;
// append strings for the two sections we're creating
const char *code_section_name = IFUNC_SECTION;
Elf64_Word code_section_name_offset = shdrstr_shdr->sh_size;
memcpy((char *)elf + esize, code_section_name, strlen(code_section_name) + 1);
shdrstr_shdr->sh_size += strlen(code_section_name) + 1;
esize += strlen(code_section_name) + 1;
const char *rela_section_name = ".rela" IFUNC_SECTION;
Elf64_Word rela_section_name_offset = shdrstr_shdr->sh_size;
memcpy((char *)elf + esize, rela_section_name, strlen(rela_section_name) + 1);
shdrstr_shdr->sh_size += strlen(rela_section_name) + 1;
esize += strlen(rela_section_name) + 1;
unassert(esize == shdrstr_shdr->sh_offset + shdrstr_shdr->sh_size);
++esize;
// duplicate section headers to end of file
esize = (esize + alignof(Elf64_Shdr) - 1) & -alignof(Elf64_Shdr);
memcpy((char *)elf + esize, (char *)elf + elf->e_shoff,
elf->e_shnum * elf->e_shentsize);
elf->e_shoff = esize;
esize += elf->e_shnum * elf->e_shentsize;
unassert(esize == elf->e_shoff + elf->e_shnum * elf->e_shentsize);
// append code section header
Elf64_Shdr *code_shdr = (Elf64_Shdr *)((char *)elf + esize);
Elf64_Word code_shdr_index = elf->e_shnum++;
esize += elf->e_shentsize;
code_shdr->sh_name = code_section_name_offset;
code_shdr->sh_type = SHT_PROGBITS;
code_shdr->sh_flags = SHF_ALLOC | SHF_EXECINSTR;
code_shdr->sh_addr = 0;
code_shdr->sh_link = 0;
code_shdr->sh_info = 0;
code_shdr->sh_entsize = 1;
code_shdr->sh_addralign = 1;
code_shdr->sh_size = code_i;
// append code's rela section header
Elf64_Shdr *rela_shdr = (Elf64_Shdr *)((char *)elf + esize);
esize += elf->e_shentsize;
rela_shdr->sh_name = rela_section_name_offset;
rela_shdr->sh_type = SHT_RELA;
rela_shdr->sh_flags = SHF_INFO_LINK;
rela_shdr->sh_addr = 0;
rela_shdr->sh_info = code_shdr_index;
rela_shdr->sh_link = symtab_shdr_index;
rela_shdr->sh_entsize = sizeof(Elf64_Rela);
rela_shdr->sh_addralign = alignof(Elf64_Rela);
rela_shdr->sh_size = relas_i * sizeof(Elf64_Rela);
elf->e_shnum++;
// append relas
esize = (esize + 63) & -64;
rela_shdr->sh_offset = esize;
memcpy((char *)elf + esize, relas, relas_i * sizeof(Elf64_Rela));
esize += relas_i * sizeof(Elf64_Rela);
unassert(esize == rela_shdr->sh_offset + rela_shdr->sh_size);
// append code
esize = (esize + 63) & -64;
code_shdr->sh_offset = esize;
memcpy((char *)elf + esize, code, code_i);
esize += code_i;
unassert(esize == code_shdr->sh_offset + code_shdr->sh_size);
if (ftruncate(fildes, esize)) SysExit("ifunc ftruncate #1");
}
// when __attribute__((__target_clones__(...))) is used, static binaries
// become poisoned with rela IFUNC relocations, which the linker refuses
// to remove. even if we objcopy the ape executable as binary the linker
// preserves its precious ifunc code and puts them before the executable
// header. the good news is that the linker actually does link correctly
// which means we can delete the broken rela sections in the elf binary.
static void PurgeIfuncSections(void) {
Elf64_Shdr *shdrs = (Elf64_Shdr *)((char *)elf + elf->e_shoff);
for (Elf64_Word i = 0; i < elf->e_shnum; ++i) {
char *name;
if (shdrs[i].sh_type == SHT_RELA ||
((name = GetElfSectionName(elf, esize, shdrs + i)) &&
!strcmp(name, ".init.202.ifunc"))) {
shdrs[i].sh_type = SHT_NULL;
shdrs[i].sh_flags &= ~SHF_ALLOC;
}
}
}
static void FixupObject(void) {
if ((fildes = open(epath, mode)) == -1) {
SysExit("open");
@ -373,8 +575,8 @@ static void FixupObject(void) {
SysExit("lseek");
}
if (esize) {
if ((elf = mmap(0, esize, PROT_READ | PROT_WRITE, MAP_SHARED, fildes, 0)) ==
MAP_FAILED) {
if ((elf = mmap((void *)0x003210000000, esize, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_SHARED, fildes, 0)) == MAP_FAILED) {
SysExit("mmap");
}
if (!IsElf64Binary(elf, esize)) {
@ -393,6 +595,7 @@ static void FixupObject(void) {
if (mode == O_RDWR) {
if (elf->e_machine == EM_NEXGEN32E) {
OptimizePatchableFunctionEntries();
GenerateIfuncInit();
} else if (elf->e_machine == EM_AARCH64) {
RewriteTlsCode();
if (elf->e_type != ET_REL) {
@ -400,6 +603,7 @@ static void FixupObject(void) {
}
}
if (elf->e_type != ET_REL) {
PurgeIfuncSections();
RelinkZipFiles();
}
if (msync(elf, esize, MS_ASYNC | MS_INVALIDATE)) {

View file

@ -19,6 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/fmt/libgen.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/kprintf.h"
@ -45,48 +46,48 @@
"copyright 2023 justine tunney\n" \
"https://github.com/jart/cosmopolitan\n"
#define MANUAL \
" -r o// -o OUTPUT INPUT...\n" \
"\n" \
"DESCRIPTION\n" \
"\n" \
" Generates header file dependencies for your makefile\n" \
"\n" \
" This tool computes the transitive closure of included paths\n" \
" for every source file in your repository. This program does\n" \
" it orders of a magnitude faster than `gcc -M` on each file.\n" \
"\n" \
" Includes look like this:\n" \
"\n" \
" - #include <stdio.h>\n" \
" - #include \"samedir.h\"\n" \
" - #include \"root/of/repository/foo.h\"\n" \
" - .include \"asm/x86_64/foo.s\"\n" \
"\n" \
" Your generated make code looks like this:\n" \
"\n" \
" o//package/foo.o: \\\n" \
" package/foo.c \\\n" \
" package/foo.h \\\n" \
" package/bar.h \\\n" \
" libc/isystem/stdio.h\n" \
" o//package/bar.o: \\\n" \
" package/bar.c \\\n" \
" package/bar.h\n" \
"\n" \
"FLAGS\n" \
"\n" \
" -h show usage\n" \
" -o OUTPUT set output path\n" \
" -g ROOT set generated path [default: o/]\n" \
" -r ROOT set build output path, e.g. o/$(MODE)/\n" \
" -S PATH isystem include path [default: libc/isystem/]\n" \
" -s hermetically sealed mode [repeatable]\n" \
"\n" \
"ARGUMENTS\n" \
"\n" \
" OUTPUT shall be makefile code\n" \
" INPUT should be source or @args.txt\n" \
#define MANUAL \
" -r o// -o OUTPUT INPUT...\n" \
"\n" \
"DESCRIPTION\n" \
"\n" \
" Generates header file dependencies for your makefile\n" \
"\n" \
" This tool computes the transitive closure of included paths\n" \
" for every source file in your repository. This program does\n" \
" it orders of a magnitude faster than `gcc -M` on each file.\n" \
"\n" \
" Includes look like this:\n" \
"\n" \
" - #include <stdio.h>\n" \
" - #include \"samedir.h\"\n" \
" - #include \"root/of/repository/foo.h\"\n" \
" - .include \"asm/x86_64/foo.s\"\n" \
"\n" \
" Your generated make code looks like this:\n" \
"\n" \
" o//package/foo.o: \\\n" \
" package/foo.c \\\n" \
" package/foo.h \\\n" \
" package/bar.h \\\n" \
" libc/isystem/stdio.h\n" \
" o//package/bar.o: \\\n" \
" package/bar.c \\\n" \
" package/bar.h\n" \
"\n" \
"FLAGS\n" \
"\n" \
" -h show usage\n" \
" -o OUTPUT set output path\n" \
" -g ROOT set generated path [default: o/]\n" \
" -r ROOT set build output path, e.g. o/$(MODE)/\n" \
" -S PATH isystem include path [repeatable; default: libc/isystem/]\n" \
" -s hermetically sealed mode [repeatable]\n" \
"\n" \
"ARGUMENTS\n" \
"\n" \
" OUTPUT shall be makefile code\n" \
" INPUT should be source or @args.txt\n" \
"\n"
#define Read32(s) (s[3] << 24 | s[2] << 16 | s[1] << 8 | s[0])
@ -118,6 +119,11 @@ struct Edges {
struct Edge *p;
};
struct Paths {
long n;
const char *p[64];
};
static const uint32_t kSourceExts[] = {
EXT("s"), // assembly
EXT("S"), // assembly with c preprocessor
@ -135,7 +141,7 @@ static const char *prog;
static struct Edges edges;
static struct Sauce *sauces;
static struct Sources sources;
static const char *systempath;
static struct Paths systempaths;
static const char *buildroot;
static const char *genroot;
static const char *outpath;
@ -329,7 +335,7 @@ static const char *FindIncludePath(const char *map, size_t mapsize,
// scan backwards for hash character
for (;;) {
if (q == map) {
return false;
return 0;
}
if (IsBlank(q[-1])) {
--q;
@ -342,7 +348,7 @@ static const char *FindIncludePath(const char *map, size_t mapsize,
--q;
break;
} else {
return false;
return 0;
}
}
@ -359,7 +365,7 @@ static const char *FindIncludePath(const char *map, size_t mapsize,
if (q[-1] == '\n') {
break;
} else {
return false;
return 0;
}
}
}
@ -378,7 +384,7 @@ static const char *FindIncludePath(const char *map, size_t mapsize,
++q;
break;
} else {
return false;
return 0;
}
}
@ -395,7 +401,7 @@ static void LoadRelationships(int argc, char *argv[]) {
struct GetArgs ga;
int srcid, dependency;
static char srcdirbuf[PATH_MAX];
const char *p, *pe, *src, *path, *pathend, *srcdir;
const char *p, *pe, *src, *path, *pathend, *srcdir, *final;
getargs_init(&ga, argv + optind);
while ((src = getargs_next(&ga))) {
CreateSourceId(src);
@ -433,51 +439,71 @@ static void LoadRelationships(int argc, char *argv[]) {
DieSys(src);
}
for (p = map, pe = map + size; p < pe; ++p) {
char *bp;
char right;
char buf[PATH_MAX];
if (!(p = memmem(p, pe - p, "include ", 8))) break;
if (!(path = FindIncludePath(map, size, p, is_assembly))) continue;
bp = buf;
// copy the specified include path
char right;
if (path[-1] == '<') {
if (!systempath) continue;
bp = stpcpy(bp, systempath);
if (!systempaths.n) continue;
right = '>';
} else {
right = '"';
}
if ((pathend = memchr(path, right, pe - path))) {
const char *final;
char juf[PATH_MAX];
if ((bp - buf) + (pathend - path) >= PATH_MAX) {
tinyprint(2, src, ": include path too long\n", NULL);
exit(1);
}
*(bp = mempcpy(bp, path, pathend - path)) = 0;
// let foo/bar.c say `#include "foo/hdr.h"`
dependency = GetSourceId((final = buf));
// let foo/bar.c say `#include "hdr.h"`
if (dependency == -1 && right == '"' && !strchr(buf, '/')) {
if (!(final = __join_paths(juf, PATH_MAX, srcdir, buf))) {
DiePathTooLong(buf);
if (!(pathend = memchr(path, right, pe - path))) continue;
if (pathend - path >= PATH_MAX) {
tinyprint(2, src, ": uses really long include path\n", NULL);
exit(1);
}
char juf[PATH_MAX];
char incpath[PATH_MAX];
*(char *)mempcpy(incpath, path, pathend - path) = 0;
if (right == '>') {
// handle angle bracket includes
dependency = -1;
for (long i = 0; i < systempaths.n; ++i) {
if (!(final =
__join_paths(juf, PATH_MAX, systempaths.p[i], incpath))) {
DiePathTooLong(incpath);
}
if ((dependency = GetSourceId(final)) != -1) {
break;
}
dependency = GetSourceId(final);
}
if (dependency == -1) {
if (startswith(buf, genroot)) {
dependency = CreateSourceId(src);
} else if (!hermetic) {
continue;
} else if (hermetic == 1 && right == '>') {
if (dependency != -1) {
AppendEdge(&edges, dependency, srcid);
p = pathend + 1;
} else {
if (hermetic == 1) {
// chances are the `#include <foo>` is in some #ifdef
// that'll never actually be executed; thus we ignore
// since landlock make unveil() shall catch it anyway
continue;
}
tinyprint(2, incpath,
": system header not specified by the HDRS/SRCS/INCS "
"make variables defined by the hermetic mono repo\n",
NULL);
exit(1);
}
} else {
// handle double quote includes
// let foo/bar.c say `#include "foo/hdr.h"`
dependency = GetSourceId((final = incpath));
// let foo/bar.c say `#include "hdr.h"`
if (dependency == -1 && !strchr(final, '/')) {
if (!(final = __join_paths(juf, PATH_MAX, srcdir, final))) {
DiePathTooLong(incpath);
}
dependency = GetSourceId(final);
}
if (dependency == -1) {
if (startswith(final, genroot)) {
dependency = CreateSourceId(src);
} else {
tinyprint(
2, final,
": path not specified by HDRS/SRCS/INCS make variables\n",
NULL);
tinyprint(2, incpath,
": path not specified by HDRS/SRCS/INCS make variables "
"(it was included by ",
src, ")\n", NULL);
exit(1);
}
}
@ -498,6 +524,13 @@ static wontreturn void ShowUsage(int rc, int fd) {
exit(rc);
}
static void AddPath(struct Paths *paths, const char *path) {
if (paths->n == ARRAYLEN(paths->p)) {
Die("too many path arguments");
}
paths->p[paths->n++] = path;
}
static void GetOpts(int argc, char *argv[]) {
int opt;
while ((opt = getopt(argc, argv, "hnsgS:o:r:")) != -1) {
@ -506,10 +539,7 @@ static void GetOpts(int argc, char *argv[]) {
++hermetic;
break;
case 'S':
if (systempath) {
Die("multiple system paths not supported yet");
}
systempath = optarg;
AddPath(&systempaths, optarg);
break;
case 'o':
if (outpath) {
@ -555,29 +585,33 @@ static void GetOpts(int argc, char *argv[]) {
if (!startswith(buildroot, genroot)) {
Die("build output path must start with generated output path");
}
if (!systempath && hermetic) {
systempath = "libc/isystem/";
if (!systempaths.n && hermetic) {
AddPath(&systempaths, "third_party/libcxx/include/");
AddPath(&systempaths, "libc/isystem/");
}
if (systempath && !hermetic) {
if (systempaths.n && !hermetic) {
Die("system path can only be specified in hermetic mode");
}
if (systempath) {
long j = 0;
for (long i = 0; i < systempaths.n; ++i) {
size_t n;
struct stat st;
if (stat(systempath, &st)) {
DieSys(systempath);
const char *path = systempaths.p[i];
if (!stat(path, &st)) {
systempaths.p[j++] = path;
if (!S_ISDIR(st.st_mode)) {
errno = ENOTDIR;
DieSys(path);
}
}
if (!S_ISDIR(st.st_mode)) {
errno = ENOTDIR;
DieSys(systempath);
if ((n = strlen(path)) >= PATH_MAX) {
DiePathTooLong(path);
}
if ((n = strlen(systempath)) >= PATH_MAX) {
DiePathTooLong(systempath);
}
if (!n || systempath[n - 1] != '/') {
if (!n || path[n - 1] != '/') {
Die("system path must end with slash");
}
}
systempaths.n = j;
}
static const char *StripExt(char pathbuf[hasatleast PATH_MAX], const char *s) {

View file

@ -201,7 +201,7 @@ static void ValidateMachoSection(const char *inpath, //
Die(inpath, "don't bother with mach-o sections");
}
namelen = strnlen(loadseg->name, sizeof(loadseg->name));
if (!loadseg->name) {
if (!loadseg->name[0]) {
Die(inpath, "mach-o load segment missing name");
}
if (filesize || (loadseg->vaddr && loadseg->memsz)) {

View file

@ -433,7 +433,8 @@ static void LoadSymbols(struct Package *pkg, uint32_t object) {
symbol.type = ELF64_ST_TYPE(obj->syms[i].st_info);
if (symbol.bind_ != STB_LOCAL &&
(symbol.type == STT_OBJECT || symbol.type == STT_FUNC ||
symbol.type == STT_COMMON || symbol.type == STT_NOTYPE)) {
symbol.type == STT_COMMON || symbol.type == STT_NOTYPE ||
symbol.type == STT_GNU_IFUNC)) {
if (!(name = GetElfString(obj->elf, obj->size, obj->strs,
obj->syms[i].st_name))) {
Die("error", "elf overflow");

View file

@ -151,17 +151,11 @@ void Connect(void) {
struct timespec deadline;
if ((rc = getaddrinfo(g_hostname, gc(xasprintf("%hu", g_runitdport)),
&kResolvHints, &ai)) != 0) {
FATALF("%s:%hu: EAI_%s %m", g_hostname, g_runitdport, gai_strerror(rc));
FATALF("%s:%hu: DNS lookup failed: %s", g_hostname, g_runitdport,
gai_strerror(rc));
__builtin_unreachable();
}
ip4 = (const char *)&((struct sockaddr_in *)ai->ai_addr)->sin_addr;
if (ispublicip(ai->ai_family,
&((struct sockaddr_in *)ai->ai_addr)->sin_addr)) {
FATALF("%s points to %hhu.%hhu.%hhu.%hhu"
" which isn't part of a local/private/testing subnet",
g_hostname, ip4[0], ip4[1], ip4[2], ip4[3]);
__builtin_unreachable();
}
DEBUGF("connecting to %d.%d.%d.%d port %d", ip4[0], ip4[1], ip4[2], ip4[3],
ntohs(((struct sockaddr_in *)ai->ai_addr)->sin_port));
CHECK_NE(-1,

View file

@ -26,7 +26,6 @@
#include "libc/errno.h"
#include "libc/fmt/conv.h"
#include "libc/fmt/libgen.h"
#include "libc/serialize.h"
#include "libc/intrin/safemacros.internal.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
@ -34,6 +33,7 @@
#include "libc/mem/gc.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/serialize.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/auxv.h"

View file

@ -125,7 +125,7 @@ Keywords={
"mayalias",
"dontinstrument",
"interruptfn",
"nocallback",
"dontcallback",
"textstartup",
"warnifused",
"attributeallocsize",

View file

@ -67,7 +67,8 @@
"progbits"
"nobits"
"init_array"
"fini_array")])
"fini_array"
"gnu_indirect_function")])
"\\>"])
"GNU Assembler section, relocation, macro param qualifiers.")

View file

@ -91,7 +91,7 @@
"mayalias"
"dontinstrument"
"interruptfn"
"nocallback"
"dontcallback"
"textstartup"
"warnifused"
"attributeallocsize"
@ -206,6 +206,9 @@
"__section__"
"__sentinel__"
"__simd__"
"__vex"
"__avx2"
"__target_clones"
"__target_clones__"
"__unused__"
"__used__"

View file

@ -71,7 +71,8 @@
"__SUPPORT_SNAN__"
"__GCC_IEC_559_COMPLEX"
"__NO_MATH_ERRNO__"
"__gnu__"))
"__gnu__"
"_OPENMP"))
(cosmo
'("__LINKER__"))

View file

@ -215,7 +215,7 @@
(runs (format "o/$m/%s.com%s V=5 TESTARGS=-b" name runsuffix))
(buns (format "o/$m/test/%s_test.com%s V=5 TESTARGS=-b" name runsuffix)))
(cond ((not (member ext '("c" "cc" "cpp" "s" "S" "rl" "f")))
(format "m=%s; make -j12 MODE=$m o/$m/%s"
(format "m=%s; make -j32 MODE=$m o/$m/%s"
mode
(directory-file-name
(or (file-name-directory
@ -226,7 +226,7 @@
(cosmo-join
" && "
`("m=%s; f=o/$m/%s.com"
,(concat "make -j12 $f MODE=$m")
,(concat "make -j32 $f MODE=$m")
"scp $f $f.dbg win10:; ssh win10 ./%s.com"))
mode name (file-name-nondirectory name)))
((eq kind 'run-xnu)
@ -234,19 +234,19 @@
(cosmo-join
" && "
`("m=%s; f=o/$m/%s.com"
,(concat "make -j12 $f MODE=$m")
,(concat "make -j32 $f MODE=$m")
"scp $f $f.dbg xnu:"
"ssh xnu ./%s.com"))
mode name (file-name-nondirectory name)))
((and (equal suffix "")
(cosmo-contains "_test." (buffer-file-name)))
(format "m=%s; make -j12 MODE=$m %s"
(format "m=%s; make -j32 MODE=$m %s"
mode runs))
((and (equal suffix "")
(file-exists-p (format "%s" buddy)))
(format (cosmo-join
" && "
'("m=%s; n=%s; make -j12 o/$m/$n%s.o MODE=$m"
'("m=%s; n=%s; make -j32 o/$m/$n%s.o MODE=$m"
;; "bloat o/$m/%s.o | head"
;; "nm -C --size o/$m/%s.o | sort -r"
"echo"
@ -258,11 +258,11 @@
(cosmo-join
" && "
`("m=%s; f=o/$m/%s.com"
,(concat "make -j12 $f MODE=$m")
,(concat "make -j32 $f MODE=$m")
"build/run ./$f"))
mode name))
((eq kind 'test)
(format `"m=%s; f=o/$m/%s.com.ok && make -j12 $f MODE=$m" mode name))
(format `"m=%s; f=o/$m/%s.com.ok && make -j32 $f MODE=$m" mode name))
((and (file-regular-p this)
(file-executable-p this))
(format "build/run ./%s" file))
@ -271,7 +271,7 @@
(cosmo-join
" && "
`("m=%s; f=o/$m/%s%s.o"
,(concat "make -j12 $f MODE=$m")
,(concat "make -j32 $f MODE=$m")
;; "nm -C --size $f | sort -r"
"echo"
"size -A $f | grep '^[.T]' | grep -v 'debug\\|command.line\\|stack' | sort -rnk2"
@ -481,7 +481,7 @@
(error "don't know how to show assembly for non c/c++ source file"))
(let* ((default-directory root)
(compile-command
(format "make %s -j12 MODE=%s %s %s"
(format "make %s -j32 MODE=%s %s %s"
(or extra-make-flags "") mode asm-gcc asm-clang)))
(save-buffer)
(set-visited-file-modtime (current-time))
@ -641,11 +641,11 @@
(compile (format "sh -c %s" file)))
((eq major-mode 'lua-mode)
(let* ((mode (cosmo--make-mode arg)))
(compile (format "make -j16 MODE=%s o/%s/tool/net/redbean.com && build/run o/%s/tool/net/redbean.com -i %s" mode mode mode file))))
(compile (format "make -j32 MODE=%s o/%s/tool/net/redbean.com && build/run o/%s/tool/net/redbean.com -i %s" mode mode mode file))))
((and (eq major-mode 'python-mode)
(cosmo-startswith "third_party/python/Lib/test/" file))
(let ((mode (cosmo--make-mode arg)))
(compile (format "make -j12 MODE=%s PYHARNESSARGS=-vv PYTESTARGS=-v o/%s/%s.py.runs"
(compile (format "make -j32 MODE=%s PYHARNESSARGS=-vv PYTESTARGS=-v o/%s/%s.py.runs"
mode mode (file-name-sans-extension file)))))
((eq major-mode 'python-mode)
(compile (format "python.com %s" file)))
@ -692,8 +692,10 @@
(define-key lua-mode-map (kbd "C-c C-r") 'cosmo-run)
(define-key python-mode-map (kbd "C-c C-r") 'cosmo-run)
(define-key c-mode-map (kbd "C-c C-s") 'cosmo-run-test)
(define-key c++-mode-map (kbd "C-c C-s") 'cosmo-run-test)
(define-key c-mode-map (kbd "C-c C-_") 'cosmo-run-win7)
(define-key c-mode-map (kbd "C-c C-_") 'cosmo-run-win10))
(define-key c-mode-map (kbd "C-c C-_") 'cosmo-run-win10)
(define-key c++-mode-map (kbd "C-c C-_") 'cosmo-run-win10))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -939,7 +941,7 @@
"T[0-9][0-9]:[0-9][0-9]:[0-9][0-9]" ;; time
"[+.][0-9][0-9][0-9][0-9][0-9][0-9]" ;; micros
":\\([^:]+\\)" ;; file
":\\([0-9]+\\)")) ;; line
":\\([0-9]+\\)")) ;; line
1 2))
(eval-after-load 'compile
@ -948,6 +950,20 @@
(cons 'cosmo cosmo-compilation-regexps))
(add-to-list 'compilation-error-regexp-alist 'cosmo)))
(defvar cosmo-gcc123-compilation-regexps
(list (cosmo-join
""
'("inlined from '[^']*' at "
"\\([^:]+\\)" ;; file
":\\([0-9]+\\)")) ;; line
1 2))
(eval-after-load 'compile
'(progn
(add-to-list 'compilation-error-regexp-alist-alist
(cons 'cosmo cosmo-gcc123-compilation-regexps))
(add-to-list 'compilation-error-regexp-alist 'cosmo)))
(provide 'cosmo-stuff)
;;; cosmo-stuff.el ends here

View file

@ -340,7 +340,7 @@ cosmo_kws = frozenset([
"mallocesque",
"mayalias",
"memcpyesque",
"nocallback",
"dontcallback",
"nodebuginfo",
"__wur",
"dontinline",
@ -399,7 +399,7 @@ cosmo_kws = frozenset([
"mallocesque",
"mayalias",
"memcpyesque",
"nocallback",
"dontcallback",
"nodebuginfo",
"__wur",
"dontinline",

View file

@ -188,7 +188,7 @@ dontasan void PrintTeb(void) {
}
void PrintPeb(void) {
struct NtPeb *peb = NtGetPeb();
__seg_gs struct NtPeb *peb = NtGetPeb();
printf("\n\
\n\
new technology § peb \n\
@ -327,8 +327,6 @@ void PrintPeb(void) {
"pShimData", peb->pShimData);
printf("0x%04x: %-40s = 0x%lx\n", offsetof(struct NtPeb, AppCompatInfo),
"AppCompatInfo", peb->AppCompatInfo);
printf("0x%04x: %-40s = \"%s\"\n", offsetof(struct NtPeb, CSDVersion),
"CSDVersion", GetString(&peb->CSDVersion));
printf("0x%04x: %-40s = 0x%lx\n",
offsetof(struct NtPeb, ActivationContextData), "ActivationContextData",
peb->ActivationContextData);