Skip to content

Commit 7d31fc3

Browse files
authored
Loaders rewrite argv[0] for old binaries (#1170)
For this to work, a loader has to be able to tell the difference between an ‘old’ and a ‘new’ binary. This is achieved via a repurposing of ELF’s e_flags field. We previously tried to use the padding in e_ident for it, but binutils was resetting it to zero in e.g. strip. This introduces one new ELF flag for cosmopolitan binaries. It is called `EF_APE_MODERN`. We choose 0x101ca75, "lol cat 5". It should now be safe to install the ape loader binfmt registration with the `P` flag.
1 parent 57c0b06 commit 7d31fc3

File tree

5 files changed

+27
-3
lines changed

5 files changed

+27
-3
lines changed

ape/ape-m1.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ struct Syslib {
146146
#define AT_RANDOM 25
147147
#define AT_EXECFN 31
148148

149+
#define EF_APE_MODERN 0x101ca75
150+
#define EF_APE_MODERN_MASK 0x1ffffff
151+
149152
#define AUXV_WORDS 31
150153

151154
/* from the xnu codebase */
@@ -799,7 +802,7 @@ __attribute__((__noreturn__)) static void Spawn(const char *exe, int fd,
799802
}
800803

801804
static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
802-
const char *exe, int fd, long *sp, long *auxv,
805+
char *exe, int fd, long *sp, long *auxv,
803806
char *execfn) {
804807
long i, rc;
805808
unsigned size;
@@ -820,6 +823,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
820823
if (e->e_machine != EM_AARCH64) {
821824
return "couldn't find ELF header with ARM64 machine type";
822825
}
826+
if ((e->e_flags & EF_APE_MODERN_MASK) != EF_APE_MODERN && sp[0] > 0) {
827+
/* change argv[0] to resolved path for older binaries */
828+
((char **)(sp + 1))[0] = exe;
829+
}
823830
if (e->e_phentsize != sizeof(struct ElfPhdr)) {
824831
Pexit(exe, 0, "e_phentsize is wrong");
825832
}

ape/ape.S

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ ape_mz:
196196
.quad ape_elf_entry // 18: e_entry
197197
.quad ape_elf_phoff // 20: e_phoff
198198
.quad ape_elf_shoff // 28: e_shoff
199-
.long 0 // 30: e_flags
199+
.long 0x101ca75 // 30: ape e_flags
200200
.short 64 // 34: e_ehsize
201201
.short 56 // 36: e_phentsize
202202
.short ape_elf_phnum // 38: e_phnum
@@ -669,7 +669,7 @@ apesh: .ascii "\n@\n#'\"\n" // sixth edition shebang
669669
.shstub ape_elf_entry,8 // 18: e_entry
670670
.shstub ape_elf_phoff,8 // 20: e_phoff
671671
.shstub ape_elf_shoff,8 // 28: e_shoff
672-
.ascii "\\0\\0\\0\\0" // 30: e_flags
672+
.ascii "\\165\\312\\1\\1" // 30: ape e_flags
673673
.ascii "\\100\\0" // 34: e_ehsize
674674
.ascii "\\070\\0" // 36: e_phentsize
675675
.shstub ape_elf_phnum,2 // 38: e_phnum

ape/loader.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@
152152
#define PR_SET_MM 35
153153
#define PR_SET_MM_EXE_FILE 13
154154

155+
#define EF_APE_MODERN 0x101ca75
156+
#define EF_APE_MODERN_MASK 0x1ffffff
157+
155158
#define READ32(S) \
156159
((unsigned)(255 & (S)[3]) << 030 | (unsigned)(255 & (S)[2]) << 020 | \
157160
(unsigned)(255 & (S)[1]) << 010 | (unsigned)(255 & (S)[0]) << 000)
@@ -834,6 +837,10 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
834837
return "couldn't find ELF header with x86-64 machine type";
835838
}
836839
#endif
840+
if ((e->e_flags & EF_APE_MODERN_MASK) != EF_APE_MODERN && sp[0] > 0) {
841+
/* change argv[0] to resolved path for older binaries */
842+
((char **)(sp + 1))[0] = exe;
843+
}
837844
if (e->e_phentsize != sizeof(struct ElfPhdr)) {
838845
Pexit(os, exe, 0, "e_phentsize is wrong");
839846
}

libc/elf/def.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@
8585
#define EM_RISCV 243
8686
#define EM_BPF 247
8787

88+
/* the ape flag, "lol cat 5" */
89+
#define EF_APE_MODERN 0x101ca75
90+
#define EF_APE_MODERN_MASK 0x1ffffff
91+
8892
#define GRP_COMDAT 1
8993
#define STN_UNDEF 0
9094

tool/build/fixupobj.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,11 @@ static void UseFreebsdOsAbi(void) {
327327
elf->e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
328328
}
329329

330+
static void WriteApeFlags(void) {
331+
/* try to be forward-compatible */
332+
elf->e_flags = (elf->e_flags & ~EF_APE_MODERN_MASK) | EF_APE_MODERN;
333+
}
334+
330335
/**
331336
* Improve GCC11 `-fpatchable-function-entry` codegen.
332337
*
@@ -668,6 +673,7 @@ static void FixupObject(void) {
668673
UseFreebsdOsAbi();
669674
}
670675
if (elf->e_type != ET_REL) {
676+
WriteApeFlags();
671677
PurgeIfuncSections();
672678
RelinkZipFiles();
673679
}

0 commit comments

Comments
 (0)