Fix zip executables on MacOS

Here's why we got those `Killed: 11` failures on MacOS after modifying
the contentns of the redbean.com executable. If you were inserting a
small file, such as a HelloWorld.html file, then InfoZIP might have
decreased the size of the executable to less than what the Mach-O
section had been expecting.

That's because when zipobj.com put things like time zone data in the
executable, it aligned each zip file entry on a 64-byte boundary, simply
for the sake of readability in binary dumps. But when InfoZIP edited the
file it would rewrite every entry using ZIP's usual 2-byte alignment.
Thus causing shrinkage.

The solution was to reconfigure the linker script so that zip file bits
that get put into the executable at link-time, such as timezone data,
aren't officially part of the executable image, i.e. we don't want the
operating system to load that part.

The original decision to put the linked zip files into the .data section
was mostly made so that when the executable was run in its .com.dbg form
it would still have the zip entries be accessible, even though there was
tons of GNU debug data following the central directory. We're not going
to be able to do that. The .com executable should be the canonical
executable. We have really good tools for automatically attaching and
configuring GDB correctly with debug symbols even when the .com is run.
We'll have to rely on those in cases where zip embedding is used.

See #53
See #54
See #68
This commit is contained in:
Justine Tunney 2021-02-27 18:02:32 -08:00
parent cc56038b05
commit 94afa982c3
8 changed files with 36 additions and 1333 deletions

View file

