mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-12 05:59:10 +00:00
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:
parent
f6407d5f7c
commit
8ff48201ca
125 changed files with 1056 additions and 928 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(§, 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);
|
||||
|
|
|
@ -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
235
tool/build/zipcopy.c
Normal 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");
|
||||
}
|
||||
}
|
|
@ -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
29
tool/decode/word.c
Normal 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);
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -203,6 +203,8 @@
|
|||
"STATIC_YOINK"
|
||||
"PYTHON_YOINK"
|
||||
"PYTHON_PROVIDE"
|
||||
"STATIC_STACK_ADDR"
|
||||
"STATIC_STACK_SIZE"
|
||||
"STRINGIFY"))
|
||||
|
||||
)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 == '.') {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue