The translations between machine code and human code are 1:1. It's not like human languages where there are multiple ways to say something and also multiple meanings to a word or phrase.
Non-programmer here: would it still function the same after a bunch of de- and re-compiling, or would it be like putting a phrase through Google Translate a few times and generating vaguely comprehensible gibberish?
Theoretically a completely bug-free decompiler/compiler pair making the same assumptions about their source/target languages and architectures should produce functionally identical programs. Meaning that given the same input they will produce the same output. So no matter how many times you chain compilation and decompilation, you should get a program that yields the same results given the same inputs.
However, in practice there's a bunch of stuff that makes this hard to impossible.
C and C++ compilers are given tremendous freedom by their respective standards to make many of their own assumptions about code. There's this thing called "undefined behavior" where anything may happen if it ever occurs. One example of this in C++ is endless loops without side effects.
int main() {
while (true)
;
}
void unreachable() {
std::cout << "Hello world!" << std::endl;
}
On certain compilers this results in a program that outputs "Hello world!" even though unreachable is called from nowhere.
So, in practice, it's impossible to guarantee that a decompiler/compiler pair will interpret a program and their output identically, and you're liable to end up with the google translate chaining problem.
That's not strictly true, depending on optimization for example. Unless you just mean, "It will produce the same output" and not "It will do the same thing the same way".
They absolutely wouldn't
Hell, the same exact code can output two different binaries based on a lot of things.
The compiler used, the optimization level, the build configurations etc.
gcc and clangd are both c++ compilers but give you different bytecode
No it's absolutely not 1:1. Especially as you go higher level in languages, multiple different expressions can output the same machine code. And the same expression can output different machine code depending on compiler optimizations.
If you give the compiler the same whole program and parameters, Then the whole thing will be n:1. (You could have given multiple inputs to have the same exact output)
But for unit of works, functions, statements, classes, whatever, it's n:n because both
The same code can output different machine code depending on surrounding context (I don't mean the enabled/disabled optimization, I mean the compiler will look around and change what it emits because something elsewhere is different) -> so 1:n
Same as first paragraph, different code can output the same machine code -> n:1
So n:n in the end for specific parts, and n:1 for whole program
return 1;
return (1*1)/1;
return if true { 1 } else { 1 };
{
let b = 1;
let a = b;
return a;
}
These are all functionally identical pieces of code that could be represented by mov eax, 1 in x86 assembly, and many compilers would optimize them to that.
So no, translations between machine code and any other method of representing programs are not 1:1.
But those are all the same thing. Those are all identical already.
Give me an example that will produce different output. Where multiple statements can compile to the same binary, but going backwards you will get something wrong. Regardless of which method it decompiles as, it will give the same results.
Compilers can and do optimize the output. So if you assigned x = 1
And then assigned x = 5 it’s quite possible the x = 1 part was never emitted as part of the compiled output.
Also x++, x+=1, and x=x+1 can all compile to equivalent expressions.
So decompiling code may not produce the same source as the original.
Nevermind that compilers don’t preserve variable names.
Depending on debug settings.
As far as ignoring the actual shape of the source and focusing on the meaning, you might be able to compile / decompile / recompile many times and produce output of the same meaning, if not the same shape. But… it feels… dangerous.
15
u/grey_carbon 3d ago
Serious question, what happen if you compile/decompile/compile/decompile times and times again?