Rewrite .zip.o file linker

This change takes an entirely new approach to the incremental linking of
pkzip executables. The assets created by zipobj.com are now treated like
debug data. After a .com.dbg is compiled, fixupobj.com should be run, so
it can apply fixups to the offsets and move the zip directory to the end
of the file. Since debug data doesn't get objcopy'd, a new tool has been
introduced called zipcopy.com which should be run after objcopy whenever
a .com file is created. This is all automated by the `cosmocc` toolchain
which is rapidly becoming the new recommended approach.

This change also introduces the new C23 checked arithmetic macros.
This commit is contained in:
Justine Tunney 2023-06-10 09:15:19 -07:00
parent f6407d5f7c
commit 8ff48201ca
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
125 changed files with 1056 additions and 928 deletions

View file

@ -27,7 +27,7 @@
#include "libc/sysv/consts/o.h"
#include "libc/x/x.h"
STATIC_YOINK("zip_uri_support");
STATIC_YOINK("zipos");
static struct ZipArgs {
bool initialized;

View file

@ -25,6 +25,7 @@
#include "libc/intrin/kprintf.h"
#include "libc/log/check.h"
#include "libc/runtime/runtime.h"
#include "libc/stdckdint.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/msync.h"
@ -181,8 +182,7 @@ void GetMachoPayload(const char *image, size_t imagesize, int *out_offset,
bs = atoi(script + rm[1].rm_so);
skip = atoi(script + rm[2].rm_so);
count = atoi(script + rm[3].rm_so);
if (__builtin_mul_overflow(skip, bs, &offset) ||
__builtin_mul_overflow(count, bs, &size)) {
if (ckd_mul(&offset, skip, bs) || ckd_mul(&size, count, bs)) {
kprintf("%s: integer overflow parsing macho\n");
exit(8);
}

View file

@ -28,6 +28,9 @@
#include "libc/errno.h"
#include "libc/fmt/itoa.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/intrin/bits.h"
#include "libc/intrin/kprintf.h"
#include "libc/limits.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/gc.internal.h"
@ -37,22 +40,13 @@
#include "libc/sysv/consts/msync.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/zip.internal.h"
#include "third_party/getopt/getopt.h"
/**
* @fileoverview GCC Codegen Fixer-Upper.
*/
#define GETOPTS "ch"
#define USAGE \
"\
Usage: fixupobj.com [-h] ARGS...\n\
-?\n\
-h show help\n\
-c check-only mode\n\
"
#define COSMO_TLS_REG 28
#define MRS_TPIDR_EL0 0xd53bd040u
#define MOV_REG(DST, SRC) (0xaa0003e0u | (SRC) << 16 | (DST))
@ -69,6 +63,7 @@ static const unsigned char kFatNops[8][8] = {
};
static int mode;
static int fildes;
static char *symstrs;
static char *secstrs;
static ssize_t esize;
@ -89,6 +84,11 @@ nullterminated() static void Print(int fd, const char *s, ...) {
va_end(va);
}
static wontreturn void Die(const char *reason) {
Print(2, epath, ": ", reason, "\n", NULL);
exit(1);
}
static wontreturn void SysExit(const char *func) {
const char *errstr;
if (!(errstr = _strerdoc(errno))) errstr = "EUNKNOWN";
@ -96,31 +96,68 @@ static wontreturn void SysExit(const char *func) {
exit(1);
}
static wontreturn void PrintUsage(int fd, int exitcode) {
Print(fd, "\n\
NAME\n\
\n\
Cosmopolitan Object Fixer\n\
\n\
SYNOPSIS\n\
\n\
",
program_invocation_name, " [FLAGS] OBJECT...\n\
\n\
DESCRIPTION\n\
\n\
This program applies fixups to ELF object files and executables that\n\
at build time whenever they're created by the toolchain. It's needed\n\
so that zip assets work correctly, plus this'll make code go faster.\n\
This program is also able to spot some coding errors like privileged\n\
functions calling unprivileged ones.\n\
\n\
Multiple binary files may be specified, which are modified in-place.\n\
\n\
FLAGS\n\
\n\
-h show this help\n\
-c checks only mode\n\
\n\
",
NULL);
exit(exitcode);
}
static void GetOpts(int argc, char *argv[]) {
int opt;
mode = O_RDWR;
while ((opt = getopt(argc, argv, GETOPTS)) != -1) {
while ((opt = getopt(argc, argv, "ch")) != -1) {
switch (opt) {
case 'c':
mode = O_RDONLY;
break;
case 'h':
case '?':
write(1, USAGE, sizeof(USAGE) - 1);
exit(0);
PrintUsage(1, 0);
default:
write(2, USAGE, sizeof(USAGE) - 1);
exit(64);
PrintUsage(2, 1);
}
}
if (optind == argc) {
Print(2,
"error: no elf object files specified\n"
"run ",
program_invocation_name, " -h for usage\n", NULL);
exit(1);
}
}
static Elf64_Shdr *FindElfSectionByName(const char *name) {
long i;
Elf64_Shdr *shdr;
const char *secname;
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, esize, i);
if (!strcmp(GetElfString(elf, esize, secstrs, shdr->sh_name), name)) {
if ((shdr = GetElfSectionHeaderAddress(elf, esize, i)) &&
(secname = GetElfString(elf, esize, secstrs, shdr->sh_name)) &&
!strcmp(name, secname)) {
return shdr;
}
}
@ -128,28 +165,31 @@ static Elf64_Shdr *FindElfSectionByName(const char *name) {
}
static void CheckPrivilegedCrossReferences(void) {
long i, x;
long i;
unsigned long x;
Elf64_Shdr *shdr;
const char *secname;
Elf64_Rela *rela, *erela;
if (!(shdr = FindElfSectionByName(".rela.privileged"))) return;
rela = GetElfSectionAddress(elf, esize, shdr);
if (!(rela = GetElfSectionAddress(elf, esize, shdr))) return;
erela = rela + shdr->sh_size / sizeof(*rela);
for (; rela < erela; ++rela) {
if (!ELF64_R_TYPE(rela->r_info)) continue;
if (!(x = ELF64_R_SYM(rela->r_info))) continue;
if (x >= symcount) continue;
if (syms[x].st_shndx == SHN_ABS) continue;
if (!syms[x].st_shndx) continue;
shdr = GetElfSectionHeaderAddress(elf, esize, syms[x].st_shndx);
if (~shdr->sh_flags & SHF_EXECINSTR) continue; // data reference
secname = GetElfString(elf, esize, secstrs, shdr->sh_name);
if (strcmp(".privileged", secname)) {
Print(2, epath,
": code in .privileged section "
"references symbol '",
GetElfString(elf, esize, symstrs, syms[x].st_name),
"' in unprivileged code section '", secname, "'\n", NULL);
exit(1);
if ((shdr = GetElfSectionHeaderAddress(elf, esize, syms[x].st_shndx))) {
if (~shdr->sh_flags & SHF_EXECINSTR) continue; // data reference
if ((secname = GetElfString(elf, esize, secstrs, shdr->sh_name)) &&
strcmp(".privileged", secname)) {
Print(2, epath,
": code in .privileged section "
"references symbol '",
GetElfString(elf, esize, symstrs, syms[x].st_name),
"' in unprivileged code section '", secname, "'\n", NULL);
exit(1);
}
}
}
}
@ -160,11 +200,15 @@ static void RewriteTlsCode(void) {
Elf64_Shdr *shdr;
uint32_t *p, *pe;
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, esize, i);
if (shdr->sh_type == SHT_PROGBITS && //
(shdr->sh_flags & SHF_ALLOC) && //
(shdr->sh_flags & SHF_EXECINSTR) && //
(p = GetElfSectionAddress(elf, esize, shdr))) {
if (!(shdr = GetElfSectionHeaderAddress(elf, esize, i))) {
Die("elf header overflow");
}
if (shdr->sh_type == SHT_PROGBITS && //
(shdr->sh_flags & SHF_ALLOC) && //
(shdr->sh_flags & SHF_EXECINSTR)) {
if (!(p = GetElfSectionAddress(elf, esize, shdr))) {
Die("elf header overflow");
}
for (pe = p + shdr->sh_size / 4; p <= pe; ++p) {
if ((*p & -32) == MRS_TPIDR_EL0) {
*p = MOV_REG(*p & 31, COSMO_TLS_REG);
@ -191,119 +235,140 @@ static void OptimizePatchableFunctionEntries(void) {
Elf64_Shdr *shdr;
unsigned char *p, *pe;
for (i = 0; i < symcount; ++i) {
if (ELF64_ST_TYPE(syms[i].st_info) == STT_FUNC && syms[i].st_size) {
shdr = GetElfSectionHeaderAddress(elf, esize, syms[i].st_shndx);
p = GetElfSectionAddress(elf, esize, shdr);
p += syms[i].st_value;
pe = p + syms[i].st_size;
for (; p + 1 < pe; p += n) {
if (p[0] != 0x90) break;
if (p[1] != 0x90) break;
for (n = 2; p + n < pe && n < ARRAYLEN(kFatNops); ++n) {
if (p[n] != 0x90) break;
}
memcpy(p, kFatNops[n], n);
if (!syms[i].st_size) continue;
if (ELF64_ST_TYPE(syms[i].st_info) != STT_FUNC) continue;
if (!(shdr = GetElfSectionHeaderAddress(elf, esize, syms[i].st_shndx))) {
Die("elf header overflow");
}
if (shdr->sh_type != SHT_PROGBITS) continue;
if (!(p = GetElfSectionAddress(elf, esize, shdr))) {
Die("elf header overflow");
}
p += syms[i].st_value - shdr->sh_addr;
pe = p + syms[i].st_size;
for (; p + 1 < pe; p += n) {
if (p[0] != 0x90) break;
if (p[1] != 0x90) break;
for (n = 2; p + n < pe && n < ARRAYLEN(kFatNops); ++n) {
if (p[n] != 0x90) break;
}
memcpy(p, kFatNops[n], n);
}
}
#endif /* __x86_64__ */
}
static void OptimizeRelocations(void) {
Elf64_Half i;
Elf64_Rela *rela;
unsigned char *code, *p;
Elf64_Shdr *shdr, *shdrcode;
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, esize, i);
if (shdr->sh_type == SHT_RELA) {
shdrcode = GetElfSectionHeaderAddress(elf, esize, shdr->sh_info);
if (!(shdrcode->sh_flags & SHF_EXECINSTR)) continue;
code = GetElfSectionAddress(elf, esize, shdrcode);
for (rela = GetElfSectionAddress(elf, esize, shdr);
((uintptr_t)rela + shdr->sh_entsize <=
MIN((uintptr_t)elf + esize,
(uintptr_t)elf + shdr->sh_offset + shdr->sh_size));
++rela) {
/*
* GCC isn't capable of -mnop-mcount when using -fpie.
* Let's fix that. It saves ~14 cycles per function call.
* Then libc/runtime/ftrace.greg.c morphs it back at runtime.
*/
if (ELF64_R_TYPE(rela->r_info) == R_X86_64_GOTPCRELX &&
strcmp(GetElfString(elf, esize, symstrs,
syms[ELF64_R_SYM(rela->r_info)].st_name),
"mcount") == 0) {
rela->r_info = R_X86_64_NONE;
p = code + rela->r_offset - 2;
p[0] = 0x66; /* nopw 0x00(%rax,%rax,1) */
p[1] = 0x0f;
p[2] = 0x1f;
p[3] = 0x44;
p[4] = 0x00;
p[5] = 0x00;
}
/*
* Let's just try to nop mcount calls in general due to the above.
*/
if ((ELF64_R_TYPE(rela->r_info) == R_X86_64_PC32 ||
ELF64_R_TYPE(rela->r_info) == R_X86_64_PLT32) &&
strcmp(GetElfString(elf, esize, symstrs,
syms[ELF64_R_SYM(rela->r_info)].st_name),
"mcount") == 0) {
rela->r_info = R_X86_64_NONE;
p = code + rela->r_offset - 1;
p[0] = 0x0f; /* nopl 0x00(%rax,%rax,1) */
p[1] = 0x1f;
p[2] = 0x44;
p[3] = 0x00;
p[4] = 0x00;
}
}
/**
* Converts PKZIP recs from PC-relative to RVA-relative.
*/
static void RelinkZipFiles(void) {
int rela, recs;
unsigned long cdsize, cdoffset;
unsigned char foot[kZipCdirHdrMinSize];
unsigned char *base, *xeof, *stop, *eocd, *cdir, *lfile, *cfile;
base = (unsigned char *)elf;
xeof = (unsigned char *)elf + esize;
eocd = xeof - kZipCdirHdrMinSize;
stop = base;
// scan backwards for zip eocd todo record
// that was created by libc/nexgen32e/zip.S
for (;;) {
if (eocd < stop) return;
if (READ32LE(eocd) == kZipCdirHdrMagicTodo && //
ZIP_CDIR_SIZE(eocd) && //
!ZIP_CDIR_OFFSET(eocd) && //
!ZIP_CDIR_RECORDS(eocd) && //
!ZIP_CDIR_RECORDSONDISK(eocd)) {
break;
}
eocd = memrchr(stop, 'P', eocd - base);
}
// apply fixups to zip central directory recs
recs = 0;
cdir = (stop = eocd) - (cdsize = ZIP_CDIR_SIZE(eocd));
for (cfile = cdir; cfile < stop; cfile += ZIP_CFILE_HDRSIZE(cfile)) {
if (++recs >= 65536) {
Die("too many zip central directory records");
}
if (cfile < base || //
cfile + kZipCfileHdrMinSize > xeof || //
cfile + ZIP_CFILE_HDRSIZE(cfile) > xeof) {
Die("zip central directory entry overflows image");
}
if (READ32LE(cfile) != kZipCfileHdrMagic) {
Die("bad __zip_cdir_size or zip central directory corrupted");
}
if ((rela = ZIP_CFILE_OFFSET(cfile)) < 0) {
lfile = cfile + kZipCfileOffsetOffset + rela;
} else {
lfile = base + rela; // earlier fixup failed partway?
}
if (lfile < base || //
lfile + kZipLfileHdrMinSize > xeof || //
lfile + ZIP_LFILE_SIZE(lfile) > xeof) {
Die("zip local file overflows image");
}
if (READ32LE(lfile) != kZipLfileHdrMagic) {
Die("zip central directory offset to local file corrupted");
}
if (rela < 0) {
WRITE32LE(cfile + kZipCfileOffsetOffset, lfile - base);
}
}
// append new eocd record to program image
if (esize > INT_MAX - sizeof(foot) ||
(cdoffset = esize) > INT_MAX - sizeof(foot)) {
Die("the time has come to adopt zip64");
}
bzero(foot, sizeof(foot));
WRITE32LE(foot, kZipCdirHdrMagic);
WRITE32LE(foot + kZipCdirSizeOffset, cdsize);
WRITE16LE(foot + kZipCdirRecordsOffset, recs);
WRITE32LE(foot + kZipCdirOffsetOffset, cdoffset);
WRITE16LE(foot + kZipCdirRecordsOnDiskOffset, recs);
if (pwrite(fildes, cdir, cdsize, esize) != cdsize) {
SysExit("cdir pwrite");
}
if (pwrite(fildes, foot, sizeof(foot), esize + cdsize) != sizeof(foot)) {
SysExit("eocd pwrite");
}
eocd = foot;
}
static void FixupObject(void) {
int fd;
if ((fd = open(epath, mode)) == -1) {
if ((fildes = open(epath, mode)) == -1) {
SysExit("open");
}
if ((esize = lseek(fd, 0, SEEK_END)) == -1) {
if ((esize = lseek(fildes, 0, SEEK_END)) == -1) {
SysExit("lseek");
}
if (esize) {
if ((elf = mmap(0, esize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) ==
if ((elf = mmap(0, esize, PROT_READ | PROT_WRITE, MAP_SHARED, fildes, 0)) ==
MAP_FAILED) {
SysExit("mmap");
}
if (!IsElf64Binary(elf, esize)) {
Print(2, epath, ": not an elf64 binary\n", NULL);
exit(1);
Die("not an elf64 binary");
}
if (!(syms = GetElfSymbolTable(elf, esize, &symcount))) {
Print(2, epath, ": missing elf symbol table\n", NULL);
exit(1);
Die("missing elf symbol table");
}
if (!(secstrs = GetElfSectionNameStringTable(elf, esize))) {
Print(2, epath, ": missing elf section string table\n", NULL);
exit(1);
Die("missing elf section string table");
}
if (!(symstrs = GetElfStringTable(elf, esize))) {
Print(2, epath, ": missing elf symbol string table\n", NULL);
exit(1);
Die("missing elf symbol string table");
}
CheckPrivilegedCrossReferences();
if (mode == O_RDWR) {
if (elf->e_machine == EM_NEXGEN32E) {
OptimizeRelocations();
OptimizePatchableFunctionEntries();
}
if (elf->e_machine == EM_AARCH64) {
} else if (elf->e_machine == EM_AARCH64) {
RewriteTlsCode();
}
if (elf->e_type != ET_REL) {
RelinkZipFiles();
}
if (msync(elf, esize, MS_ASYNC | MS_INVALIDATE)) {
SysExit("msync");
}
@ -312,7 +377,7 @@ static void FixupObject(void) {
SysExit("munmap");
}
}
if (close(fd)) {
if (close(fildes)) {
SysExit("close");
}
}

View file

@ -300,3 +300,20 @@ uint32_t elfwriter_relatype_abs32(const struct ElfWriter *elf) {
notpossible;
}
}
uint32_t elfwriter_relatype_pc32(const struct ElfWriter *elf) {
switch (elf->ehdr->e_machine) {
case EM_NEXGEN32E:
return R_X86_64_PC32;
case EM_AARCH64:
return R_AARCH64_PREL32;
case EM_PPC64:
return R_PPC64_REL32;
case EM_RISCV:
return R_RISCV_RELATIVE;
case EM_S390:
return R_390_PC32;
default:
notpossible;
}
}

View file

@ -64,6 +64,7 @@ void elfwriter_commit(struct ElfWriter *, size_t);
void elfwriter_finishsection(struct ElfWriter *);
void elfwriter_appendrela(struct ElfWriter *, uint64_t, struct ElfWriterSymRef,
uint32_t, int64_t);
uint32_t elfwriter_relatype_pc32(const struct ElfWriter *);
uint32_t elfwriter_relatype_abs32(const struct ElfWriter *);
struct ElfWriterSymRef elfwriter_linksym(struct ElfWriter *, const char *, int,
int);
@ -73,7 +74,7 @@ void elfwriter_yoink(struct ElfWriter *, const char *, int);
void elfwriter_setsection(struct ElfWriter *, struct ElfWriterSymRef, uint16_t);
void elfwriter_zip(struct ElfWriter *, const char *, const char *, size_t,
const void *, size_t, uint32_t, struct timespec,
struct timespec, struct timespec, bool, uint64_t, size_t);
struct timespec, struct timespec, bool);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -34,8 +34,7 @@
#include "third_party/zlib/zlib.h"
#include "tool/build/lib/elfwriter.h"
#define ZIP_LOCALFILE_SECTION ".zip.2."
#define ZIP_DIRECTORY_SECTION ".zip.4."
#define ZIP_CFILE_HDR_SIZE (kZipCfileHdrMinSize + 36)
static bool ShouldCompress(const char *name, size_t namesize,
const unsigned char *data, size_t datasize,
@ -103,7 +102,6 @@ static void EmitZipCdirHdr(unsigned char *p, const void *name, size_t namesize,
p = WRITE32LE(p, compsize);
p = WRITE32LE(p, uncompsize);
p = WRITE16LE(p, namesize);
#define CFILE_HDR_SIZE (kZipCfileHdrMinSize + 36)
p = WRITE16LE(p, 36); /* extra size */
/* 32 */
p = WRITE16LE(p, commentsize);
@ -134,8 +132,7 @@ static void EmitZipCdirHdr(unsigned char *p, const void *name, size_t namesize,
void elfwriter_zip(struct ElfWriter *elf, const char *symbol, const char *name,
size_t namesize, const void *data, size_t size,
uint32_t mode, struct timespec mtim, struct timespec atim,
struct timespec ctim, bool nocompress, uint64_t imagebase,
size_t kZipCdirHdrLinkableSizeBootstrap) {
struct timespec ctim, bool nocompress) {
z_stream zs;
uint8_t era;
uint32_t crc;
@ -149,6 +146,7 @@ void elfwriter_zip(struct ElfWriter *elf, const char *symbol, const char *name,
gflags = 0;
iattrs = 0;
compsize = size;
commentsize = 0;
uncompsize = size;
CHECK_LE(uncompsize, UINT32_MAX);
lfilehdrsize = kZipLfileHdrMinSize + namesize;
@ -158,7 +156,6 @@ void elfwriter_zip(struct ElfWriter *elf, const char *symbol, const char *name,
if (S_ISREG(mode) && _istext(data, size)) {
iattrs |= kZipIattrText;
}
commentsize = kZipCdirHdrLinkableSizeBootstrap - (CFILE_HDR_SIZE + namesize);
dosmode = !(mode & 0200) ? kNtFileAttributeReadonly : 0;
method = ShouldCompress(name, namesize, data, size, nocompress)
? kZipCompressionDeflate
@ -166,9 +163,7 @@ void elfwriter_zip(struct ElfWriter *elf, const char *symbol, const char *name,
/* emit embedded file content w/ pkzip local file header */
elfwriter_align(elf, 1, 0);
elfwriter_startsection(elf,
_gc(xasprintf("%s%s", ZIP_LOCALFILE_SECTION, name)),
SHT_PROGBITS, SHF_ALLOC);
elfwriter_startsection(elf, ".zip.file", SHT_PROGBITS, 0);
if (method == kZipCompressionDeflate) {
CHECK_EQ(Z_OK, deflateInit2(memset(&zs, 0, sizeof(zs)),
Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
@ -205,18 +200,16 @@ void elfwriter_zip(struct ElfWriter *elf, const char *symbol, const char *name,
/* emit central directory record */
elfwriter_align(elf, 1, 0);
elfwriter_startsection(elf,
_gc(xasprintf("%s%s", ZIP_DIRECTORY_SECTION, name)),
SHT_PROGBITS, SHF_ALLOC);
elfwriter_startsection(elf, ".zip.cdir", SHT_PROGBITS, 0);
EmitZipCdirHdr(
(cfile = elfwriter_reserve(elf, kZipCdirHdrLinkableSizeBootstrap)), name,
(cfile = elfwriter_reserve(elf, ZIP_CFILE_HDR_SIZE + namesize)), name,
namesize, crc, era, gflags, method, mtime, mdate, iattrs, dosmode, mode,
compsize, uncompsize, commentsize, mtim, atim, ctim);
elfwriter_appendsym(elf, _gc(xasprintf("%s%s", "zip+cdir:", name)),
ELF64_ST_INFO(STB_LOCAL, STT_OBJECT), STV_DEFAULT, 0,
kZipCdirHdrLinkableSizeBootstrap);
ZIP_CFILE_HDR_SIZE + namesize);
elfwriter_appendrela(elf, kZipCfileOffsetOffset, lfilesym,
elfwriter_relatype_abs32(elf), -imagebase);
elfwriter_commit(elf, kZipCdirHdrLinkableSizeBootstrap);
elfwriter_relatype_pc32(elf), 0);
elfwriter_commit(elf, ZIP_CFILE_HDR_SIZE + namesize);
elfwriter_finishsection(elf);
}

View file

@ -21,6 +21,7 @@
#include "libc/mem/mem.h"
#include "libc/nexgen32e/crc32.h"
#include "libc/runtime/runtime.h"
#include "libc/stdckdint.h"
#include "libc/str/str.h"
#include "libc/x/x.h"
@ -119,14 +120,14 @@ size_t internobj(struct Interner *t, const void *data, size_t size) {
} while (it->p[i].hash);
}
off = it->pool.i;
if (__builtin_add_overflow(off, size, &need)) abort();
if (__builtin_add_overflow(need, 1, &need)) abort();
if (ckd_add(&need, off, size)) abort();
if (ckd_add(&need, need, 1)) abort();
if (need > it->pool.n) {
if (__builtin_add_overflow(it->pool.n, 1, &n2)) abort();
if (ckd_add(&n2, it->pool.n, 1)) abort();
do {
if (__builtin_add_overflow(n2, n2 >> 1, &n2)) abort();
if (ckd_add(&n2, n2, n2 >> 1)) abort();
} while (need > n2);
if (__builtin_mul_overflow(n2, sizeof(*it->pool.p), &bytes)) abort();
if (ckd_mul(&bytes, n2, sizeof(*it->pool.p))) abort();
if (!(p2 = realloc(it->pool.p, bytes))) abort();
it->pool.p = p2;
it->pool.n = n2;

View file

@ -48,6 +48,7 @@
#include "libc/sock/select.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/sockaddr.h"
#include "libc/stdckdint.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/at.h"
@ -177,7 +178,7 @@ static int AppendIovsGuest(struct Machine *m, struct Iovs *iv, int64_t iovaddr,
int rc;
size_t i, iovsize;
struct iovec *guestiovs;
if (!__builtin_mul_overflow(iovlen, sizeof(struct iovec), &iovsize) &&
if (!ckd_mul(&iovsize, iovlen, sizeof(struct iovec)) &&
(0 <= iovsize && iovsize <= 0x7ffff000)) {
if ((guestiovs = malloc(iovsize))) {
VirtualSendRead(m, guestiovs, iovaddr, iovsize);
@ -1136,7 +1137,7 @@ static int OpPoll(struct Machine *m, int64_t fdsaddr, uint64_t nfds,
struct pollfd_bits *gfds;
int64_t wait, elapsed, timeout;
timeout = timeout_ms * 1000L;
if (!__builtin_mul_overflow(nfds, sizeof(struct pollfd_bits), &gfdssize) &&
if (!ckd_mul(&gfdssize, nfds, sizeof(struct pollfd_bits)) &&
gfdssize <= 0x7ffff000) {
if ((gfds = malloc(gfdssize))) {
rc = 0;

View file

@ -164,6 +164,11 @@ nullterminated() static void Print(int fd, const char *s, ...) {
va_end(va);
}
static wontreturn void Die(const char *path, const char *reason) {
Print(2, path, ": ", reason, "\n", NULL);
exit(1);
}
static wontreturn void SysExit(const char *path, const char *func) {
const char *errstr;
if (!(errstr = _strerrno(errno))) errstr = "EUNKNOWN";
@ -244,12 +249,10 @@ static struct Package *LoadPackage(const char *path) {
}
close(fd);
if (pkg->magic != PACKAGE_MAGIC) {
Print(2, path, ": not a cosmo .pkg file\n", NULL);
exit(1);
Die(path, "not a cosmo .pkg file");
}
if (pkg->abi < PACKAGE_ABI) {
Print(2, path, ": package has old abi try running make clean\n", NULL);
exit(1);
Die(path, "package has old abi try running make clean");
}
pkg->strings.p = (void *)((uintptr_t)pkg->strings.p + (uintptr_t)pkg);
pkg->objects.p = (void *)((uintptr_t)pkg->objects.p + (uintptr_t)pkg);
@ -317,7 +320,7 @@ static void WritePackage(struct Package *pkg) {
}
static wontreturn void PrintUsage(int fd, int exitcode) {
Print(fd, "\
Print(fd, "\n\
NAME\n\
\n\
Cosmopolitan Monorepo Packager\n\
@ -395,8 +398,10 @@ static void IndexSections(struct Package *pkg, struct Object *obj) {
obj->section_offset = pkg->sections.i;
for (i = 0; i < obj->elf->e_shnum; ++i) {
bzero(&sect, sizeof(sect));
shdr = GetElfSectionHeaderAddress(obj->elf, obj->size, i);
name = GetElfSectionName(obj->elf, obj->size, shdr);
if (!(shdr = GetElfSectionHeaderAddress(obj->elf, obj->size, i)) ||
!(name = GetElfSectionName(obj->elf, obj->size, shdr))) {
Die("error", "elf overflow");
}
if (shdr->sh_type == SHT_NULL) {
sect.kind = kUndef;
} else if (shdr->sh_type == SHT_NOBITS) {
@ -441,7 +446,10 @@ static void LoadSymbols(struct Package *pkg, uint32_t object) {
if (symbol.bind_ != STB_LOCAL &&
(symbol.type == STT_OBJECT || symbol.type == STT_FUNC ||
symbol.type == STT_COMMON || symbol.type == STT_NOTYPE)) {
name = GetElfString(obj->elf, obj->size, obj->strs, obj->syms[i].st_name);
if (!(name = GetElfString(obj->elf, obj->size, obj->strs,
obj->syms[i].st_name))) {
Die("error", "elf overflow");
}
if (strcmp(name, "_GLOBAL_OFFSET_TABLE_")) {
symbol.kind =
ClassifySection(pkg, obj, symbol.type, obj->syms[i].st_shndx);
@ -456,9 +464,11 @@ static Elf64_Shdr *FindElfSectionByName(Elf64_Ehdr *elf, size_t esize,
const char *name) {
long i;
Elf64_Shdr *shdr;
const char *secname;
for (i = 0; i < elf->e_shnum; ++i) {
shdr = GetElfSectionHeaderAddress(elf, esize, i);
if (!strcmp(GetElfSectionName(elf, esize, shdr), name)) {
if ((secname = GetElfSectionName(
elf, esize, (shdr = GetElfSectionHeaderAddress(elf, esize, i)))) &&
!strcmp(secname, name)) {
return shdr;
}
}
@ -473,19 +483,25 @@ static void LoadPriviligedRefsToUndefs(struct Package *pkg,
Elf64_Shdr *shdr;
Elf64_Rela *rela, *erela;
if ((shdr = FindElfSectionByName(obj->elf, obj->size, ".rela.privileged"))) {
rela = GetElfSectionAddress(obj->elf, obj->size, shdr);
if (!(rela = GetElfSectionAddress(obj->elf, obj->size, shdr))) {
Die("error", "elf overflow");
}
erela = rela + shdr->sh_size / sizeof(*rela);
for (; rela < erela; ++rela) {
if (!ELF64_R_TYPE(rela->r_info)) continue;
if (!(x = ELF64_R_SYM(rela->r_info))) continue;
if (x > obj->symcount) Die("error", "elf overflow");
if (obj->syms[x].st_shndx) continue; // symbol is defined
if (ELF64_ST_BIND(obj->syms[x].st_info) != STB_WEAK &&
ELF64_ST_BIND(obj->syms[x].st_info) != STB_GLOBAL) {
Print(2, "warning: undefined symbol not global\n", NULL);
continue;
}
r.symbol_name = strdup(
GetElfString(obj->elf, obj->size, obj->strs, obj->syms[x].st_name));
if (!(s = GetElfString(obj->elf, obj->size, obj->strs,
obj->syms[x].st_name))) {
Die("error", "elf overflow");
}
r.symbol_name = strdup(s);
r.object_path = strdup(pkg->strings.p + obj->path);
append(&prtu, &r);
}
@ -508,16 +524,13 @@ static void OpenObject(struct Package *pkg, struct Object *obj, int oid) {
}
close(fd);
if (!IsElf64Binary(obj->elf, obj->size)) {
Print(2, path, ": not an elf64 binary\n", NULL);
exit(1);
Die(path, "not an elf64 binary");
}
if (!(obj->strs = GetElfStringTable(obj->elf, obj->size))) {
Print(2, path, ": missing elf string table\n", NULL);
exit(1);
Die(path, "missing elf string table");
}
if (!(obj->syms = GetElfSymbolTable(obj->elf, obj->size, &obj->symcount))) {
Print(2, path, ": missing elf symbol table\n", NULL);
exit(1);
Die(path, "missing elf symbol table");
}
IndexSections(pkg, obj);
LoadPriviligedRefsToUndefs(pkg, obj);

View file

@ -69,7 +69,7 @@
//
STATIC_YOINK("strerror_wr");
STATIC_YOINK("zip_uri_support");
STATIC_YOINK("zipos");
#define USAGE \
"\

235
tool/build/zipcopy.c Normal file
View file

@ -0,0 +1,235 @@
/*-*- 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 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/dce.h"
#include "libc/errno.h"
#include "libc/fmt/magnumstrs.internal.h"
#include "libc/limits.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/zip.internal.h"
#include "third_party/getopt/getopt.h"
static int infd;
static int outfd;
static ssize_t insize;
static ssize_t outsize;
static const char *inpath;
static const char *outpath;
static unsigned char *inmap;
nullterminated() static void Print(int fd, const char *s, ...) {
va_list va;
char buf[2048];
va_start(va, s);
buf[0] = 0;
do {
strlcat(buf, s, sizeof(buf));
} while ((s = va_arg(va, const char *)));
write(fd, buf, strlen(buf));
va_end(va);
}
static wontreturn void Die(const char *path, const char *reason) {
Print(2, path, ": ", reason, "\n", NULL);
exit(1);
}
static wontreturn void SysExit(const char *path, const char *func) {
const char *errstr;
if (!(errstr = _strerdoc(errno))) errstr = "EUNKNOWN";
Print(2, path, ": ", func, " failed with ", errstr, "\n", NULL);
exit(1);
}
static wontreturn void PrintUsage(int fd, int exitcode) {
Print(fd, "\
NAME\n\
\n\
Cosmopolitan Zip Copier\n\
\n\
SYNOPSIS\n\
\n\
",
program_invocation_name, " [FLAGS] SRC DST\n\
\n\
DESCRIPTION\n\
\n\
This tool copies the zip artifacts, if they exist, to the\n\
end of the destination file. If no zip files exist within\n\
the input file, then this tool performs no operation. The\n\
output file will be created if it doesn't exist, which is\n\
useful for creating new zip archives possibly to clean up\n\
holes between input records. If the destination file does\n\
exist, e.g. an executable, then any existing content will\n\
be preserved, including an existing zip archive. That may\n\
however lead to bloat that's not easy to access.\n\
\n\
FLAGS\n\
\n\
-h show this help\n\
\n\
EXAMPLE\n\
\n\
objcopy -SO binary foo.com.dbg foo.com\n\
zipcopy foo.com.dbg foo.com\n\
\n\
\n\
",
NULL);
exit(exitcode);
}
static void GetOpts(int argc, char *argv[]) {
int opt;
while ((opt = getopt(argc, argv, "h")) != -1) {
switch (opt) {
case 'h':
PrintUsage(1, 0);
default:
PrintUsage(2, 1);
}
}
if (optind + 2 != argc) {
PrintUsage(2, 1);
}
inpath = argv[optind + 0];
outpath = argv[optind + 1];
}
static void CopyZip(void) {
int rela, recs;
unsigned long ldest, cdest, ltotal, ctotal, length;
unsigned char *ineof, *stop, *eocd, *cdir, *lfile, *cfile;
// find zip eocd header
ineof = (unsigned char *)inmap + insize;
eocd = ineof - kZipCdirHdrMinSize;
stop = MAX(eocd - 65536, inmap);
for (;; --eocd) {
if (eocd < stop) return;
if (READ32LE(eocd) == kZipCdirHdrMagic) {
break;
}
}
// validate input
recs = ltotal = ctotal = 0;
cdir = inmap + ZIP_CDIR_OFFSET(eocd);
stop = cdir + ZIP_CDIR_SIZE(eocd);
for (cfile = cdir; cfile < stop; cfile += ZIP_CFILE_HDRSIZE(cfile)) {
if (++recs >= 65536) {
Die(inpath, "too many zip files");
}
if (cfile < inmap || //
cfile + kZipCfileHdrMinSize > ineof || //
cfile + ZIP_CFILE_HDRSIZE(cfile) > ineof) {
Die(inpath, "zip directory overflow");
}
if (READ32LE(cfile) != kZipCfileHdrMagic) {
Die(inpath, "zip directory corrupted");
}
if ((rela = ZIP_CFILE_OFFSET(cfile)) < 0) {
Die(inpath, "zip directory offset negative or zip64");
}
lfile = inmap + rela;
if (lfile < inmap || //
lfile + kZipLfileHdrMinSize > ineof || //
lfile + ZIP_LFILE_SIZE(lfile) > ineof) {
Die(inpath, "zip local file overflow");
}
if (READ32LE(lfile) != kZipLfileHdrMagic) {
Die(inpath, "zip local file corrupted");
}
ctotal += ZIP_CFILE_HDRSIZE(cfile);
ltotal += ZIP_LFILE_SIZE(lfile);
}
if (outsize + ltotal + ctotal + ZIP_CDIR_HDRSIZE(eocd) > INT_MAX) {
Die(outpath, "the time has come to upgrade to zip64");
}
// write output
if ((outfd = open(outpath, O_WRONLY | O_CREAT, 0644)) == -1) {
SysExit(outpath, "open");
}
if ((outsize = lseek(outfd, 0, SEEK_END)) == -1) {
SysExit(outpath, "lseek");
}
ldest = outsize;
cdest = outsize + ltotal;
for (cfile = cdir; cfile < stop; cfile += ZIP_CFILE_HDRSIZE(cfile)) {
lfile = inmap + ZIP_CFILE_OFFSET(cfile);
WRITE32LE(cfile + kZipCfileOffsetOffset, ldest);
// write local file
length = ZIP_LFILE_SIZE(lfile);
if (pwrite(outfd, lfile, length, ldest) != length) {
SysExit(outpath, "lfile pwrite");
}
ldest += length;
// write directory entry
length = ZIP_CFILE_HDRSIZE(cfile);
if (READ32LE(cfile) != kZipCfileHdrMagic) notpossible;
if (pwrite(outfd, cfile, length, cdest) != length) {
SysExit(outpath, "lfile pwrite");
}
cdest += length;
}
if (ldest != outsize + ltotal) __builtin_trap();
if (cdest != outsize + ltotal + ctotal) __builtin_trap();
WRITE32LE(eocd + kZipCdirOffsetOffset, outsize + ltotal);
length = ZIP_CDIR_HDRSIZE(eocd);
if (pwrite(outfd, eocd, length, cdest) != length) {
SysExit(outpath, "eocd pwrite");
}
if (close(outfd)) {
SysExit(outpath, "close");
}
}
int main(int argc, char *argv[]) {
int i, opt;
if (!IsOptimized()) {
ShowCrashReports();
}
GetOpts(argc, argv);
if ((infd = open(inpath, O_RDONLY)) == -1) {
SysExit(inpath, "open");
}
if ((insize = lseek(infd, 0, SEEK_END)) == -1) {
SysExit(inpath, "lseek");
}
if (!insize) {
Die(inpath, "file is empty");
}
if ((inmap = mmap(0, insize, PROT_READ | PROT_WRITE, MAP_PRIVATE, infd, 0)) ==
MAP_FAILED) {
SysExit(inpath, "mmap");
}
CopyZip();
if (munmap(inmap, insize)) {
SysExit(inpath, "munmap");
}
if (close(infd)) {
SysExit(inpath, "close");
}
}

View file

@ -47,25 +47,46 @@ char *symbol_;
char *outpath_;
bool nocompress_;
bool basenamify_;
int64_t image_base_;
int strip_components_;
const char *path_prefix_;
struct timespec timestamp;
size_t kZipCdirHdrLinkableSizeBootstrap;
wontreturn void PrintUsage(int rc) {
kprintf("%s%s%s\n", "Usage: ", program_invocation_name,
" [-n] [-B] [-C INT] [-P PREFIX] [-o FILE] [-s SYMBOL] [-y YOINK] "
"[FILE...]");
kprintf("\n\
NAME\n\
\n\
Cosmpolitan Zip File Compiler\n\
\n\
SYNOPSIS\n\
\n\
%s [FLAGS] FILE...\n\
\n\
DESCRIPTION\n\
\n\
This program may be used to turn arbitrary files into .zip.o files\n\
which can be incrementally linked into binaries, without quadratic\n\
compression complexity.\n\
\n\
FLAGS\n\
\n\
-h show help\n\
-o PATH output path\n\
-0 disable compression\n\
-B basename-ify zip filename\n\
-N ZIPPATH zip filename (defaults to input arg)\n\
-P ZIPPATH prepend path zip filename using join\n\
-C INTEGER strips leading path components from zip filename\n\
-y SYMBOL generate yoink for symbol (default __zip_eocd)\n\
\n\
",
program_invocation_name);
exit(rc);
}
void GetOpts(int *argc, char ***argv) {
int opt;
yoink_ = "__zip_start";
image_base_ = IMAGE_BASE_VIRTUAL;
kZipCdirHdrLinkableSizeBootstrap = kZipCdirHdrLinkableSize;
while ((opt = getopt(*argc, *argv, "?0nhBL:N:C:P:o:s:y:b:")) != -1) {
yoink_ = "__zip_eocd";
while ((opt = getopt(*argc, *argv, "?0nhBN:C:P:o:s:y:")) != -1) {
switch (opt) {
case 'o':
outpath_ = optarg;
@ -90,15 +111,9 @@ void GetOpts(int *argc, char ***argv) {
case 'B':
basenamify_ = true;
break;
case 'b':
image_base_ = strtol(optarg, NULL, 0);
break;
case '0':
nocompress_ = true;
break;
case 'L':
kZipCdirHdrLinkableSizeBootstrap = strtoul(optarg, NULL, 0);
break;
case '?':
case 'h':
PrintUsage(EXIT_SUCCESS);
@ -108,7 +123,12 @@ void GetOpts(int *argc, char ***argv) {
}
*argc -= optind;
*argv += optind;
CHECK_NOTNULL(outpath_);
if (!outpath_) {
kprintf("error: no output path specified\n"
"run %s -h for usage\n",
program_invocation_name);
exit(1);
}
}
void ProcessFile(struct ElfWriter *elf, const char *path) {
@ -143,23 +163,20 @@ void ProcessFile(struct ElfWriter *elf, const char *path) {
}
}
elfwriter_zip(elf, name, name, strlen(name), map, st.st_size, st.st_mode,
timestamp, timestamp, timestamp, nocompress_, image_base_,
kZipCdirHdrLinkableSizeBootstrap);
timestamp, timestamp, timestamp, nocompress_);
if (st.st_size) CHECK_NE(-1, munmap(map, st.st_size));
close(fd);
}
void PullEndOfCentralDirectoryIntoLinkage(struct ElfWriter *elf) {
elfwriter_align(elf, 1, 0);
elfwriter_startsection(elf, ".yoink", SHT_PROGBITS,
SHF_ALLOC | SHF_EXECINSTR);
elfwriter_startsection(elf, ".yoink", SHT_PROGBITS, SHF_EXECINSTR);
elfwriter_yoink(elf, yoink_, STB_GLOBAL);
elfwriter_finishsection(elf);
}
void CheckFilenameKosher(const char *path) {
CHECK_LE(kZipCfileHdrMinSize + strlen(path),
kZipCdirHdrLinkableSizeBootstrap);
CHECK_LE(kZipCfileHdrMinSize + strlen(path), 65535);
CHECK(!_startswith(path, "/"));
CHECK(!strstr(path, ".."));
}

29
tool/decode/word.c Normal file
View file

@ -0,0 +1,29 @@
#include "libc/assert.h"
#include "libc/fmt/conv.h"
#include "libc/stdio/stdio.h"
/**
* Displays bytes as word, e.g.
*
* o//tool/word.com 6e c7 ff ff
* %d = -14482
* %ld = 4294952814
* %#x = 0xffffc76e
* %#lx = 0xffffc76e
*
*/
int main(int argc, char *argv[]) {
long x;
int i, k, b;
for (x = k = 0, i = 1; i < argc; ++i) {
b = strtol(argv[i], 0, 16);
assert(0 <= b && b <= 255);
x |= (unsigned long)b << k;
k += 8;
}
printf("%%d = %d\n"
"%%ld = %ld\n"
"%%#x = %#x\n"
"%%#lx = %#lx\n",
(int)x, x, (int)x, x);
}

View file

@ -16,7 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/zip.internal.h"
#include "libc/calls/calls.h"
#include "libc/calls/struct/stat.h"
#include "libc/fmt/conv.h"
@ -35,6 +34,7 @@
#include "libc/sysv/consts/prot.h"
#include "libc/x/xasprintf.h"
#include "libc/x/xiso8601.h"
#include "libc/zip.internal.h"
#include "tool/decode/lib/asmcodegen.h"
#include "tool/decode/lib/disassemblehex.h"
#include "tool/decode/lib/flagger.h"

View file

@ -203,6 +203,8 @@
"STATIC_YOINK"
"PYTHON_YOINK"
"PYTHON_PROVIDE"
"STATIC_STACK_ADDR"
"STATIC_STACK_SIZE"
"STRINGIFY"))
)

View file

@ -25,7 +25,7 @@
(require 'ld-script)
(require 'make-mode)
(setq cosmo-dbg-mode "asan")
(setq cosmo-dbg-mode "dbg")
(setq c-doc-comment-style 'javadown)
(add-to-list 'auto-mode-alist '("\\.x$" . c-mode)) ;; -aux-info

View file

@ -22,6 +22,7 @@
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/runtime/stack.h"
#include "libc/stdckdint.h"
#include "libc/str/str.h"
#include "libc/str/tab.internal.h"
#include "libc/str/utf16.h"
@ -199,8 +200,7 @@ static struct DecodeJson Parse(struct lua_State *L, const char *p,
for (x = (c - '0') * d; p < e; ++p) {
c = *p & 255;
if (isdigit(c)) {
if (__builtin_mul_overflow(x, 10, &x) ||
__builtin_add_overflow(x, (c - '0') * d, &x)) {
if (ckd_mul(&x, x, 10) || ckd_add(&x, x, (c - '0') * d)) {
goto UseDubble;
}
} else if (c == '.') {

View file

@ -138,7 +138,7 @@
#include "tool/net/sandbox.h"
STATIC_STACK_SIZE(0x40000);
STATIC_YOINK("zip_uri_support");
STATIC_YOINK("zipos");
#if !IsTiny()
#ifdef __x86_64__
STATIC_YOINK("ShowCrashReportsEarly");

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_TOOL_PLINKO_LIB_CONS_H_
#define COSMOPOLITAN_TOOL_PLINKO_LIB_CONS_H_
#include "libc/stdckdint.h"
#include "tool/plinko/lib/error.h"
#include "tool/plinko/lib/plinko.h"
#include "tool/plinko/lib/types.h"
@ -26,7 +27,7 @@ forceinline void Set(int i, dword t) {
forceinline int Alloc(dword t) {
int c = cx;
if (!__builtin_sub_overflow(c, 1, &c)) {
if (!ckd_sub(&c, c, 1)) {
Set(c, t);
return cx = c;
}

View file

@ -17,13 +17,14 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/limits.h"
#include "libc/stdckdint.h"
#include "tool/plinko/lib/histo.h"
long GetLongSum(const long *h, size_t n) {
long t;
size_t i;
for (t = i = 0; i < n; ++i) {
if (__builtin_add_overflow(t, h[i], &t)) {
if (ckd_add(&t, t, h[i])) {
t = LONG_MAX;
break;
}

View file

@ -1,6 +1,7 @@
#ifndef COSMOPOLITAN_TOOL_PLINKO_LIB_STACK_H_
#define COSMOPOLITAN_TOOL_PLINKO_LIB_STACK_H_
#include "libc/log/check.h"
#include "libc/stdckdint.h"
#include "tool/plinko/lib/error.h"
#include "tool/plinko/lib/plinko.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
@ -24,7 +25,7 @@ forceinline dword GetCurrentFrame(void) {
forceinline void Push(int x) {
unsigned short s = sp;
g_stack[s] = MAKE(x, ~cx);
if (!__builtin_add_overflow(s, 1, &s)) {
if (!ckd_add(&s, s, 1)) {
sp = s;
} else {
StackOverflow();

View file

@ -1,5 +1,6 @@
#!/bin/sh
# replacement for c++ command
#
# cosmopolitan c++ compiler
#
# we assume you run the following beforehand
#
@ -19,8 +20,9 @@
# make install
#
COSMO=/opt/cosmo
COSMOS=/opt/cosmos
MODE=${MODE:-$m}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos}
if [ "$1" = "--version" ]; then
cat <<'EOF'
@ -32,15 +34,18 @@ EOF
exit 0
fi
UNDEF="-D__COSMOPOLITAN__"
PLATFORM="-D__COSMOPOLITAN__"
PREDEF="-include libc/integral/normalize.inc"
CXX="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-g++"
OBJCOPY="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-objcopy"
CCFLAGS="-g -fdata-sections -ffunction-sections -fno-pie -mno-tls-direct-seg-refs -mno-red-zone -fportcosmo"
CXXFLAGS="-fno-exceptions -fuse-cxa-atexit -fno-threadsafe-statics"
CPPFLAGS="-DNDEBUG -nostdinc -iquote /opt/cosmo -isystem $COSMOS/include -isystem $COSMO/libc/isystem"
LDFLAGS="-static -no-pie -nostdlib -fuse-ld=bfd -Wl,-melf_x86_64 -Wl,--gc-sections -L$COSMOS/lib -Wl,-T,$COSMO/o/ape/public/ape.lds $COSMO/o/ape/ape-no-modify-self.o $COSMO/o/libc/crt/crt.o"
LDLIBS="$COSMO/o/third_party/libcxx/libcxx.a $COSMO/o/cosmopolitan.a"
LDFLAGS="-static -no-pie -nostdlib -fuse-ld=bfd -Wl,-melf_x86_64 -Wl,--gc-sections -L$COSMOS/lib -Wl,-T,$COSMO/o/$MODE/ape/public/ape.lds $COSMO/o/$MODE/ape/ape-no-modify-self.o $COSMO/o/$MODE/libc/crt/crt.o"
LDLIBS="$COSMO/o/$MODE/third_party/libcxx/libcxx.a $COSMO/o/$MODE/cosmopolitan.a"
CXX="$COSMO/o/$MODE/third_party/gcc/bin/x86_64-linux-musl-g++"
OBJCOPY="$COSMO/o/$MODE/third_party/gcc/bin/x86_64-linux-musl-objcopy"
FIXUPOBJ="$COSMO/o/$MODE/tool/build/fixupobj.com"
ZIPCOPY="$COSMO/o/$MODE/tool/build/zipcopy.com"
if [ ! -d "$COSMO" ]; then
echo "you need to checkout cosmopolitan to your $COSMO directory" >&2
@ -61,11 +66,9 @@ if [ ! -d "$COSMOS/lib" ]; then
fi
OPT=
HAS_C=0
HAS_O=0
HAS_E=0
FIRST=1
OUTPUT=
INTENT=ld
NEED_OUTPUT=
FRAME=-fno-omit-frame-pointer
for x; do
@ -84,14 +87,12 @@ for x; do
elif [ x"$x" != x"${x#-O}" ]; then
OPT=$x
elif [ x"$x" = x"-c" ]; then
HAS_C=1
INTENT=cc
elif [ x"$x" = x"-E" ]; then
HAS_E=1
INTENT=cpp
elif [ x"$x" = x"-o" ]; then
HAS_O=1
NEED_OUTPUT=1
elif [ x"$x" != x"${x#-o}" ]; then
HAS_O=1
OUTPUT=${x#-o}
elif [ -n "$NEED_OUTPUT" ]; then
NEED_OUTPUT=
@ -110,26 +111,26 @@ for x; do
set -- "$@" "$x"
done
if [ x"$OPT" != x"-Os" ]; then
if [ x"$OPT" != x"-Os" ] && [ x"$MODE" != x"tiny" ]; then
# support --ftrace unless optimizing for size
CXXFLAGS="$CXXFLAGS -fpatchable-function-entry=18,16"
fi
LINKING=
if [ "$HAS_E" = "1" ]; then
set -- $UNDEF $CCFLAGS $CPPFLAGS "$@"
elif [ "$HAS_C" = "1" ]; then
set -- $UNDEF $PREDEF $CCFLAGS $CXXFLAGS $CPPFLAGS "$@" $FRAME
if [ $INTENT = cpp ]; then
set -- $PLATFORM $CCFLAGS $CPPFLAGS "$@"
elif [ $INTENT = cc ]; then
set -- $PLATFORM $PREDEF $CCFLAGS $CXXFLAGS $CPPFLAGS "$@" $FRAME
else
LINKING=1
set -- $UNDEF $PREDEF $LDFLAGS $CXXFLAGS $CPPFLAGS "$@" $LDLIBS -Wl,-z,common-page-size=65536 -Wl,-z,max-page-size=65536 $FRAME
set -- $PLATFORM $PREDEF $LDFLAGS $CXXFLAGS $CPPFLAGS "$@" $LDLIBS -Wl,-z,common-page-size=65536 -Wl,-z,max-page-size=65536 $FRAME
fi
set -- "$CXX" "$@"
printf '(cd %s; %s)\n' "$PWD" "$*" >>/tmp/build.log
"$@" || exit
if [ -n "$LINKING" ] && [ x"$OUTPUT" != x"" ]; then
if [ $INTENT = cc ] && [ -n "$OUTPUT" ]; then
"$FIXUPOBJ" "$OUTPUT" || exit
elif [ $INTENT = ld ] && [ -n "$OUTPUT" ]; then
if [ x"$OUTPUT" != x"${OUTPUT%.com}" ] ||
[ x"$OUTPUT" != x"${OUTPUT%.exe}" ]; then
# cosmocc -o foo.com ...
@ -137,6 +138,7 @@ if [ -n "$LINKING" ] && [ x"$OUTPUT" != x"" ]; then
# -> foo.com.dbg (elf)
mv -f "$OUTPUT" "$OUTPUT.dbg" || exit
"$OBJCOPY" -S -O binary "$OUTPUT.dbg" "$OUTPUT" || exit
"$ZIPCOPY" "$OUTPUT.dbg" "$OUTPUT" || exit
else
# cosmocc -o foo ...
# -> foo (elf)
@ -144,5 +146,6 @@ if [ -n "$LINKING" ] && [ x"$OUTPUT" != x"" ]; then
# -> foo.com.dbg (elf)
cp -f "$OUTPUT" "$OUTPUT.com.dbg" || exit
"$OBJCOPY" -S -O binary "$OUTPUT" "$OUTPUT.com" || exit
"$ZIPCOPY" "$OUTPUT" "$OUTPUT.com" || exit
fi
fi

View file

@ -1,5 +1,6 @@
#!/bin/sh
# replacement for cc command
#
# cosmopolitan c compiler
#
# we assume you run the following beforehand
#
@ -19,8 +20,9 @@
# make install
#
COSMO=/opt/cosmo
COSMOS=/opt/cosmos
MODE=${MODE:-$m}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos}
if [ "$1" = "--version" ]; then
cat <<'EOF'
@ -32,15 +34,18 @@ EOF
exit 0
fi
UNDEF="-D__COSMOPOLITAN__"
PLATFORM="-D__COSMOPOLITAN__"
PREDEF="-include libc/integral/normalize.inc"
CC="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-gcc"
OBJCOPY="$COSMO/o/third_party/gcc/bin/x86_64-linux-musl-objcopy"
CCFLAGS="-g -fdata-sections -ffunction-sections -fno-pie -mno-tls-direct-seg-refs -mno-red-zone -fportcosmo"
CFLAGS=
CPPFLAGS="-DNDEBUG -nostdinc -iquote /opt/cosmo -isystem $COSMOS/include -isystem $COSMO/libc/isystem"
LDFLAGS="-static -no-pie -nostdlib -fuse-ld=bfd -Wl,-melf_x86_64 -Wl,--gc-sections -L$COSMOS/lib -Wl,-T,$COSMO/o/ape/public/ape.lds $COSMO/o/ape/ape-no-modify-self.o $COSMO/o/libc/crt/crt.o"
LDLIBS="$COSMO/o/cosmopolitan.a"
LDFLAGS="-static -no-pie -nostdlib -fuse-ld=bfd -Wl,-melf_x86_64 -Wl,--gc-sections -L$COSMOS/lib -Wl,-T,$COSMO/o/$MODE/ape/public/ape.lds $COSMO/o/$MODE/ape/ape-no-modify-self.o $COSMO/o/$MODE/libc/crt/crt.o"
LDLIBS="$COSMO/o/$MODE/cosmopolitan.a"
CC="$COSMO/o/$MODE/third_party/gcc/bin/x86_64-linux-musl-gcc"
OBJCOPY="$COSMO/o/$MODE/third_party/gcc/bin/x86_64-linux-musl-objcopy"
FIXUPOBJ="$COSMO/o/$MODE/tool/build/fixupobj.com"
ZIPCOPY="$COSMO/o/$MODE/tool/build/zipcopy.com"
if [ ! -d "$COSMO" ]; then
echo "you need to checkout cosmopolitan to your $COSMO directory" >&2
@ -61,11 +66,9 @@ if [ ! -d "$COSMOS/lib" ]; then
fi
OPT=
HAS_C=0
HAS_O=0
HAS_E=0
FIRST=1
OUTPUT=
INTENT=ld
NEED_OUTPUT=
FRAME=-fno-omit-frame-pointer
for x; do
@ -84,14 +87,12 @@ for x; do
elif [ x"$x" != x"${x#-O}" ]; then
OPT=$x
elif [ x"$x" = x"-c" ]; then
HAS_C=1
INTENT=cc
elif [ x"$x" = x"-E" ]; then
HAS_E=1
INTENT=cpp
elif [ x"$x" = x"-o" ]; then
HAS_O=1
NEED_OUTPUT=1
elif [ x"$x" != x"${x#-o}" ]; then
HAS_O=1
OUTPUT=${x#-o}
elif [ -n "$NEED_OUTPUT" ]; then
NEED_OUTPUT=
@ -110,26 +111,26 @@ for x; do
set -- "$@" "$x"
done
if [ x"$OPT" != x"-Os" ]; then
if [ x"$OPT" != x"-Os" ] && [ x"$MODE" != x"tiny" ]; then
# support --ftrace unless optimizing for size
CFLAGS="$CFLAGS -fpatchable-function-entry=18,16"
fi
LINKING=
if [ "$HAS_E" = "1" ]; then
set -- $UNDEF $CCFLAGS $CPPFLAGS "$@"
elif [ "$HAS_C" = "1" ]; then
set -- $UNDEF $PREDEF $CCFLAGS $CFLAGS $CPPFLAGS "$@" $FRAME
if [ $INTENT = cpp ]; then
set -- $PLATFORM $CCFLAGS $CPPFLAGS "$@"
elif [ $INTENT = cc ]; then
set -- $PLATFORM $PREDEF $CCFLAGS $CFLAGS $CPPFLAGS "$@" $FRAME
else
LINKING=1
set -- $UNDEF $PREDEF $LDFLAGS $CFLAGS $CPPFLAGS "$@" $LDLIBS -Wl,-z,common-page-size=65536 -Wl,-z,max-page-size=65536 $FRAME
set -- $PLATFORM $PREDEF $LDFLAGS $CFLAGS $CPPFLAGS "$@" $LDLIBS -Wl,-z,common-page-size=65536 -Wl,-z,max-page-size=65536 $FRAME
fi
set -- "$CC" "$@"
printf '(cd %s; %s)\n' "$PWD" "$*" >>/tmp/build.log
"$@" || exit
if [ -n "$LINKING" ] && [ x"$OUTPUT" != x"" ]; then
if [ $INTENT = cc ] && [ -n "$OUTPUT" ]; then
"$FIXUPOBJ" "$OUTPUT" || exit
elif [ $INTENT = ld ] && [ -n "$OUTPUT" ]; then
if [ x"$OUTPUT" != x"${OUTPUT%.com}" ] ||
[ x"$OUTPUT" != x"${OUTPUT%.exe}" ]; then
# cosmocc -o foo.com ...
@ -137,6 +138,7 @@ if [ -n "$LINKING" ] && [ x"$OUTPUT" != x"" ]; then
# -> foo.com.dbg (elf)
mv -f "$OUTPUT" "$OUTPUT.dbg" || exit
"$OBJCOPY" -S -O binary "$OUTPUT.dbg" "$OUTPUT" || exit
"$ZIPCOPY" "$OUTPUT.dbg" "$OUTPUT" || exit
else
# cosmocc -o foo ...
# -> foo (elf)
@ -144,5 +146,6 @@ if [ -n "$LINKING" ] && [ x"$OUTPUT" != x"" ]; then
# -> foo.com.dbg (elf)
cp -f "$OUTPUT" "$OUTPUT.com.dbg" || exit
"$OBJCOPY" -S -O binary "$OUTPUT" "$OUTPUT.com" || exit
"$ZIPCOPY" "$OUTPUT" "$OUTPUT.com" || exit
fi
fi