It's possible to write polyglot machine code, which decodes on x86 as a jump to more x86 machine code (which doesn't have to be valid ARM machine code). And if executed on ARM, it ends up executing a different part of the code.
So you'd have one small part of the machine code which can be decoded as instructions for either ISA, jumping to separate destinations depending on which.
For example, https://news.ycombinator.com/item?id=27033330 is a 4-way polyglot for x86, ARM, AArch64, and MIP(little-endian). Each different interpretation of the code branches to a different relative offset. (Before reaching any instructions that would do more than modify registers.) I googled polyglot arm x86
, there are likely others. Also related: x86-32 / x86-64 polyglot machine-code fragment that detects 64bit mode at run-time? is a polyglot for multiple modes of x86, which use the same machine-code format but different defaults for operand-size, except for 64-bit mode which changes the meaning of some opcodes.
It's not practical (or likely possible) to write an entire program this way, nor for the code to do the same things on both ISAs. If they have the same machine-code format, they're the same ISA (assuming other things are the same, like memory-ordering semantics, and a bunch of kernel stuff like interrupt handling, page tables, TLB invalidation semantics, etc.) ARM and x86 are not the same ISA, using very different machine-code formats.
Of course, normally a "fat binary" doesn't need that, you have metadata which tells the OS's program-loader which part of your program is which. (A "fat binary" being one with multiple versions of the machine code, usually compiled for different ISAs.
MacOS had this during the PowerPC to x86 transition, you could have one file that was about twice the size, but would run on either. And now they have it again with x86-64 and AArch64. When you run that executable, an x86-64 MacOS will see that there's a "slice" for x86-64, and run that part of the program the same as if it was the only thing in the executable. But an AArch64 MacOS would look for an AArch64 slice in an executable, and run it if found.
If the OS doesn't find what it's looking for, the execve
system call will return an error about invalid exec format. It won't map AArch64 machine code into memory and jump to it, on an x86-64 machine.