mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Make $prog.ape more reliable on Apple Silicon (#1071)
Now it doesn't matter what argv `$prog.ape` is invoked with. We just get our executable path the Apple way.
This commit is contained in:
parent
c4205f8305
commit
aa37a327ea
2 changed files with 70 additions and 81 deletions
148
ape/ape-m1.c
148
ape/ape-m1.c
|
@ -103,36 +103,39 @@ struct Syslib {
|
||||||
char *(*dlerror)(void);
|
char *(*dlerror)(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ELFCLASS32 1
|
#define ELFCLASS32 1
|
||||||
#define ELFDATA2LSB 1
|
#define ELFDATA2LSB 1
|
||||||
#define EM_AARCH64 183
|
#define EM_AARCH64 183
|
||||||
#define ET_EXEC 2
|
#define ET_EXEC 2
|
||||||
#define ET_DYN 3
|
#define ET_DYN 3
|
||||||
#define PT_LOAD 1
|
#define PT_LOAD 1
|
||||||
#define PT_DYNAMIC 2
|
#define PT_DYNAMIC 2
|
||||||
#define PT_INTERP 3
|
#define PT_INTERP 3
|
||||||
#define EI_CLASS 4
|
#define EI_CLASS 4
|
||||||
#define EI_DATA 5
|
#define EI_DATA 5
|
||||||
#define PF_X 1
|
#define PF_X 1
|
||||||
#define PF_W 2
|
#define PF_W 2
|
||||||
#define PF_R 4
|
#define PF_R 4
|
||||||
#define AT_PHDR 3
|
#define AT_PHDR 3
|
||||||
#define AT_PHENT 4
|
#define AT_PHENT 4
|
||||||
#define AT_PHNUM 5
|
#define AT_PHNUM 5
|
||||||
#define AT_PAGESZ 6
|
#define AT_PAGESZ 6
|
||||||
#define AT_BASE 7
|
#define AT_BASE 7
|
||||||
#define AT_ENTRY 9
|
#define AT_FLAGS 8
|
||||||
#define AT_UID 11
|
#define AT_FLAGS_PRESERVE_ARGV0_BIT 0
|
||||||
#define AT_EUID 12
|
#define AT_FLAGS_PRESERVE_ARGV0 (1 << AT_FLAGS_PRESERVE_ARGV0_BIT)
|
||||||
#define AT_GID 13
|
#define AT_ENTRY 9
|
||||||
#define AT_EGID 14
|
#define AT_UID 11
|
||||||
#define AT_HWCAP 16
|
#define AT_EUID 12
|
||||||
#define AT_HWCAP2 16
|
#define AT_GID 13
|
||||||
#define AT_SECURE 23
|
#define AT_EGID 14
|
||||||
#define AT_RANDOM 25
|
#define AT_HWCAP 16
|
||||||
#define AT_EXECFN 31
|
#define AT_HWCAP2 16
|
||||||
|
#define AT_SECURE 23
|
||||||
|
#define AT_RANDOM 25
|
||||||
|
#define AT_EXECFN 31
|
||||||
|
|
||||||
#define AUXV_WORDS 29
|
#define AUXV_WORDS 31
|
||||||
|
|
||||||
/* from the xnu codebase */
|
/* from the xnu codebase */
|
||||||
#define _COMM_PAGE_START_ADDRESS 0x0000000FFFFFC000ul
|
#define _COMM_PAGE_START_ADDRESS 0x0000000FFFFFC000ul
|
||||||
|
@ -322,17 +325,7 @@ static char AccessCommand(struct PathSearcher *ps, unsigned long pathlen) {
|
||||||
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
|
if (pathlen && ps->path[pathlen - 1] != '/') ps->path[pathlen++] = '/';
|
||||||
memmove(ps->path + pathlen, ps->name, ps->namelen);
|
memmove(ps->path + pathlen, ps->name, ps->namelen);
|
||||||
ps->path[pathlen + ps->namelen] = 0;
|
ps->path[pathlen + ps->namelen] = 0;
|
||||||
if (!access(ps->path, X_OK)) {
|
return !access(ps->path, X_OK);
|
||||||
if (ps->indirect) {
|
|
||||||
ps->namelen -= 4;
|
|
||||||
ps->path[pathlen + ps->namelen] = 0;
|
|
||||||
if (access(ps->path, X_OK) < 0) {
|
|
||||||
Pexit(ps->path, -errno, "access(X_OK)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char SearchPath(struct PathSearcher *ps) {
|
static char SearchPath(struct PathSearcher *ps) {
|
||||||
|
@ -358,12 +351,8 @@ static char FindCommand(struct PathSearcher *ps) {
|
||||||
ps->path[0] = 0;
|
ps->path[0] = 0;
|
||||||
|
|
||||||
/* paths are always 100% taken literally when a slash exists
|
/* paths are always 100% taken literally when a slash exists
|
||||||
$ ape foo/bar.com arg1 arg2 */
|
$ ape foo/bar.com arg1 arg2
|
||||||
if (memchr(ps->name, '/', ps->namelen)) {
|
we don't run files in the current directory
|
||||||
return AccessCommand(ps, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we don't run files in the current directory
|
|
||||||
$ ape foo.com arg1 arg2
|
$ ape foo.com arg1 arg2
|
||||||
unless $PATH has an empty string entry, e.g.
|
unless $PATH has an empty string entry, e.g.
|
||||||
$ expert PATH=":/bin"
|
$ expert PATH=":/bin"
|
||||||
|
@ -371,8 +360,8 @@ static char FindCommand(struct PathSearcher *ps) {
|
||||||
however we will execute this
|
however we will execute this
|
||||||
$ ape - foo.com foo.com arg1 arg2
|
$ ape - foo.com foo.com arg1 arg2
|
||||||
because cosmo's execve needs it */
|
because cosmo's execve needs it */
|
||||||
if (ps->literally && AccessCommand(ps, 0)) {
|
if (ps->literally || memchr(ps->name, '/', ps->namelen)) {
|
||||||
return 1;
|
return AccessCommand(ps, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* otherwise search for name on $PATH */
|
/* otherwise search for name on $PATH */
|
||||||
|
@ -382,7 +371,8 @@ static char FindCommand(struct PathSearcher *ps) {
|
||||||
static char *Commandv(struct PathSearcher *ps, const char *name,
|
static char *Commandv(struct PathSearcher *ps, const char *name,
|
||||||
const char *syspath) {
|
const char *syspath) {
|
||||||
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
|
ps->syspath = syspath ? syspath : "/bin:/usr/local/bin:/usr/bin";
|
||||||
if (!(ps->namelen = StrLen((ps->name = name)))) return 0;
|
ps->name = name;
|
||||||
|
if (!(ps->namelen = ps->indirect ? ps->indirect : StrLen(ps->name))) return 0;
|
||||||
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
|
if (ps->namelen + 1 > sizeof(ps->path)) return 0;
|
||||||
if (FindCommand(ps)) {
|
if (FindCommand(ps)) {
|
||||||
return ps->path;
|
return ps->path;
|
||||||
|
@ -861,25 +851,27 @@ static const char *TryElf(struct ApeLoader *M, union ElfEhdrBuf *ebuf,
|
||||||
auxv[7] = ebuf->ehdr.e_entry;
|
auxv[7] = ebuf->ehdr.e_entry;
|
||||||
auxv[8] = AT_PAGESZ;
|
auxv[8] = AT_PAGESZ;
|
||||||
auxv[9] = pagesz;
|
auxv[9] = pagesz;
|
||||||
auxv[10] = AT_UID;
|
auxv[10] = AT_FLAGS;
|
||||||
auxv[11] = getuid();
|
auxv[11] = M->ps.literally ? AT_FLAGS_PRESERVE_ARGV0 : 0;
|
||||||
auxv[12] = AT_EUID;
|
auxv[12] = AT_UID;
|
||||||
auxv[13] = geteuid();
|
auxv[13] = getuid();
|
||||||
auxv[14] = AT_GID;
|
auxv[14] = AT_EUID;
|
||||||
auxv[15] = getgid();
|
auxv[15] = geteuid();
|
||||||
auxv[16] = AT_EGID;
|
auxv[16] = AT_GID;
|
||||||
auxv[17] = getegid();
|
auxv[17] = getgid();
|
||||||
auxv[18] = AT_HWCAP;
|
auxv[18] = AT_EGID;
|
||||||
auxv[19] = 0xffb3ffffu;
|
auxv[19] = getegid();
|
||||||
auxv[20] = AT_HWCAP2;
|
auxv[20] = AT_HWCAP;
|
||||||
auxv[21] = 0x181;
|
auxv[21] = 0xffb3ffffu;
|
||||||
auxv[22] = AT_SECURE;
|
auxv[22] = AT_HWCAP2;
|
||||||
auxv[23] = issetugid();
|
auxv[23] = 0x181;
|
||||||
auxv[24] = AT_RANDOM;
|
auxv[24] = AT_SECURE;
|
||||||
auxv[25] = (long)M->rando;
|
auxv[25] = issetugid();
|
||||||
auxv[26] = AT_EXECFN;
|
auxv[26] = AT_RANDOM;
|
||||||
auxv[27] = (long)execfn;
|
auxv[27] = (long)M->rando;
|
||||||
auxv[28] = 0;
|
auxv[28] = AT_EXECFN;
|
||||||
|
auxv[29] = (long)execfn;
|
||||||
|
auxv[30] = 0;
|
||||||
|
|
||||||
/* we're now ready to load */
|
/* we're now ready to load */
|
||||||
Spawn(exe, fd, sp, e, p, &M->lib, M->ps.path);
|
Spawn(exe, fd, sp, e, p, &M->lib, M->ps.path);
|
||||||
|
@ -891,7 +883,7 @@ int main(int argc, char **argv, char **envp) {
|
||||||
struct ApeLoader *M;
|
struct ApeLoader *M;
|
||||||
long *sp, *sp2, *auxv;
|
long *sp, *sp2, *auxv;
|
||||||
union ElfEhdrBuf *ebuf;
|
union ElfEhdrBuf *ebuf;
|
||||||
char *p, *pe, *exe, *prog, *execfn, *shell;
|
char *p, *pe, *exe, *prog, *execfn;
|
||||||
|
|
||||||
/* allocate loader memory in program's arg block */
|
/* allocate loader memory in program's arg block */
|
||||||
n = sizeof(struct ApeLoader);
|
n = sizeof(struct ApeLoader);
|
||||||
|
@ -954,12 +946,16 @@ int main(int argc, char **argv, char **envp) {
|
||||||
M->lib.dlerror = dlerror;
|
M->lib.dlerror = dlerror;
|
||||||
|
|
||||||
/* getenv("_") is close enough to at_execfn */
|
/* getenv("_") is close enough to at_execfn */
|
||||||
execfn = argc > 0 ? argv[0] : 0;
|
execfn = 0;
|
||||||
for (i = 0; envp[i]; ++i) {
|
for (i = 0; envp[i]; ++i) {
|
||||||
if (envp[i][0] == '_' && envp[i][1] == '=') {
|
if (envp[i][0] == '_' && envp[i][1] == '=') {
|
||||||
execfn = envp[i] + 2;
|
execfn = envp[i] + 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
prog = GetEnv(envp + i + 1, "executable_path");
|
||||||
|
if (!execfn) {
|
||||||
|
execfn = prog;
|
||||||
|
}
|
||||||
|
|
||||||
/* sneak the system five abi back out of args */
|
/* sneak the system five abi back out of args */
|
||||||
sp = (long *)(argv - 1);
|
sp = (long *)(argv - 1);
|
||||||
|
@ -981,8 +977,8 @@ int main(int argc, char **argv, char **envp) {
|
||||||
sp = sp2;
|
sp = sp2;
|
||||||
|
|
||||||
/* interpret command line arguments */
|
/* interpret command line arguments */
|
||||||
if ((M->ps.indirect = argc > 0 ? GetIndirectOffset(argv[0]) : 0)) {
|
if ((M->ps.indirect = GetIndirectOffset(prog))) {
|
||||||
/* if argv[0] is $prog.ape, then we strip off the .ape and run
|
/* if called as $prog.ape, then strip off the .ape and run the
|
||||||
$prog. This allows you to use symlinks to trick the OS when
|
$prog. This allows you to use symlinks to trick the OS when
|
||||||
a native executable is required. For example, let's say you
|
a native executable is required. For example, let's say you
|
||||||
want to use the APE binary /opt/cosmos/bin/bash as a system
|
want to use the APE binary /opt/cosmos/bin/bash as a system
|
||||||
|
@ -991,13 +987,7 @@ int main(int argc, char **argv, char **envp) {
|
||||||
but it will if you say:
|
but it will if you say:
|
||||||
ln -sf /usr/local/bin/ape /opt/cosmos/bin/bash.ape
|
ln -sf /usr/local/bin/ape /opt/cosmos/bin/bash.ape
|
||||||
and then use #!/opt/cosmos/bin/bash.ape instead. */
|
and then use #!/opt/cosmos/bin/bash.ape instead. */
|
||||||
M->ps.literally = 0;
|
M->ps.literally = 1;
|
||||||
if (*argv[0] == '-' && (shell = GetEnv(envp, "SHELL")) &&
|
|
||||||
!StrCmp(argv[0] + 1, BaseName(shell))) {
|
|
||||||
execfn = prog = shell;
|
|
||||||
} else {
|
|
||||||
prog = (char *)sp[1];
|
|
||||||
}
|
|
||||||
argc = sp[0];
|
argc = sp[0];
|
||||||
argv = (char **)(sp + 1);
|
argv = (char **)(sp + 1);
|
||||||
} else if ((M->ps.literally = argc >= 3 && !StrCmp(argv[1], "-"))) {
|
} else if ((M->ps.literally = argc >= 3 && !StrCmp(argv[1], "-"))) {
|
||||||
|
|
|
@ -58,8 +58,7 @@ void SetUpOnce(void) {
|
||||||
skiptests = IsOpenbsd() || (IsXnu() && !IsXnuSilicon());
|
skiptests = IsOpenbsd() || (IsXnu() && !IsXnuSilicon());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
skiparg0 =
|
skiparg0 = !(getauxval(AT_FLAGS) & AT_FLAGS_PRESERVE_ARGV0);
|
||||||
!(IsXnuSilicon() || (getauxval(AT_FLAGS) & AT_FLAGS_PRESERVE_ARGV0));
|
|
||||||
}
|
}
|
||||||
fprintf(stderr, loaded ? "loaded\n" : "not loaded\n");
|
fprintf(stderr, loaded ? "loaded\n" : "not loaded\n");
|
||||||
if (skiptests) {
|
if (skiptests) {
|
||||||
|
|
Loading…
Reference in a new issue