mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 03:27:39 +00:00
Mint APE Loader 1.6
This change fixes a bug with loading pure bss program headers.
This commit is contained in:
parent
c48ee8e4fe
commit
1a5ef5ba13
11 changed files with 87 additions and 51 deletions
46
ape/ape-m1.c
46
ape/ape-m1.c
|
@ -544,8 +544,9 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
|
||||
/* load elf */
|
||||
for (i = 0; i < e->e_phnum; ++i) {
|
||||
void *addr;
|
||||
unsigned long size;
|
||||
if (p[i].p_type != PT_LOAD) continue;
|
||||
if (!p[i].p_memsz) continue;
|
||||
|
||||
/* configure mapping */
|
||||
prot = 0;
|
||||
|
@ -556,36 +557,51 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
|
|||
|
||||
/* load from file */
|
||||
if (p[i].p_filesz) {
|
||||
void *addr;
|
||||
int prot1, prot2;
|
||||
unsigned long size;
|
||||
unsigned long wipe;
|
||||
prot1 = prot;
|
||||
prot2 = prot;
|
||||
/*
|
||||
* when we ask the system to map the interval [vaddr,vaddr+filesz)
|
||||
* it might schlep extra file content into memory on both the left
|
||||
* and the righthand side. that's because elf doesn't require that
|
||||
* either side of the interval be aligned on the system page size.
|
||||
*
|
||||
* normally we can get away with ignoring these junk bytes. but if
|
||||
* the segment defines bss memory (i.e. memsz > filesz) then we'll
|
||||
* need to clear the extra bytes in the page, if they exist.
|
||||
*
|
||||
* since we can't do that if we're mapping a read-only page, we'll
|
||||
* actually map it with write permissions and protect it afterward
|
||||
*/
|
||||
a = p[i].p_vaddr + p[i].p_filesz; /* end of file content */
|
||||
b = (a + (pagesz - 1)) & -pagesz; /* first pure bss page */
|
||||
c = p[i].p_vaddr + p[i].p_memsz; /* end of segment data */
|
||||
if (b > c) b = c;
|
||||
if (c > b && (~prot1 & PROT_WRITE)) {
|
||||
wipe = MIN(b - a, c - a);
|
||||
if (wipe && (~prot1 & PROT_WRITE)) {
|
||||
prot1 = PROT_READ | PROT_WRITE;
|
||||
}
|
||||
addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz));
|
||||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz;
|
||||
rc = (long)mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mmap");
|
||||
if (c > b) Bzero((void *)(dynbase + a), b - a);
|
||||
if (wipe) Bzero((void *)(dynbase + a), wipe);
|
||||
if (prot2 != prot1) {
|
||||
rc = mprotect(addr, size, prot2);
|
||||
if (rc < 0) Pexit(exe, rc, "prog mprotect");
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate extra bss */
|
||||
a = p[i].p_vaddr + p[i].p_filesz;
|
||||
a = (a + (pagesz - 1)) & -pagesz;
|
||||
b = p[i].p_vaddr + p[i].p_memsz;
|
||||
if (b > a) {
|
||||
/* allocate extra bss */
|
||||
if (c > b) {
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = (long)mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "extra bss mmap");
|
||||
}
|
||||
} else {
|
||||
/* allocate pure bss */
|
||||
addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz));
|
||||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = (long)mmap((void *)(dynbase + a), b - a, prot, flags, -1, 0);
|
||||
rc = (long)mmap(addr, size, prot, flags, -1, 0);
|
||||
if (rc < 0) Pexit(exe, rc, "bss mmap");
|
||||
}
|
||||
}
|
||||
|
@ -861,7 +877,7 @@ int main(int argc, char **argv, char **envp) {
|
|||
} else if (argc < 2) {
|
||||
Emit("usage: ape PROG [ARGV1,ARGV2,...]\n"
|
||||
" ape - PROG [ARGV0,ARGV1,...]\n"
|
||||
"actually portable executable loader silicon 1.5\n"
|
||||
"actually portable executable loader silicon 1.6\n"
|
||||
"copyright 2023 justine alexandra roberts tunney\n"
|
||||
"https://justine.lol/ape.html\n");
|
||||
_exit(1);
|
||||
|
|
34
ape/ape.S
34
ape/ape.S
|
@ -610,7 +610,7 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
|
|||
// extract the loader into a temp folder, and use it to
|
||||
// load the APE without modifying it.
|
||||
.ascii "[ x\"$1\" != x--assimilate ] && {\n"
|
||||
.ascii "t=\"${TMPDIR:-${HOME:-.}}/.ape-1.5\"\n"
|
||||
.ascii "t=\"${TMPDIR:-${HOME:-.}}/.ape-1.6\"\n"
|
||||
.ascii "[ -x \"$t\" ] || {\n"
|
||||
.ascii "mkdir -p \"${t%/*}\" &&\n"
|
||||
.ascii "dd if=\"$o\" of=\"$t.$$\" skip="
|
||||
|
@ -818,7 +818,7 @@ ape.ident:
|
|||
.long 1
|
||||
1: .asciz "APE"
|
||||
2: .balign 4
|
||||
3: .long 105000000
|
||||
3: .long 106000000
|
||||
4: .size ape.ident,.-ape.ident
|
||||
.type ape.ident,@object
|
||||
.previous
|
||||
|
@ -1052,11 +1052,11 @@ PEIMPS = 0b11000000000000000000000001000000
|
|||
.balign __SIZEOF_POINTER__
|
||||
ape_pe: .ascin "PE",4
|
||||
.short kNtImageFileMachineNexgen32e
|
||||
.stub ape_pe_shnum,short // NumberOfSections
|
||||
.short ape_pe_shnum // NumberOfSections
|
||||
.long 0x5c64126b // TimeDateStamp
|
||||
.long 0 // PointerToSymbolTable
|
||||
.long 0 // NumberOfSymbols
|
||||
.stub ape_pe_optsz,short // SizeOfOptionalHeader
|
||||
.short ape_pe_optsz // SizeOfOptionalHeader
|
||||
.short PEEXE // Characteristics
|
||||
.short kNtPe64bit // Optional Header Magic
|
||||
.byte 14 // MajorLinkerVersion
|
||||
|
@ -1080,25 +1080,25 @@ ape_pe: .ascin "PE",4
|
|||
.long ape_pe_sizeofheaders // SizeOfHeaders
|
||||
.long 0 // Checksum
|
||||
.short v_ntsubsystem // Subsystem: 0=Neutral,2=GUI,3=Console
|
||||
.stub v_ntdllchar,short // DllCharacteristics
|
||||
.quad 0x0000000000100000 // StackReserve
|
||||
.quad 0x00000000000fc000 // StackCommit
|
||||
.short v_ntdllchar // DllCharacteristics
|
||||
.quad ape_stack_memsz2 // StackReserve
|
||||
.quad 64 * 1024 // StackCommit
|
||||
.quad 0 // HeapReserve
|
||||
.quad 0 // HeapCommit
|
||||
.long 0 // LoaderFlags
|
||||
.long 2 // NumberOfDirectoryEntries
|
||||
.long 0,0 // ExportsDirectory
|
||||
.stub ape_idata,long // ImportsDirectory
|
||||
.stub ape_idata_idtsize,long // ImportsDirectorySize
|
||||
.long ape_idata // ImportsDirectory
|
||||
.long ape_idata_idtsize // ImportsDirectorySize
|
||||
.endobj ape_pe,globl
|
||||
.previous
|
||||
|
||||
.section .pe.sections,"a",@progbits
|
||||
.ascin ".text",8 // Section Name
|
||||
.stub ape_text_memsz,long // Virtual Size or Physical Address
|
||||
.stub ape_text_rva,long // Relative Virtual Address
|
||||
.stub ape_text_filesz,long // Physical Size
|
||||
.stub ape_text_offset,long // Physical Offset
|
||||
.long ape_text_memsz // Virtual Size or Physical Address
|
||||
.long ape_text_rva // Relative Virtual Address
|
||||
.long ape_text_filesz // Physical Size
|
||||
.long ape_text_offset // Physical Offset
|
||||
.long 0 // Relocation Table Offset
|
||||
.long 0 // Line Number Table Offset
|
||||
.short 0 // Relocation Count
|
||||
|
@ -1108,10 +1108,10 @@ ape_pe: .ascin "PE",4
|
|||
|
||||
.section .pe.sections,"a",@progbits
|
||||
.ascin ".data",8 // Section Name
|
||||
.stub ape_ram_memsz,long // Virtual Size or Physical Address
|
||||
.stub ape_ram_rva,long // Relative Virtual Address
|
||||
.stub ape_ram_filesz,long // Physical Size
|
||||
.stub ape_ram_offset,long // Physical Offset
|
||||
.long ape_ram_memsz // Virtual Size or Physical Address
|
||||
.long ape_ram_rva // Relative Virtual Address
|
||||
.long ape_ram_filesz // Physical Size
|
||||
.long ape_ram_offset // Physical Offset
|
||||
.long 0 // Relocation Table Offset
|
||||
.long 0 // Line Number Table Offset
|
||||
.short 0 // Relocation Count
|
||||
|
|
|
@ -38,6 +38,7 @@ for x in .ape \
|
|||
.ape-1.3 \
|
||||
.ape-1.4 \
|
||||
.ape-1.5 \
|
||||
.ape-1.6 \
|
||||
.ape-blink-0.9.2 \
|
||||
.ape-blink-1.0.0; do
|
||||
rm -f \
|
||||
|
|
47
ape/loader.c
47
ape/loader.c
|
@ -698,6 +698,8 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd,
|
|||
|
||||
/* load elf */
|
||||
for (i = 0; i < e->e_phnum; ++i) {
|
||||
void *addr;
|
||||
unsigned long size;
|
||||
if (p[i].p_type != PT_LOAD) continue;
|
||||
|
||||
/* configure mapping */
|
||||
|
@ -707,38 +709,53 @@ __attribute__((__noreturn__)) static void Spawn(int os, const char *exe, int fd,
|
|||
if (p[i].p_flags & PF_W) prot |= PROT_WRITE;
|
||||
if (p[i].p_flags & PF_X) prot |= PROT_EXEC;
|
||||
|
||||
/* load from file */
|
||||
if (p[i].p_filesz) {
|
||||
void *addr;
|
||||
/* load from file */
|
||||
int prot1, prot2;
|
||||
unsigned long size;
|
||||
unsigned long wipe;
|
||||
prot1 = prot;
|
||||
prot2 = prot;
|
||||
/*
|
||||
* when we ask the system to map the interval [vaddr,vaddr+filesz)
|
||||
* it might schlep extra file content into memory on both the left
|
||||
* and the righthand side. that's because elf doesn't require that
|
||||
* either side of the interval be aligned on the system page size.
|
||||
*
|
||||
* normally we can get away with ignoring these junk bytes. but if
|
||||
* the segment defines bss memory (i.e. memsz > filesz) then we'll
|
||||
* need to clear the extra bytes in the page, if they exist.
|
||||
*
|
||||
* since we can't do that if we're mapping a read-only page, we'll
|
||||
* actually map it with write permissions and protect it afterward
|
||||
*/
|
||||
a = p[i].p_vaddr + p[i].p_filesz; /* end of file content */
|
||||
b = (a + (pagesz - 1)) & -pagesz; /* first pure bss page */
|
||||
c = p[i].p_vaddr + p[i].p_memsz; /* end of segment data */
|
||||
if (b > c) b = c;
|
||||
if (c > b && (~prot1 & PROT_WRITE)) {
|
||||
wipe = MIN(b - a, c - a);
|
||||
if (wipe && (~prot1 & PROT_WRITE)) {
|
||||
prot1 = PROT_READ | PROT_WRITE;
|
||||
}
|
||||
addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz));
|
||||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_filesz;
|
||||
rc = Mmap(addr, size, prot1, flags, fd, p[i].p_offset & -pagesz, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "prog mmap");
|
||||
if (c > b) Bzero((void *)(dynbase + a), b - a);
|
||||
if (wipe) Bzero((void *)(dynbase + a), wipe);
|
||||
if (prot2 != prot1) {
|
||||
rc = Mprotect(addr, size, prot2, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "prog mprotect");
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate extra bss */
|
||||
a = p[i].p_vaddr + p[i].p_filesz;
|
||||
a = (a + (pagesz - 1)) & -pagesz;
|
||||
b = p[i].p_vaddr + p[i].p_memsz;
|
||||
if (b > a) {
|
||||
/* allocate extra bss */
|
||||
if (c > b) {
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = Mmap((void *)(dynbase + b), c - b, prot, flags, -1, 0, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "extra bss mmap");
|
||||
}
|
||||
} else {
|
||||
/* allocate pure bss */
|
||||
addr = (void *)(dynbase + (p[i].p_vaddr & -pagesz));
|
||||
size = (p[i].p_vaddr & (pagesz - 1)) + p[i].p_memsz;
|
||||
flags |= MAP_ANONYMOUS;
|
||||
rc = Mmap((void *)(dynbase + a), b - a, prot, flags, -1, 0, os);
|
||||
rc = Mmap(addr, size, prot, flags, -1, 0, os);
|
||||
if (rc < 0) Pexit(os, exe, rc, "bss mmap");
|
||||
}
|
||||
}
|
||||
|
@ -874,7 +891,7 @@ static __attribute__((__noreturn__)) void ShowUsage(int os, int fd, int rc) {
|
|||
Print(os, fd,
|
||||
"NAME\n"
|
||||
"\n"
|
||||
" actually portable executable loader version 1.5\n"
|
||||
" actually portable executable loader version 1.6\n"
|
||||
" copyright 2023 justine alexandra roberts tunney\n"
|
||||
" https://justine.lol/ape.html\n"
|
||||
"\n"
|
||||
|
|
|
@ -65,7 +65,7 @@ ape.ident:
|
|||
.long 1
|
||||
1: .asciz "APE"
|
||||
2: .balign 4
|
||||
3: .long 105000000
|
||||
3: .long 106000000
|
||||
4: .size ape.ident,.-ape.ident
|
||||
.type ape.ident,@object
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -85,8 +85,8 @@ int sys_execve(const char *prog, char *const argv[], char *const envp[]) {
|
|||
(CanExecute((ape = "/usr/bin/ape")) ||
|
||||
CanExecute((ape = Join(firstnonnull(getenv("TMPDIR"),
|
||||
firstnonnull(getenv("HOME"), ".")),
|
||||
".ape-1.5", buf))) ||
|
||||
CanExecute((ape = Join(firstnonnull(getenv("HOME"), "."), ".ape-1.5",
|
||||
".ape-1.6", buf))) ||
|
||||
CanExecute((ape = Join(firstnonnull(getenv("HOME"), "."), ".ape-1.6",
|
||||
buf))))) {
|
||||
shargs[0] = ape;
|
||||
shargs[1] = "-";
|
||||
|
|
|
@ -317,7 +317,9 @@ static void showpeheader(struct NtImageNtHeaders *pe) {
|
|||
printf("\n");
|
||||
showpeoptionalheader(pecheckaddress(mz, mzsize, &pe->OptionalHeader,
|
||||
pe->FileHeader.SizeOfOptionalHeader));
|
||||
ShowSections(pecheckaddress(mz, mzsize, pe + 1,
|
||||
ShowSections(pecheckaddress(mz, mzsize,
|
||||
(char *)(pe + 1) +
|
||||
pe->OptionalHeader.NumberOfRvaAndSizes * 8,
|
||||
pe->FileHeader.NumberOfSections *
|
||||
sizeof(struct NtImageSectionHeader)),
|
||||
pe->FileHeader.NumberOfSections);
|
||||
|
|
Loading…
Reference in a new issue