@ -364,6 +364,11 @@ SECTIONS {
PROVIDE_HIDDEN(edata = .); PROVIDE_HIDDEN(edata = .);
} :Ram } :Ram
.zip : {
KEEP(*(SORT_BY_NAME(.zip.*)))
. = ALIGN(PAGESIZE);
}
.bss . : { .bss . : {
KEEP(*(SORT_BY_NAME(.piro.bss.init.*))) KEEP(*(SORT_BY_NAME(.piro.bss.init.*)))
*(.piro.bss) *(.piro.bss)
@ -382,7 +387,7 @@ SECTIONS {
. = ALIGN(FRAMESIZE); /* for brk()/sbrk() allocation */ . = ALIGN(FRAMESIZE); /* for brk()/sbrk() allocation */
HIDDEN(_end = .); HIDDEN(_end = .);
PROVIDE_HIDDEN(end = .); PROVIDE_HIDDEN(end = .);
} :Ram }
/*END: nt addressability guarantee */ /*END: nt addressability guarantee */
/*END: bsd addressability guarantee */ /*END: bsd addressability guarantee */
@ -453,7 +458,7 @@ HIDDEN(ape_rom_rva = RVA(ape_rom_vaddr));
HIDDEN(ape_ram_offset = ape_rom_offset + ape_rom_filesz); HIDDEN(ape_ram_offset = ape_rom_offset + ape_rom_filesz);
HIDDEN(ape_ram_vaddr = ADDR(.data)); HIDDEN(ape_ram_vaddr = ADDR(.data));
HIDDEN(ape_ram_paddr = LOADADDR(.data)); HIDDEN(ape_ram_paddr = LOADADDR(.data));
HIDDEN(ape_ram_filesz = LOADADDR(.bss) - LOADADDR(.data)); HIDDEN(ape_ram_filesz = SIZEOF(.data));
HIDDEN(ape_ram_memsz = ADDR(.bss) + SIZEOF(.bss) - ape_ram_vaddr); HIDDEN(ape_ram_memsz = ADDR(.bss) + SIZEOF(.bss) - ape_ram_vaddr);
HIDDEN(ape_ram_align = PAGESIZE); HIDDEN(ape_ram_align = PAGESIZE);
HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr)); HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr));
@ -535,7 +540,7 @@ HIDDEN(v_ape_highsectors =
ZIPCONST(v_zip_cdoffset, __zip_start - IMAGE_BASE_VIRTUAL); ZIPCONST(v_zip_cdoffset, __zip_start - IMAGE_BASE_VIRTUAL);
ZIPCONST(v_zip_cdirsize, __zip_end - __zip_start); ZIPCONST(v_zip_cdirsize, __zip_end - __zip_start);
ZIPCONST(v_zip_records, v_zip_cdirsize / kZipCdirHdrLinkableSize); ZIPCONST(v_zip_records, v_zip_cdirsize / kZipCdirHdrLinkableSize);
ZIPCONST(v_zip_commentsize, _edata - __zip_end - kZipCdirHdrMinSize); ZIPCONST(v_zip_commentsize, 0);
#if SupportsXnu() #if SupportsXnu()
/* Generates deterministic ID. */ /* Generates deterministic ID. */

Binary file not shown.

View file

@ -21,7 +21,7 @@
#include "libc/zip.h" #include "libc/zip.h"
// ZIP Central Directory. // ZIP Central Directory.
.section .piro.data.sort.zip.3,"a",@progbits .section .zip.3,"",@progbits
.hidden __zip_start .hidden __zip_start
.globl __zip_start .globl __zip_start
.type __zip_start,@object .type __zip_start,@object
@ -31,7 +31,7 @@ __zip_start:
... ...
decentralized content decentralized content
... ...
*/.section .piro.data.sort.zip.5,"a",@progbits */.section .zip.5,"",@progbits
.align kZipCdirAlign .align kZipCdirAlign
__zip_end: __zip_end:
.long kZipCdirHdrMagic # magic .long kZipCdirHdrMagic # magic

View file

@ -83,7 +83,7 @@ noasan texthead uint64_t *__get_virtual(struct mman *mm, uint64_t *t,
/** /**
* Sorts, rounds, and filters BIOS memory map. * Sorts, rounds, and filters BIOS memory map.
*/ */
static noasan texthead void __normalize_e820(struct mman *mm) { static noasan textreal void __normalize_e820(struct mman *mm) {
uint64_t a, b; uint64_t a, b;
uint64_t x, y; uint64_t x, y;
unsigned i, j, n; unsigned i, j, n;
@ -113,7 +113,7 @@ static noasan texthead void __normalize_e820(struct mman *mm) {
/** /**
* Identity maps all usable physical memory to its negative address. * Identity maps all usable physical memory to its negative address.
*/ */
static noasan texthead void __invert_memory(struct mman *mm, uint64_t *pml4t) { static noasan textreal void __invert_memory(struct mman *mm, uint64_t *pml4t) {
uint64_t i, j, *m, p, pe; uint64_t i, j, *m, p, pe;
for (i = 0; i < mm->e820n; ++i) { for (i = 0; i < mm->e820n; ++i) {
for (p = mm->e820[i].addr, pe = mm->e820[i].addr + mm->e820[i].size; for (p = mm->e820[i].addr, pe = mm->e820[i].addr + mm->e820[i].size;
@ -126,7 +126,7 @@ static noasan texthead void __invert_memory(struct mman *mm, uint64_t *pml4t) {
} }
} }
noasan texthead void __setup_mman(struct mman *mm, uint64_t *pml4t) { noasan textreal void __setup_mman(struct mman *mm, uint64_t *pml4t) {
__normalize_e820(mm); __normalize_e820(mm);
__invert_memory(mm, pml4t); __invert_memory(mm, pml4t);
} }

View file

@ -113,7 +113,7 @@ TEST(undeflate, testEmbeddedCompressedZipFile_theHardWay) {
ASSERT_TRUE(found); ASSERT_TRUE(found);
} }
//////////////////////////////////////////////////////////////////////////////// #if 0 /* todo: don't rely on __zip_end */
uint8_t *buf_; uint8_t *buf_;
size_t bufsize_; size_t bufsize_;
@ -165,3 +165,5 @@ BENCH(undeflate, bench) {
EZBENCH(donothing, Inflate()); EZBENCH(donothing, Inflate());
EZBENCH(donothing, Undeflate()); EZBENCH(donothing, Undeflate());
} }
#endif

View file

@ -52,8 +52,8 @@
#include "third_party/zlib/zlib.h" #include "third_party/zlib/zlib.h"
#include "tool/build/lib/elfwriter.h" #include "tool/build/lib/elfwriter.h"
#define ZIP_LOCALFILE_SECTION ".piro.data.sort.zip.2." #define ZIP_LOCALFILE_SECTION ".zip.2."
#define ZIP_DIRECTORY_SECTION ".piro.data.sort.zip.4." #define ZIP_DIRECTORY_SECTION ".zip.4."
#define PUT8(P, V) *P++ = V #define PUT8(P, V) *P++ = V
#define PUT16(P, V) P[0] = V & 0xff, P[1] = V >> 010 & 0xff, P += 2 #define PUT16(P, V) P[0] = V & 0xff, P[1] = V >> 010 & 0xff, P += 2
@ -218,9 +218,8 @@ void EmitZip(struct ElfWriter *elf, const char *name, size_t namesize,
/* emit embedded file content w/ pkzip local file header */ /* emit embedded file content w/ pkzip local file header */
elfwriter_align(elf, kZipCdirAlign, 0); elfwriter_align(elf, kZipCdirAlign, 0);
elfwriter_startsection(elf, elfwriter_startsection(
gc(xasprintf("%s%s", ZIP_LOCALFILE_SECTION, name)), elf, gc(xasprintf("%s%s", ZIP_LOCALFILE_SECTION, name)), SHT_PROGBITS, 0);
SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
if (method == kZipCompressionDeflate) { if (method == kZipCompressionDeflate) {
CHECK_EQ(Z_OK, deflateInit2(memset(&zs, 0, sizeof(zs)), CHECK_EQ(Z_OK, deflateInit2(memset(&zs, 0, sizeof(zs)),
Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
@ -257,9 +256,8 @@ void EmitZip(struct ElfWriter *elf, const char *name, size_t namesize,
/* emit central directory record */ /* emit central directory record */
elfwriter_align(elf, kZipCdirAlign, 0); elfwriter_align(elf, kZipCdirAlign, 0);
elfwriter_startsection(elf, elfwriter_startsection(
gc(xasprintf("%s%s", ZIP_DIRECTORY_SECTION, name)), elf, gc(xasprintf("%s%s", ZIP_DIRECTORY_SECTION, name)), SHT_PROGBITS, 0);
SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
EmitZipCdirHdr((cfile = elfwriter_reserve(elf, kZipCdirHdrLinkableSize)), EmitZipCdirHdr((cfile = elfwriter_reserve(elf, kZipCdirHdrLinkableSize)),
name, namesize, crc, era, gflags, method, mtime, mdate, iattrs, name, namesize, crc, era, gflags, method, mtime, mdate, iattrs,
dosmode, st->st_mode, compsize, uncompsize, commentsize); dosmode, st->st_mode, compsize, uncompsize, commentsize);

File diff suppressed because it is too large Load diff

View file

@ -634,33 +634,22 @@ static bool OpenZip(const char *path) {
if (zmap) { if (zmap) {
LOGIFNEG1(munmap(zmap, zmapsize)); LOGIFNEG1(munmap(zmap, zmapsize));
} }
if (!zmap && ZIP_CDIR_MAGIC(__zip_end) == kZipCdirHdrMagic) { fd = -1;
if (IndexAssets(_base, __zip_end)) { map = MAP_FAILED;
ok = true; if ((fd = open(path, O_RDONLY)) != -1 && fstat(fd, &st) != -1 && st.st_size &&
zbase = _base; (map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) &&
zcdir = __zip_end; (cdir = zipfindcentraldir(map, st.st_size)) && IndexAssets(map, cdir)) {
} else { ok = true;
ok = false; zmap = map;
} zbase = map;
} else { zcdir = cdir;
fd = -1;
map = MAP_FAILED; map = MAP_FAILED;
if ((fd = open(path, O_RDONLY)) != -1 && fstat(fd, &st) != -1 && zmapsize = st.st_size;
st.st_size && } else {
(map = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) && ok = false;
(cdir = zipfindcentraldir(map, st.st_size)) && IndexAssets(map, cdir)) {
ok = true;
zmap = map;
zbase = map;
zcdir = cdir;
map = MAP_FAILED;
zmapsize = st.st_size;
} else {
ok = false;
}
if (map != MAP_FAILED) LOGIFNEG1(munmap(map, st.st_size));
if (fd != -1) LOGIFNEG1(close(fd));
} }
if (map != MAP_FAILED) LOGIFNEG1(munmap(map, st.st_size));
if (fd != -1) LOGIFNEG1(close(fd));
return ok; return ok;
} }