From eeda824637cb18437ec6c5181d085f68d0efb0bd Mon Sep 17 00:00:00 2001 From: Brett Jia Date: Thu, 6 Mar 2025 11:59:29 -0500 Subject: [PATCH] Support additional architectures in apelink This updates apelink to support machine architectures not in the source program input list by adding additional loaders, extracting the correct one that matches the host uname machine. With this change, blink can be supplied as the additional loader to run the program in x86_64 VMs. The change has been verified against blink 1.0, powerpc64le and mips64el in Docker using QEMU. --- libc/elf/def.h | 1 + tool/build/apelink.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/libc/elf/def.h b/libc/elf/def.h index 913e9c930..04d69985e 100644 --- a/libc/elf/def.h +++ b/libc/elf/def.h @@ -68,6 +68,7 @@ #define EM_NONE 0 #define EM_M32 1 #define EM_386 3 +#define EM_MIPS 8 #define EM_PPC64 21 #define EM_S390 22 #define EM_ARM 40 diff --git a/tool/build/apelink.c b/tool/build/apelink.c index 862ed3f13..e7d2debc8 100644 --- a/tool/build/apelink.c +++ b/tool/build/apelink.c @@ -1630,6 +1630,20 @@ static char *GenerateScriptIfMachine(char *p, struct Input *in) { } } +static char *GenerateScriptIfLoaderMachine(char *p, struct Loader *loader) { + if (loader->machine == EM_NEXGEN32E) { + return stpcpy(p, "if [ \"$m\" = x86_64 ] || [ \"$m\" = amd64 ]; then\n"); + } else if (loader->machine == EM_AARCH64) { + return stpcpy(p, "if [ \"$m\" = aarch64 ] || [ \"$m\" = arm64 ]; then\n"); + } else if (loader->machine == EM_PPC64) { + return stpcpy(p, "if [ \"$m\" = ppc64le ]; then\n"); + } else if (loader->machine == EM_MIPS) { + return stpcpy(p, "if [ \"$m\" = mips64 ]; then\n"); + } else { + Die(loader->path, "unsupported cpu architecture"); + } +} + static char *FinishGeneratingDosHeader(char *p) { p = WRITE16LE(p, 0x1000); // 10: MZ: lowers upper bound load / 16 p = WRITE16LE(p, 0xf800); // 12: MZ: roll greed on bss @@ -2190,6 +2204,32 @@ int main(int argc, char *argv[]) { gotsome = true; } } + + // extract the ape loader for non-input architectures + for (i = 0; i < loaders.n; ++i) { + struct Loader *loader = loaders.p + i; + if (loader->used) { + continue; + } + loader->used = true; + p = GenerateScriptIfLoaderMachine(p, loader); + p = stpcpy(p, "mkdir -p \"${t%/*}\" ||exit\n" + "dd if=\"$o\""); + p = stpcpy(p, " skip="); + loader->ddarg_skip2 = p; + p = GenerateDecimalOffsetRelocation(p); + p = stpcpy(p, " count="); + loader->ddarg_size2 = p; + p = GenerateDecimalOffsetRelocation(p); + p = stpcpy(p, " bs=1 2>/dev/null | gzip -dc >\"$t.$$\" ||exit\n" + "chmod 755 \"$t.$$\" ||exit\n" + "mv -f \"$t.$$\" \"$t\" ||exit\n"); + p = stpcpy(p, "exec \"$t\" \"$o\" \"$@\"\n" + "fi\n"); + gotsome = true; + } + + // close if-statements if (inputs.n && (support_vector & _HOSTXNU)) { if (!gotsome) { p = stpcpy(p, "true\n");