Fix invalid XNU binaries generated by apelink in some edge cases (#1106)

* Fix `if...fi` generation in the generated APE shell script

A shell will fail with a syntax error on an empty `if` or `else` body.
That is, neither of these is allowed:

    # Empty `if`
    if [ ... ]; then
    fi

    # Empty `else`
    if [ ... ]; then
    ...
    else
    fi

There were two places where `apelink` could generate problematic `if`'s:

1. The XNU shell generation for aarch64 binaries when no loaders (either
   binary or source) are provided. They can't assimilate, so the resulting
   `else` body becomes empty.
   There is actually a code path guarded by the `gotsome` variable that
   inserts an extra `true` in this case, but the variable was never
   initialized, so in practice this code path didn't activate in my
   tests. This is fixed by initializing the variable.
2. The loader extraction code when no loaders are provided and XNU
   support is requested. This is fixed by adding a simliar code path
   that prevents an empty body from being generated.

* Update the apelink manual after commit d53c335

The `-s` option changed its meaning, but the docs weren't updated.
This commit is contained in:
Ivan Komarov 2024-02-23 17:11:27 +01:00 committed by GitHub
parent e72a88ea70
commit 99f0491f04
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -102,7 +102,7 @@
" - 32: freebsd\n" \
" - 64: netbsd\n" \
"\n" \
" for example, `-s 0b1110001` may be used to\n" \
" for example, `-V 0b1110001` may be used to\n" \
" produce ELF binaries that only support the\n" \
" truly open unix systems. in this case when\n" \
" a single input executable is supplied, the\n" \
@ -120,8 +120,8 @@
" also pass strings in a variety of intuitive\n" \
" supported representations. for example, bsd\n" \
" will enable freebsd+netbsd+openbsd and that\n" \
" string too is a legal input. the -s flag is\n" \
" also repeatable, e.g. `-s nt -s xnu` to use\n" \
" string too is a legal input. the -V flag is\n" \
" also repeatable, e.g. `-V nt -V xnu` to use\n" \
" the union of the two.\n" \
"\n" \
" since the support vector controls the file\n" \
@ -988,7 +988,7 @@ static void GetOpts(int argc, char *argv[]) {
if (ParseSupportVector(optarg, &bits)) {
support_vector |= bits;
} else {
Die(prog, "unrecognized token passed to -s support vector flag");
Die(prog, "unrecognized token passed to -V support vector flag");
exit(1);
}
got_support_vector = true;
@ -2036,7 +2036,7 @@ int main(int argc, char *argv[]) {
// let our shell script compile the ape loader on first run.
//
if (support_vector & _HOSTXNU) {
bool gotsome;
bool gotsome = false;
p = stpcpy(p, "else\n"); // if [ -d /Applications ]; then
// output native mach-o morph
@ -2136,6 +2136,7 @@ int main(int argc, char *argv[]) {
}
// extract the ape loader for open platforms
bool gotsome = false;
if (inputs.n && (support_vector & _HOSTXNU)) {
p = stpcpy(p, "if [ ! -d /Applications ]; then\n");
}
@ -2158,9 +2159,13 @@ int main(int argc, char *argv[]) {
"mv -f \"$t.$$\" \"$t\" ||exit\n");
p = stpcpy(p, "exec \"$t\" \"$o\" \"$@\"\n"
"fi\n");
gotsome = true;
}
}
if (inputs.n && (support_vector & _HOSTXNU)) {
if (!gotsome) {
p = stpcpy(p, "true\n");
}
p = stpcpy(p, "fi\n");
}