mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
Introduce Python objectifier (#259)
This commit is contained in:
parent
34b68f1945
commit
81287b7ec0
13 changed files with 1702 additions and 1564 deletions
2
Makefile
2
Makefile
|
@ -143,8 +143,8 @@ include third_party/mbedtls/test/test.mk
|
|||
include third_party/quickjs/quickjs.mk
|
||||
include third_party/lz4cli/lz4cli.mk
|
||||
include third_party/infozip/infozip.mk
|
||||
include third_party/python/python.mk
|
||||
include tool/build/lib/buildlib.mk
|
||||
include third_party/python/python.mk
|
||||
include third_party/chibicc/chibicc.mk
|
||||
include third_party/chibicc/test/test.mk
|
||||
include tool/build/emucrt/emucrt.mk
|
||||
|
|
|
@ -173,6 +173,9 @@ DEFAULT_LDFLAGS = \
|
|||
ZIPOBJ_FLAGS = \
|
||||
-b$(IMAGE_BASE_VIRTUAL)
|
||||
|
||||
PYFLAGS = \
|
||||
-b$(IMAGE_BASE_VIRTUAL)
|
||||
|
||||
ASONLYFLAGS = \
|
||||
-c \
|
||||
-g \
|
||||
|
|
|
@ -80,8 +80,11 @@ o/$(MODE)/%-gcc.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S
|
|||
o/$(MODE)/%-clang.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $< || echo / need $(CLANG) >$@
|
||||
o/$(MODE)/%-clang.asm: CC = $(CLANG)
|
||||
|
||||
o/$(MODE)/%.o: %.py o/$(MODE)/third_party/python/pyobj
|
||||
@$(COMPILE) -APYOBJ o/$(MODE)/third_party/python/pyobj $(PYFLAGS) -o $@ $<
|
||||
|
||||
o/$(MODE)/%.pyc: %.py o/$(MODE)/third_party/python/pycomp
|
||||
@$(COMPILE) -APYCOMP o/$(MODE)/third_party/python/pycomp $(PYFLAGS) -o $@ $<
|
||||
@$(COMPILE) -APYCOMP o/$(MODE)/third_party/python/pycomp $(PYCFLAGS) -o $@ $<
|
||||
|
||||
o/$(MODE)/%.lua: %.lua o/$(MODE)/third_party/lua/luac
|
||||
@$(COMPILE) -ALUAC -T$@ o/$(MODE)/third_party/lua/luac.com -s -o $@ $<
|
||||
@$(COMPILE) -ALUAC -T$@ o/$(MODE)/third_party/lua/luac -s -o $@ $<
|
||||
|
|
10
third_party/python/Include/yoink.h
vendored
10
third_party/python/Include/yoink.h
vendored
|
@ -2,17 +2,9 @@
|
|||
#define COSMOPOLITAN_THIRD_PARTY_PYTHON_INCLUDE_YOINK_H_
|
||||
#include "libc/dce.h"
|
||||
|
||||
#if !IsTiny()
|
||||
#define PYTHON_YOINK(s) \
|
||||
__asm__(".section .yoink\n\t" \
|
||||
"nopl\t\"" s "\"\n\t" \
|
||||
"nopl\t\"" s "c\"\n\t" \
|
||||
"nopl\t\"py:" s "\"\n\t" \
|
||||
".previous")
|
||||
#else
|
||||
#define PYTHON_YOINK(s) \
|
||||
__asm__(".section .yoink\n\t" \
|
||||
"nopl\t\"" s "c\"\n\t" \
|
||||
".previous")
|
||||
#endif
|
||||
|
||||
#endif /* COSMOPOLITAN_THIRD_PARTY_PYTHON_INCLUDE_YOINK_H_ */
|
||||
|
|
1139
third_party/python/Programs/python.c
vendored
1139
third_party/python/Programs/python.c
vendored
File diff suppressed because it is too large
Load diff
1271
third_party/python/Programs/pythontester.c
vendored
1271
third_party/python/Programs/pythontester.c
vendored
File diff suppressed because it is too large
Load diff
16
third_party/python/pycomp.c
vendored
16
third_party/python/pycomp.c
vendored
|
@ -38,6 +38,7 @@
|
|||
#include "third_party/python/Include/pylifecycle.h"
|
||||
#include "third_party/python/Include/pymacro.h"
|
||||
#include "third_party/python/Include/pythonrun.h"
|
||||
#include "tool/build/lib/stripcomponents.h"
|
||||
/* clang-format off */
|
||||
|
||||
#define MANUAL "\
|
||||
|
@ -67,21 +68,6 @@ int optimize;
|
|||
char *inpath;
|
||||
char *outpath;
|
||||
|
||||
char *
|
||||
StripComponents(const char *path, int n)
|
||||
{
|
||||
const char *p;
|
||||
while (n-- > 0) {
|
||||
for (p = path; *p; ++p) {
|
||||
if (*p == '/') {
|
||||
path = p + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (char *)path;
|
||||
}
|
||||
|
||||
void
|
||||
GetOpts(int argc, char *argv[])
|
||||
{
|
||||
|
|
251
third_party/python/pyobj.c
vendored
Normal file
251
third_party/python/pyobj.c
vendored
Normal file
|
@ -0,0 +1,251 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=4 sts=4 sw=4 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2021 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/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/python/Include/bytesobject.h"
|
||||
#include "third_party/python/Include/compile.h"
|
||||
#include "third_party/python/Include/fileutils.h"
|
||||
#include "third_party/python/Include/import.h"
|
||||
#include "third_party/python/Include/marshal.h"
|
||||
#include "third_party/python/Include/pydebug.h"
|
||||
#include "third_party/python/Include/pylifecycle.h"
|
||||
#include "third_party/python/Include/pymacro.h"
|
||||
#include "third_party/python/Include/pythonrun.h"
|
||||
#include "tool/build/lib/elfwriter.h"
|
||||
#include "tool/build/lib/stripcomponents.h"
|
||||
/* clang-format off */
|
||||
|
||||
#define MANUAL "\
|
||||
SYNOPSIS\n\
|
||||
\n\
|
||||
pyobj.com [FLAGS] SOURCE\n\
|
||||
\n\
|
||||
OVERVIEW\n\
|
||||
\n\
|
||||
Python Objectifier\n\
|
||||
\n\
|
||||
FLAGS\n\
|
||||
\n\
|
||||
-o PATH output elf object file\n\
|
||||
-P STR prefix fake directory in zip\n\
|
||||
-C INT strip directory components from src in zip\n\
|
||||
-O0 don't optimize [default]\n\
|
||||
-O1 remove debug statements\n\
|
||||
-O2 remove debug statements and docstrings\n\
|
||||
-b binary only (don't include .py file)\n\
|
||||
-0 zip uncompressed\n\
|
||||
-n do nothing\n\
|
||||
-h help\n\
|
||||
\n"
|
||||
|
||||
bool binonly;
|
||||
int optimize;
|
||||
char *pyfile;
|
||||
char *outpath;
|
||||
bool nocompress;
|
||||
uint64_t image_base;
|
||||
int strip_components;
|
||||
const char *path_prefix;
|
||||
|
||||
static void
|
||||
GetOpts(int argc, char *argv[])
|
||||
{
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "hn0Bb:O:o:C:P:")) != -1) {
|
||||
switch (opt) {
|
||||
case 'O':
|
||||
optimize = atoi(optarg);
|
||||
break;
|
||||
case 'o':
|
||||
outpath = optarg;
|
||||
break;
|
||||
case 'P':
|
||||
path_prefix = optarg;
|
||||
break;
|
||||
case 'C':
|
||||
strip_components = atoi(optarg);
|
||||
break;
|
||||
case 'b':
|
||||
image_base = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'B':
|
||||
binonly = true;
|
||||
break;
|
||||
case '0':
|
||||
nocompress = true;
|
||||
break;
|
||||
case 'n':
|
||||
exit(0);
|
||||
case 'h':
|
||||
fputs(MANUAL, stdout);
|
||||
exit(0);
|
||||
default:
|
||||
fputs(MANUAL, stderr);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (argc - optind != 1) {
|
||||
fputs("error: need one input file\n", stderr);
|
||||
exit(1);
|
||||
}
|
||||
pyfile = argv[optind];
|
||||
if (!outpath) {
|
||||
outpath = xstrcat(pyfile, ".o");
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
Dotify(char *s)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; s[i]; ++i) {
|
||||
if (s[i] == '/') {
|
||||
s[i] = '.';
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static void
|
||||
Yoink(struct ElfWriter *elf, const char *symbol)
|
||||
{
|
||||
elfwriter_align(elf, 1, 0);
|
||||
elfwriter_startsection(elf, ".yoink", SHT_PROGBITS,
|
||||
SHF_ALLOC | SHF_EXECINSTR);
|
||||
elfwriter_yoink(elf, symbol);
|
||||
elfwriter_finishsection(elf);
|
||||
}
|
||||
|
||||
static char *
|
||||
GetZipFile(void)
|
||||
{
|
||||
const char *zipfile;
|
||||
zipfile = pyfile;
|
||||
zipfile = StripComponents(zipfile, strip_components);
|
||||
if (path_prefix) {
|
||||
zipfile = gc(xjoinpaths(path_prefix, zipfile));
|
||||
}
|
||||
return strdup(zipfile);
|
||||
}
|
||||
|
||||
static char *
|
||||
GetZipDir(void)
|
||||
{
|
||||
return xstrcat(gc(xdirname(gc(GetZipFile()))), '/');
|
||||
}
|
||||
|
||||
static char *
|
||||
GetSynFile(void)
|
||||
{
|
||||
return xstrcat("/zip/", gc(GetZipFile()));
|
||||
}
|
||||
|
||||
static char *
|
||||
GetModName(bool *ispkg)
|
||||
{
|
||||
char *mod;
|
||||
mod = Dotify(xstripexts(StripComponents(pyfile, strip_components)));
|
||||
if ((*ispkg = endswith(mod, ".__init__"))) {
|
||||
mod[strlen(mod) - strlen(".__init__")] = 0;
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
char t[12];
|
||||
bool ispkg;
|
||||
ssize_t rc;
|
||||
struct stat st;
|
||||
struct ElfWriter *elf;
|
||||
struct timespec timestamp;
|
||||
PyObject *code, *marshalled;
|
||||
size_t i, pysize, pycsize, marsize;
|
||||
char *s, *pydata, *pycdata, *mardata, *zipfile, *zipdir, *synfile, *modname;
|
||||
ShowCrashReports();
|
||||
GetOpts(argc, argv);
|
||||
marshalled = 0;
|
||||
if (stat(pyfile, &st) == -1) perror(pyfile), exit(1);
|
||||
CHECK_NOTNULL((pydata = gc(xslurp(pyfile, &pysize))));
|
||||
Py_NoUserSiteDirectory++;
|
||||
Py_NoSiteFlag++;
|
||||
Py_IgnoreEnvironmentFlag++;
|
||||
Py_FrozenFlag++;
|
||||
Py_SetProgramName(gc(utf8toutf32(argv[0], -1, 0)));
|
||||
_Py_InitializeEx_Private(1, 0);
|
||||
zipdir = gc(GetZipDir());
|
||||
zipfile = gc(GetZipFile());
|
||||
synfile = gc(GetSynFile());
|
||||
modname = gc(GetModName(&ispkg));
|
||||
code = Py_CompileStringExFlags(pydata, synfile, Py_file_input, NULL, optimize);
|
||||
if (!code) goto error;
|
||||
marshalled = PyMarshal_WriteObjectToString(code, Py_MARSHAL_VERSION);
|
||||
Py_CLEAR(code);
|
||||
if (!marshalled) goto error;
|
||||
memset(×tamp, 0, sizeof(timestamp));
|
||||
assert(PyBytes_CheckExact(marshalled));
|
||||
mardata = PyBytes_AS_STRING(marshalled);
|
||||
marsize = PyBytes_GET_SIZE(marshalled);
|
||||
elf = elfwriter_open(outpath, 0644);
|
||||
elfwriter_cargoculting(elf);
|
||||
WRITE16LE(t+0, 3379); /* Python 3.6rc1 */
|
||||
WRITE16LE(t+2, READ16LE("\r\n"));
|
||||
WRITE32LE(t+4, timestamp.tv_sec);
|
||||
WRITE32LE(t+8, marsize);
|
||||
pycsize = sizeof(t) + marsize;
|
||||
pycdata = gc(malloc(pycsize));
|
||||
memcpy(pycdata, t, sizeof(t));
|
||||
memcpy(pycdata + sizeof(t), mardata, marsize);
|
||||
if (ispkg) {
|
||||
elfwriter_zip(elf, zipdir, zipdir, strlen(zipdir),
|
||||
pydata, pysize, 040755, timestamp, timestamp,
|
||||
timestamp, nocompress, image_base);
|
||||
}
|
||||
if (!binonly) {
|
||||
elfwriter_zip(elf, gc(xstrcat("py:", modname)), zipfile,
|
||||
strlen(zipfile), pydata, pysize, st.st_mode, timestamp,
|
||||
timestamp, timestamp, nocompress, image_base);
|
||||
}
|
||||
elfwriter_zip(elf, gc(xstrcat("pyc:", modname)), gc(xstrcat(zipfile, 'c')),
|
||||
strlen(zipfile) + 1, pycdata, pycsize, st.st_mode, timestamp,
|
||||
timestamp, timestamp, nocompress, image_base);
|
||||
Yoink(elf, "__zip_start");
|
||||
elfwriter_close(elf);
|
||||
Py_CLEAR(marshalled);
|
||||
Py_Finalize();
|
||||
return 0;
|
||||
error:
|
||||
PyErr_Print();
|
||||
Py_Finalize();
|
||||
if (marshalled) Py_DECREF(marshalled);
|
||||
return 1;
|
||||
}
|
125
third_party/python/python.mk
vendored
125
third_party/python/python.mk
vendored
|
@ -11,8 +11,6 @@ THIRD_PARTY_PYTHON_STAGE2 = \
|
|||
$(THIRD_PARTY_PYTHON_STAGE2_A_DEPS) \
|
||||
$(THIRD_PARTY_PYTHON_STAGE2_A) \
|
||||
$(THIRD_PARTY_PYTHON_STDLIB_PYS_A) \
|
||||
$(THIRD_PARTY_PYTHON_STDLIB_PYCS_A) \
|
||||
$(THIRD_PARTY_PYTHON_STDLIB_DIRS_A) \
|
||||
$(THIRD_PARTY_PYTHON_STDLIB_DATA_A)
|
||||
|
||||
THIRD_PARTY_PYTHON_ARTIFACTS = \
|
||||
|
@ -26,6 +24,7 @@ THIRD_PARTY_PYTHON_BINS = \
|
|||
THIRD_PARTY_PYTHON_COMS = \
|
||||
o/$(MODE)/third_party/python/python.com \
|
||||
o/$(MODE)/third_party/python/freeze.com \
|
||||
o/$(MODE)/third_party/python/pyobj.com \
|
||||
o/$(MODE)/third_party/python/pycomp.com \
|
||||
o/$(MODE)/third_party/python/pythontester.com
|
||||
|
||||
|
@ -37,17 +36,12 @@ THIRD_PARTY_PYTHON_CHECKS = \
|
|||
THIRD_PARTY_PYTHON_STAGE1_A = o/$(MODE)/third_party/python/python-stage1.a
|
||||
THIRD_PARTY_PYTHON_STAGE2_A = o/$(MODE)/third_party/python/python-stage2.a
|
||||
THIRD_PARTY_PYTHON_STDLIB_PYS_A = o/$(MODE)/third_party/python/python-stdlib-pys.a
|
||||
THIRD_PARTY_PYTHON_STDLIB_PYCS_A = o/$(MODE)/third_party/python/python-stdlib-pycs.a
|
||||
THIRD_PARTY_PYTHON_STDLIB_DIRS_A = o/$(MODE)/third_party/python/python-stdlib-dirs.a
|
||||
THIRD_PARTY_PYTHON_STDLIB_DATA_A = o/$(MODE)/third_party/python/python-stdlib-data.a
|
||||
|
||||
THIRD_PARTY_PYTHON_STAGE1_A_OBJS = $(THIRD_PARTY_PYTHON_STAGE1_A_SRCS:%.c=o/$(MODE)/%.o)
|
||||
THIRD_PARTY_PYTHON_STAGE2_A_OBJS = $(THIRD_PARTY_PYTHON_STAGE2_A_SRCS:%.c=o/$(MODE)/%.o)
|
||||
THIRD_PARTY_PYTHON_STDLIB_PYS_OBJS = $(THIRD_PARTY_PYTHON_STDLIB_PYS:%=o/$(MODE)/%.zip.o)
|
||||
THIRD_PARTY_PYTHON_STDLIB_PYCS_OBJS = $(THIRD_PARTY_PYTHON_STDLIB_PYCS:%=%.zip.o)
|
||||
THIRD_PARTY_PYTHON_STDLIB_DIRS_OBJS = $(THIRD_PARTY_PYTHON_STDLIB_DIRS:%=o/$(MODE)/%.zip.o)
|
||||
THIRD_PARTY_PYTHON_STDLIB_PYS_OBJS = $(THIRD_PARTY_PYTHON_STDLIB_PYS:%.py=o/$(MODE)/%.o)
|
||||
THIRD_PARTY_PYTHON_STDLIB_DATA_OBJS = $(THIRD_PARTY_PYTHON_STDLIB_DATA:%=o/$(MODE)/%.zip.o)
|
||||
THIRD_PARTY_PYTHON_STDLIB_PYCS = $(THIRD_PARTY_PYTHON_STDLIB_PYS:%=o/$(MODE)/%c)
|
||||
|
||||
THIRD_PARTY_PYTHON_HDRS = \
|
||||
third_party/python/Include/yoink.h \
|
||||
|
@ -533,98 +527,8 @@ THIRD_PARTY_PYTHON_STAGE2_A_SRCS = \
|
|||
third_party/python/Python/pyfpe.c \
|
||||
third_party/python/Python/sigcheck.c
|
||||
|
||||
THIRD_PARTY_PYTHON_STDLIB_DIRS = \
|
||||
third_party/python/Lib/ \
|
||||
third_party/python/Lib/asyncio/ \
|
||||
third_party/python/Lib/collections/ \
|
||||
third_party/python/Lib/dbm/ \
|
||||
third_party/python/Lib/distutils/ \
|
||||
third_party/python/Lib/distutils/command/ \
|
||||
third_party/python/Lib/distutils/tests/ \
|
||||
third_party/python/Lib/email/ \
|
||||
third_party/python/Lib/email/mime/ \
|
||||
third_party/python/Lib/encodings/ \
|
||||
third_party/python/Lib/ensurepip/ \
|
||||
third_party/python/Lib/ensurepip/_bundled/ \
|
||||
third_party/python/Lib/html/ \
|
||||
third_party/python/Lib/http/ \
|
||||
third_party/python/Lib/importlib/ \
|
||||
third_party/python/Lib/json/ \
|
||||
third_party/python/Lib/logging/ \
|
||||
third_party/python/Lib/msilib/ \
|
||||
third_party/python/Lib/multiprocessing/ \
|
||||
third_party/python/Lib/multiprocessing/dummy/ \
|
||||
third_party/python/Lib/sqlite3/ \
|
||||
third_party/python/Lib/unittest/ \
|
||||
third_party/python/Lib/urllib/ \
|
||||
third_party/python/Lib/venv/ \
|
||||
third_party/python/Lib/venv/scripts/common/ \
|
||||
third_party/python/Lib/venv/scripts/nt/ \
|
||||
third_party/python/Lib/venv/scripts/posix/ \
|
||||
third_party/python/Lib/wsgiref/ \
|
||||
third_party/python/Lib/xml/ \
|
||||
third_party/python/Lib/xml/dom/ \
|
||||
third_party/python/Lib/xml/etree/ \
|
||||
third_party/python/Lib/xml/parsers/ \
|
||||
third_party/python/Lib/xml/sax/ \
|
||||
third_party/python/Lib/xmlrpc/ \
|
||||
third_party/python/Lib/test/ \
|
||||
third_party/python/Lib/test/xmltestdata/ \
|
||||
third_party/python/Lib/test/test_email/ \
|
||||
third_party/python/Lib/test/test_email/data/ \
|
||||
third_party/python/Lib/test/sndhdrdata/ \
|
||||
third_party/python/Lib/test/test_asyncio/ \
|
||||
third_party/python/Lib/test/audiodata/ \
|
||||
third_party/python/Lib/test/imghdrdata/ \
|
||||
third_party/python/Lib/test/decimaltestdata/ \
|
||||
third_party/python/Lib/test/test_import/ \
|
||||
third_party/python/Lib/test/test_import/data/ \
|
||||
third_party/python/Lib/test/test_import/data/package/ \
|
||||
third_party/python/Lib/test/test_import/data/package2/ \
|
||||
third_party/python/Lib/test/test_import/data/circular_imports/ \
|
||||
third_party/python/Lib/test/test_import/data/circular_imports/subpkg/ \
|
||||
third_party/python/Lib/test/libregrtest/ \
|
||||
third_party/python/Lib/test/leakers/ \
|
||||
third_party/python/Lib/test/test_json/ \
|
||||
third_party/python/Lib/test/eintrdata/ \
|
||||
third_party/python/Lib/test/support/ \
|
||||
third_party/python/Lib/test/test_importlib/ \
|
||||
third_party/python/Lib/test/test_importlib/extension/ \
|
||||
third_party/python/Lib/test/test_importlib/frozen/ \
|
||||
third_party/python/Lib/test/test_importlib/import_/ \
|
||||
third_party/python/Lib/test/test_importlib/builtin/ \
|
||||
third_party/python/Lib/test/test_importlib/source/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/project2/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/project2/parent/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/project2/parent/child/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/portion2/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/portion2/foo/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/project3/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/project3/parent/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/project3/parent/child/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/portion1/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/portion1/foo/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/both_portions/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/both_portions/foo/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/project1/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/project1/parent/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/project1/parent/child/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/not_a_namespace_pkg/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/not_a_namespace_pkg/foo/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/module_and_namespace_package/ \
|
||||
third_party/python/Lib/test/test_importlib/namespace_pkgs/module_and_namespace_package/a_test/ \
|
||||
third_party/python/Lib/test/test_warnings/ \
|
||||
third_party/python/Lib/test/test_warnings/data/ \
|
||||
third_party/python/Lib/test/capath/ \
|
||||
third_party/python/Lib/test/dtracedata/ \
|
||||
third_party/python/Lib/test/subprocessdata/ \
|
||||
third_party/python/Lib/test/crashers/ \
|
||||
third_party/python/Lib/test/cjkencodings/ \
|
||||
third_party/python/Lib/test/test_tools/ \
|
||||
third_party/python/Lib/test/tracedmodules/
|
||||
|
||||
THIRD_PARTY_PYTHON_STDLIB_DATA = \
|
||||
third_party/python/Lib/ \
|
||||
third_party/python/Lib/distutils/command/command_template \
|
||||
third_party/python/Lib/distutils/tests/Setup.sample \
|
||||
third_party/python/Lib/email/architecture.rst \
|
||||
|
@ -2181,6 +2085,7 @@ THIRD_PARTY_PYTHON_STAGE1_A_DIRECTDEPS = \
|
|||
LIBC_TINYMATH \
|
||||
LIBC_UNICODE \
|
||||
LIBC_X \
|
||||
TOOL_BUILD_LIB \
|
||||
THIRD_PARTY_GETOPT
|
||||
|
||||
THIRD_PARTY_PYTHON_STAGE1_A_DEPS = \
|
||||
|
@ -2220,6 +2125,14 @@ THIRD_PARTY_PYTHON_STAGE2_A_DIRECTDEPS = \
|
|||
THIRD_PARTY_PYTHON_STAGE2_A_DEPS = \
|
||||
$(call uniq,$(foreach x,$(THIRD_PARTY_PYTHON_STAGE2_A_DIRECTDEPS),$($(x))))
|
||||
|
||||
o/$(MODE)/third_party/python/pyobj.com.dbg: \
|
||||
$(THIRD_PARTY_PYTHON_STAGE1) \
|
||||
$(THIRD_PARTY_PYTHON_STAGE1_A).pkg \
|
||||
o/$(MODE)/third_party/python/pyobj.o \
|
||||
$(CRT) \
|
||||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/third_party/python/pycomp.com.dbg: \
|
||||
$(THIRD_PARTY_PYTHON_STAGE1) \
|
||||
$(THIRD_PARTY_PYTHON_STAGE1_A).pkg \
|
||||
|
@ -2256,6 +2169,11 @@ o/$(MODE)/third_party/python/pythontester.com.dbg: \
|
|||
$(APE)
|
||||
@$(APELINK)
|
||||
|
||||
o/$(MODE)/third_party/python/pyobj: \
|
||||
o/$(MODE)/third_party/python/pyobj.com
|
||||
@cp -f $< $@
|
||||
@$@ -n
|
||||
|
||||
o/$(MODE)/third_party/python/pycomp: \
|
||||
o/$(MODE)/third_party/python/pycomp.com
|
||||
@cp -f $< $@
|
||||
|
@ -2287,9 +2205,7 @@ $(THIRD_PARTY_PYTHON_STAGE2_A): \
|
|||
$(THIRD_PARTY_PYTHON_STAGE2_A_OBJS)
|
||||
|
||||
$(THIRD_PARTY_PYTHON_STDLIB_PYS_A): $(THIRD_PARTY_PYTHON_STDLIB_PYS_OBJS)
|
||||
$(THIRD_PARTY_PYTHON_STDLIB_DIRS_A): $(THIRD_PARTY_PYTHON_STDLIB_DIRS_OBJS)
|
||||
$(THIRD_PARTY_PYTHON_STDLIB_DATA_A): $(THIRD_PARTY_PYTHON_STDLIB_DATA_OBJS)
|
||||
$(THIRD_PARTY_PYTHON_STDLIB_PYCS_A): $(THIRD_PARTY_PYTHON_STDLIB_PYCS_OBJS)
|
||||
|
||||
$(THIRD_PARTY_PYTHON_STAGE1_A).pkg: \
|
||||
$(THIRD_PARTY_PYTHON_STAGE1_A_OBJS) \
|
||||
|
@ -2332,11 +2248,8 @@ o/$(MODE)/third_party/python/Modules/faulthandler.o: \
|
|||
OVERRIDE_CFLAGS += \
|
||||
-fno-optimize-sibling-calls
|
||||
|
||||
$(THIRD_PARTY_PYTHON_STDLIB_PYS_OBJS): ZIPOBJ_FLAGS += -P.python -C3
|
||||
$(THIRD_PARTY_PYTHON_STDLIB_DIRS_OBJS): ZIPOBJ_FLAGS += -P.python -C3
|
||||
$(THIRD_PARTY_PYTHON_STDLIB_PYS_OBJS): PYFLAGS += -P.python -C3
|
||||
$(THIRD_PARTY_PYTHON_STDLIB_DATA_OBJS): ZIPOBJ_FLAGS += -P.python -C3
|
||||
$(THIRD_PARTY_PYTHON_STDLIB_PYCS_OBJS): ZIPOBJ_FLAGS += -P.python -C5
|
||||
.PRECIOUS: $(THIRD_PARTY_PYTHON_STDLIB_PYCS)
|
||||
|
||||
o/$(MODE)/third_party/python/Python/ceval.o: QUOTA = -M512m
|
||||
o/$(MODE)/third_party/python/Objects/unicodeobject.o: QUOTA += -C16
|
||||
|
@ -2352,6 +2265,7 @@ THIRD_PARTY_PYTHON_LIBS = \
|
|||
|
||||
THIRD_PARTY_PYTHON_OBJS = \
|
||||
$(foreach x,$(THIRD_PARTY_PYTHON_ARTIFACTS),$($(x)_OBJS)) \
|
||||
o/$(MODE)/third_party/python/pyobj.o \
|
||||
o/$(MODE)/third_party/python/pycomp.o \
|
||||
o/$(MODE)/third_party/python/Programs/freeze.o \
|
||||
o/$(MODE)/third_party/python/Programs/python.o \
|
||||
|
@ -2359,6 +2273,7 @@ THIRD_PARTY_PYTHON_OBJS = \
|
|||
|
||||
THIRD_PARTY_PYTHON_SRCS = \
|
||||
$(foreach x,$(THIRD_PARTY_PYTHON_ARTIFACTS),$($(x)_SRCS)) \
|
||||
third_party/python/pyobj.c \
|
||||
third_party/python/pycomp.c \
|
||||
third_party/python/Programs/freeze.c \
|
||||
third_party/python/Programs/python.c \
|
||||
|
|
|
@ -48,7 +48,8 @@ TOOL_BUILD_LIB_A_DIRECTDEPS = \
|
|||
NET_HTTPS \
|
||||
THIRD_PARTY_COMPILER_RT \
|
||||
THIRD_PARTY_MBEDTLS \
|
||||
THIRD_PARTY_XED
|
||||
THIRD_PARTY_XED \
|
||||
THIRD_PARTY_ZLIB
|
||||
|
||||
TOOL_BUILD_LIB_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(TOOL_BUILD_LIB_A_DIRECTDEPS),$($(x))))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef COSMOPOLITAN_TOOL_BUILD_LIB_ELFWRITER_H_
|
||||
#define COSMOPOLITAN_TOOL_BUILD_LIB_ELFWRITER_H_
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/elf/struct/ehdr.h"
|
||||
#include "libc/elf/struct/rela.h"
|
||||
#include "libc/elf/struct/shdr.h"
|
||||
|
@ -48,7 +49,7 @@ struct ElfWriter {
|
|||
struct ElfWriterSyms syms[3][1];
|
||||
struct {
|
||||
size_t i, j, n;
|
||||
struct ElfWriterRela * p;
|
||||
struct ElfWriterRela *p;
|
||||
} relas[1];
|
||||
struct Interner *strtab;
|
||||
struct Interner *shstrtab;
|
||||
|
@ -70,6 +71,9 @@ struct ElfWriterSymRef elfwriter_appendsym(struct ElfWriter *, const char *,
|
|||
int, int, size_t, size_t);
|
||||
void elfwriter_yoink(struct ElfWriter *, const char *);
|
||||
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);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
221
tool/build/lib/elfwriter_zip.c
Normal file
221
tool/build/lib/elfwriter_zip.c
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*-*- 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 2021 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/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/dos.h"
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/nexgen32e/crc32.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/time/struct/tm.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/zip.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
#include "tool/build/lib/elfwriter.h"
|
||||
#include "tool/build/lib/isnocompressext.h"
|
||||
|
||||
#define ZIP_LOCALFILE_SECTION ".zip.2."
|
||||
#define ZIP_DIRECTORY_SECTION ".zip.4."
|
||||
|
||||
static bool ShouldCompress(const char *name, size_t namesize,
|
||||
const unsigned char *data, size_t datasize,
|
||||
bool nocompress) {
|
||||
return !nocompress && datasize >= 64 && !IsNoCompressExt(name, namesize) &&
|
||||
(datasize < 1000 || MeasureEntropy((void *)data, 1000) < 7);
|
||||
}
|
||||
|
||||
static void GetDosLocalTime(int64_t utcunixts, uint16_t *out_time,
|
||||
uint16_t *out_date) {
|
||||
struct tm tm;
|
||||
CHECK_NOTNULL(localtime_r(&utcunixts, &tm));
|
||||
*out_time = DOS_TIME(tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
*out_date = DOS_DATE(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday + 1);
|
||||
}
|
||||
|
||||
static int DetermineVersionNeededToExtract(int method) {
|
||||
if (method == kZipCompressionDeflate) {
|
||||
return kZipEra1993;
|
||||
} else {
|
||||
return kZipEra1989;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char *EmitZipLfileHdr(unsigned char *p, const void *name,
|
||||
size_t namesize, uint32_t crc,
|
||||
uint8_t era, uint16_t gflags,
|
||||
uint16_t method, uint16_t mtime,
|
||||
uint16_t mdate, size_t compsize,
|
||||
size_t uncompsize) {
|
||||
p = WRITE32LE(p, kZipLfileHdrMagic);
|
||||
*p++ = era;
|
||||
*p++ = kZipOsDos;
|
||||
p = WRITE16LE(p, gflags);
|
||||
p = WRITE16LE(p, method);
|
||||
p = WRITE16LE(p, mtime);
|
||||
p = WRITE16LE(p, mdate);
|
||||
p = WRITE32LE(p, crc);
|
||||
p = WRITE32LE(p, compsize);
|
||||
p = WRITE32LE(p, uncompsize);
|
||||
p = WRITE16LE(p, namesize);
|
||||
p = WRITE16LE(p, 0); /* extra */
|
||||
return mempcpy(p, name, namesize);
|
||||
}
|
||||
|
||||
static void EmitZipCdirHdr(unsigned char *p, const void *name, size_t namesize,
|
||||
uint32_t crc, uint8_t era, uint16_t gflags,
|
||||
uint16_t method, uint16_t mtime, uint16_t mdate,
|
||||
uint16_t iattrs, uint16_t dosmode, uint16_t unixmode,
|
||||
size_t compsize, size_t uncompsize,
|
||||
size_t commentsize, struct timespec mtim,
|
||||
struct timespec atim, struct timespec ctim) {
|
||||
uint64_t mt, at, ct;
|
||||
p = WRITE32LE(p, kZipCfileHdrMagic);
|
||||
*p++ = kZipCosmopolitanVersion;
|
||||
*p++ = kZipOsUnix;
|
||||
*p++ = era;
|
||||
*p++ = kZipOsDos;
|
||||
p = WRITE16LE(p, gflags);
|
||||
p = WRITE16LE(p, method);
|
||||
p = WRITE16LE(p, mtime);
|
||||
p = WRITE16LE(p, mdate);
|
||||
/* 16 */
|
||||
p = WRITE32LE(p, crc);
|
||||
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);
|
||||
p = WRITE16LE(p, 0); /* disk */
|
||||
p = WRITE16LE(p, iattrs);
|
||||
p = WRITE16LE(p, dosmode);
|
||||
p = WRITE16LE(p, unixmode);
|
||||
p = WRITE32LE(p, 0); /* RELOCATE ME (kZipCfileOffsetOffset) */
|
||||
/* 46 */
|
||||
memcpy(p, name, namesize);
|
||||
p += namesize;
|
||||
p = WRITE16LE(p, kZipExtraNtfs);
|
||||
p = WRITE16LE(p, 32);
|
||||
p = WRITE32LE(p, 0);
|
||||
p = WRITE16LE(p, 1);
|
||||
p = WRITE16LE(p, 24);
|
||||
mt = TimeSpecToWindowsTime(mtim);
|
||||
at = TimeSpecToWindowsTime(atim);
|
||||
ct = TimeSpecToWindowsTime(ctim);
|
||||
p = WRITE64LE(p, mt);
|
||||
p = WRITE64LE(p, at);
|
||||
p = WRITE64LE(p, ct);
|
||||
}
|
||||
|
||||
/**
|
||||
* Embeds zip file in elf object.
|
||||
*/
|
||||
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) {
|
||||
z_stream zs;
|
||||
uint8_t era;
|
||||
uint32_t crc;
|
||||
unsigned char *lfile, *cfile;
|
||||
struct ElfWriterSymRef lfilesym;
|
||||
size_t lfilehdrsize, uncompsize, compsize, commentsize;
|
||||
uint16_t method, gflags, mtime, mdate, iattrs, dosmode;
|
||||
|
||||
gflags = 0;
|
||||
iattrs = 0;
|
||||
compsize = size;
|
||||
uncompsize = size;
|
||||
CHECK_LE(uncompsize, UINT32_MAX);
|
||||
lfilehdrsize = kZipLfileHdrMinSize + namesize;
|
||||
crc = crc32_z(0, data, uncompsize);
|
||||
GetDosLocalTime(mtim.tv_sec, &mtime, &mdate);
|
||||
if (IsUtf8(name, namesize)) gflags |= kZipGflagUtf8;
|
||||
if (S_ISREG(mode) && IsText(data, size)) {
|
||||
iattrs |= kZipIattrText;
|
||||
}
|
||||
commentsize = kZipCdirHdrLinkableSize - (CFILE_HDR_SIZE + namesize);
|
||||
dosmode = !(mode & 0200) ? kNtFileAttributeReadonly : 0;
|
||||
method = ShouldCompress(name, namesize, data, size, nocompress)
|
||||
? kZipCompressionDeflate
|
||||
: kZipCompressionNone;
|
||||
|
||||
/* 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);
|
||||
if (method == kZipCompressionDeflate) {
|
||||
CHECK_EQ(Z_OK, deflateInit2(memset(&zs, 0, sizeof(zs)),
|
||||
Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
|
||||
MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY));
|
||||
zs.next_in = data;
|
||||
zs.avail_in = uncompsize;
|
||||
zs.next_out = ((lfile = elfwriter_reserve(
|
||||
elf, (lfilehdrsize +
|
||||
(zs.avail_out = compressBound(uncompsize))))) +
|
||||
lfilehdrsize);
|
||||
CHECK_EQ(Z_STREAM_END, deflate(&zs, Z_FINISH));
|
||||
CHECK_EQ(Z_OK, deflateEnd(&zs));
|
||||
if (zs.total_out < uncompsize) {
|
||||
compsize = zs.total_out;
|
||||
} else {
|
||||
method = kZipCompressionNone;
|
||||
}
|
||||
} else {
|
||||
lfile = elfwriter_reserve(elf, lfilehdrsize + uncompsize);
|
||||
}
|
||||
if (method == kZipCompressionNone) {
|
||||
memcpy(lfile + lfilehdrsize, data, uncompsize);
|
||||
}
|
||||
era = method ? kZipEra1993 : kZipEra1989;
|
||||
EmitZipLfileHdr(lfile, name, namesize, crc, era, gflags, method, mtime, mdate,
|
||||
compsize, uncompsize);
|
||||
elfwriter_commit(elf, lfilehdrsize + compsize);
|
||||
lfilesym = elfwriter_appendsym(elf, gc(xasprintf("%s%s", "zip+lfile:", name)),
|
||||
ELF64_ST_INFO(STB_LOCAL, STT_OBJECT),
|
||||
STV_DEFAULT, 0, lfilehdrsize);
|
||||
elfwriter_appendsym(elf, symbol, ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
|
||||
STV_DEFAULT, lfilehdrsize, compsize);
|
||||
elfwriter_finishsection(elf);
|
||||
|
||||
/* emit central directory record */
|
||||
elfwriter_align(elf, 1, 0);
|
||||
elfwriter_startsection(elf,
|
||||
gc(xasprintf("%s%s", ZIP_DIRECTORY_SECTION, name)),
|
||||
SHT_PROGBITS, SHF_ALLOC);
|
||||
EmitZipCdirHdr((cfile = elfwriter_reserve(elf, kZipCdirHdrLinkableSize)),
|
||||
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,
|
||||
kZipCdirHdrLinkableSize);
|
||||
elfwriter_appendrela(elf, kZipCfileOffsetOffset, lfilesym, R_X86_64_32,
|
||||
-imagebase);
|
||||
elfwriter_commit(elf, kZipCdirHdrLinkableSize);
|
||||
elfwriter_finishsection(elf);
|
||||
}
|
|
@ -16,50 +16,25 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/arraylist.internal.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/bswap.h"
|
||||
#include "libc/bits/safemacros.internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/dos.h"
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/fmt/conv.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/log/check.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/mem/alloca.h"
|
||||
#include "libc/nexgen32e/crc32.h"
|
||||
#include "libc/nt/enum/fileflagandattributes.h"
|
||||
#include "libc/nt/struct/imageauxsymbolex.internal.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/runtime/symbols.internal.h"
|
||||
#include "libc/stdio/stdio.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/ex.h"
|
||||
#include "libc/sysv/consts/exit.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/ok.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/time/struct/tm.h"
|
||||
#include "libc/time/time.h"
|
||||
#include "libc/x/x.h"
|
||||
#include "libc/zip.h"
|
||||
#include "third_party/getopt/getopt.h"
|
||||
#include "third_party/zlib/zlib.h"
|
||||
#include "tool/build/lib/elfwriter.h"
|
||||
#include "tool/build/lib/isnocompressext.h"
|
||||
#include "tool/build/lib/stripcomponents.h"
|
||||
|
||||
#define ZIP_LOCALFILE_SECTION ".zip.2."
|
||||
#define ZIP_DIRECTORY_SECTION ".zip.4."
|
||||
|
||||
char *name_;
|
||||
char *yoink_;
|
||||
char *symbol_;
|
||||
|
@ -124,187 +99,13 @@ void GetOpts(int *argc, char ***argv) {
|
|||
CHECK_NOTNULL(outpath_);
|
||||
}
|
||||
|
||||
bool ShouldCompress(const char *name, size_t namesize,
|
||||
const unsigned char *data, size_t datasize) {
|
||||
return !nocompress_ && datasize >= 64 && !IsNoCompressExt(name, namesize) &&
|
||||
(datasize < 1000 || MeasureEntropy((void *)data, 1000) < 7);
|
||||
}
|
||||
|
||||
void GetDosLocalTime(int64_t utcunixts, uint16_t *out_time,
|
||||
uint16_t *out_date) {
|
||||
struct tm tm;
|
||||
CHECK_NOTNULL(localtime_r(&utcunixts, &tm));
|
||||
*out_time = DOS_TIME(tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
*out_date = DOS_DATE(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday + 1);
|
||||
}
|
||||
|
||||
static int DetermineVersionNeededToExtract(int method) {
|
||||
if (method == kZipCompressionDeflate) {
|
||||
return kZipEra1993;
|
||||
} else {
|
||||
return kZipEra1989;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned char *EmitZipLfileHdr(unsigned char *p, const void *name,
|
||||
size_t namesize, uint32_t crc,
|
||||
uint8_t era, uint16_t gflags,
|
||||
uint16_t method, uint16_t mtime,
|
||||
uint16_t mdate, size_t compsize,
|
||||
size_t uncompsize) {
|
||||
p = WRITE32LE(p, kZipLfileHdrMagic);
|
||||
*p++ = era;
|
||||
*p++ = kZipOsDos;
|
||||
p = WRITE16LE(p, gflags);
|
||||
p = WRITE16LE(p, method);
|
||||
p = WRITE16LE(p, mtime);
|
||||
p = WRITE16LE(p, mdate);
|
||||
p = WRITE32LE(p, crc);
|
||||
p = WRITE32LE(p, compsize);
|
||||
p = WRITE32LE(p, uncompsize);
|
||||
p = WRITE16LE(p, namesize);
|
||||
p = WRITE16LE(p, 0); /* extra */
|
||||
return mempcpy(p, name, namesize);
|
||||
}
|
||||
|
||||
static void EmitZipCdirHdr(unsigned char *p, const void *name, size_t namesize,
|
||||
uint32_t crc, uint8_t era, uint16_t gflags,
|
||||
uint16_t method, uint16_t mtime, uint16_t mdate,
|
||||
uint16_t iattrs, uint16_t dosmode, uint16_t unixmode,
|
||||
size_t compsize, size_t uncompsize,
|
||||
size_t commentsize, struct stat *st) {
|
||||
uint64_t mt, at, ct;
|
||||
p = WRITE32LE(p, kZipCfileHdrMagic);
|
||||
*p++ = kZipCosmopolitanVersion;
|
||||
*p++ = kZipOsUnix;
|
||||
*p++ = era;
|
||||
*p++ = kZipOsDos;
|
||||
p = WRITE16LE(p, gflags);
|
||||
p = WRITE16LE(p, method);
|
||||
p = WRITE16LE(p, mtime);
|
||||
p = WRITE16LE(p, mdate);
|
||||
/* 16 */
|
||||
p = WRITE32LE(p, crc);
|
||||
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);
|
||||
p = WRITE16LE(p, 0); /* disk */
|
||||
p = WRITE16LE(p, iattrs);
|
||||
p = WRITE16LE(p, dosmode);
|
||||
p = WRITE16LE(p, unixmode);
|
||||
p = WRITE32LE(p, 0); /* RELOCATE ME (kZipCfileOffsetOffset) */
|
||||
/* 46 */
|
||||
memcpy(p, name, namesize);
|
||||
p += namesize;
|
||||
p = WRITE16LE(p, kZipExtraNtfs);
|
||||
p = WRITE16LE(p, 32);
|
||||
p = WRITE32LE(p, 0);
|
||||
p = WRITE16LE(p, 1);
|
||||
p = WRITE16LE(p, 24);
|
||||
#define NTTIME(t) \
|
||||
(t.tv_sec + MODERNITYSECONDS) * HECTONANOSECONDS + t.tv_nsec / 100
|
||||
mt = NTTIME(st->st_mtim);
|
||||
at = NTTIME(st->st_atim);
|
||||
ct = NTTIME(st->st_ctim);
|
||||
p = WRITE64LE(p, mt);
|
||||
p = WRITE64LE(p, at);
|
||||
p = WRITE64LE(p, ct);
|
||||
}
|
||||
|
||||
void EmitZip(struct ElfWriter *elf, const char *name, size_t namesize,
|
||||
const unsigned char *data, struct stat *st) {
|
||||
z_stream zs;
|
||||
uint8_t era;
|
||||
uint32_t crc;
|
||||
unsigned char *lfile, *cfile;
|
||||
struct ElfWriterSymRef lfilesym;
|
||||
size_t lfilehdrsize, uncompsize, compsize, commentsize;
|
||||
uint16_t method, gflags, mtime, mdate, iattrs, dosmode;
|
||||
|
||||
gflags = 0;
|
||||
iattrs = 0;
|
||||
compsize = st->st_size;
|
||||
uncompsize = st->st_size;
|
||||
CHECK_LE(uncompsize, UINT32_MAX);
|
||||
lfilehdrsize = kZipLfileHdrMinSize + namesize;
|
||||
crc = crc32_z(0, data, uncompsize);
|
||||
GetDosLocalTime(st->st_mtim.tv_sec, &mtime, &mdate);
|
||||
if (IsUtf8(name, namesize)) gflags |= kZipGflagUtf8;
|
||||
if (S_ISREG(st->st_mode) && IsText(data, st->st_size)) {
|
||||
iattrs |= kZipIattrText;
|
||||
}
|
||||
commentsize = kZipCdirHdrLinkableSize - (CFILE_HDR_SIZE + namesize);
|
||||
dosmode = !(st->st_mode & 0200) ? kNtFileAttributeReadonly : 0;
|
||||
method = ShouldCompress(name, namesize, data, st->st_size)
|
||||
? kZipCompressionDeflate
|
||||
: kZipCompressionNone;
|
||||
|
||||
/* 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);
|
||||
if (method == kZipCompressionDeflate) {
|
||||
CHECK_EQ(Z_OK, deflateInit2(memset(&zs, 0, sizeof(zs)),
|
||||
Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
|
||||
MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY));
|
||||
zs.next_in = data;
|
||||
zs.avail_in = uncompsize;
|
||||
zs.next_out = ((lfile = elfwriter_reserve(
|
||||
elf, (lfilehdrsize +
|
||||
(zs.avail_out = compressBound(uncompsize))))) +
|
||||
lfilehdrsize);
|
||||
CHECK_EQ(Z_STREAM_END, deflate(&zs, Z_FINISH));
|
||||
CHECK_EQ(Z_OK, deflateEnd(&zs));
|
||||
if (zs.total_out < uncompsize) {
|
||||
compsize = zs.total_out;
|
||||
} else {
|
||||
method = kZipCompressionNone;
|
||||
}
|
||||
} else {
|
||||
lfile = elfwriter_reserve(elf, lfilehdrsize + uncompsize);
|
||||
}
|
||||
if (method == kZipCompressionNone) {
|
||||
memcpy(lfile + lfilehdrsize, data, uncompsize);
|
||||
}
|
||||
era = method ? kZipEra1993 : kZipEra1989;
|
||||
EmitZipLfileHdr(lfile, name, namesize, crc, era, gflags, method, mtime, mdate,
|
||||
compsize, uncompsize);
|
||||
elfwriter_commit(elf, lfilehdrsize + compsize);
|
||||
lfilesym = elfwriter_appendsym(elf, gc(xasprintf("%s%s", "zip+lfile:", name)),
|
||||
ELF64_ST_INFO(STB_LOCAL, STT_OBJECT),
|
||||
STV_DEFAULT, 0, lfilehdrsize);
|
||||
elfwriter_appendsym(elf, name, ELF64_ST_INFO(STB_GLOBAL, STT_OBJECT),
|
||||
STV_DEFAULT, lfilehdrsize, compsize);
|
||||
elfwriter_finishsection(elf);
|
||||
|
||||
/* emit central directory record */
|
||||
elfwriter_align(elf, 1, 0);
|
||||
elfwriter_startsection(elf,
|
||||
gc(xasprintf("%s%s", ZIP_DIRECTORY_SECTION, name)),
|
||||
SHT_PROGBITS, SHF_ALLOC);
|
||||
EmitZipCdirHdr((cfile = elfwriter_reserve(elf, kZipCdirHdrLinkableSize)),
|
||||
name, namesize, crc, era, gflags, method, mtime, mdate, iattrs,
|
||||
dosmode, st->st_mode, compsize, uncompsize, commentsize, st);
|
||||
elfwriter_appendsym(elf, gc(xasprintf("%s%s", "zip+cdir:", name)),
|
||||
ELF64_ST_INFO(STB_LOCAL, STT_OBJECT), STV_DEFAULT, 0,
|
||||
kZipCdirHdrLinkableSize);
|
||||
elfwriter_appendrela(elf, kZipCfileOffsetOffset, lfilesym, R_X86_64_32,
|
||||
-image_base_);
|
||||
elfwriter_commit(elf, kZipCdirHdrLinkableSize);
|
||||
elfwriter_finishsection(elf);
|
||||
}
|
||||
|
||||
void ProcessFile(struct ElfWriter *elf, const char *path) {
|
||||
int fd;
|
||||
void *map;
|
||||
size_t pathlen;
|
||||
struct stat st;
|
||||
const char *name;
|
||||
struct timespec timestamp;
|
||||
CHECK_NE(-1, (fd = open(path, O_RDONLY)));
|
||||
CHECK_NE(-1, fstat(fd, &st));
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
|
@ -329,7 +130,9 @@ void ProcessFile(struct ElfWriter *elf, const char *path) {
|
|||
name = gc(xasprintf("%s/", name));
|
||||
}
|
||||
}
|
||||
EmitZip(elf, name, strlen(name), map, &st);
|
||||
memset(×tamp, 0, sizeof(timestamp));
|
||||
elfwriter_zip(elf, name, name, strlen(name), map, st.st_size, st.st_mode,
|
||||
timestamp, timestamp, timestamp, nocompress_, image_base_);
|
||||
if (st.st_size) CHECK_NE(-1, munmap(map, st.st_size));
|
||||
close(fd);
|
||||
}
|
||||
|
@ -362,7 +165,6 @@ void zipobj(int argc, char **argv) {
|
|||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
showcrashreports();
|
||||
zipobj(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue