For me, the trivial C program appears to run faster than the empty file:
$ touch empty
$ chmod +x empty
$ time ./empty
real 0m0.002s
user 0m0.000s
sys 0m0.000s
$ echo "int main(){return 0;}" > trivial.c
$ gcc trivial.c -o trivial
$ time ./trivial
real 0m0.001s
user 0m0.000s
sys 0m0.000s
Timing results are consistent over several repetitions (provided everything's in cache from disk). Linux x86_64. `mov` takes ten thousand to a million times less than a millisecond ( https://gist.github.com/jboner/2841832 ), so I can't find out this way whether removing 'return 0' changes anything.
(If I use my default zsh shell to execute ./empty, it gives me
zsh: exec format error: ./empty
./empty 0.00s user 0.00s system 0% cpu 0.008 total
So here's what happens with empty. If you run it from the shell, first the shell will fork, then try to exec empty. But the exec fails, since empty doesn't begin with a magic value. Therefore the exec call returns an error. Now the shell picks up this error, and then tries to run the program again, this time as an argument to an invocation of the shell (i.e., it does an exec of /bin/bash, passing it "empty" as a parameter). This is why empty ends up taking longer to run.
This is the normal pattern, just in case you forget to put "#!/bin/bash" at the top of the script, so that the script can be run anyway. This is also a source of confusion for some sysadmins, when a script works from the command line but not from something like a cron script.
Before the system can execute any one of these programs, it has fork the bash process, call exec to load the new binary in the process memory, load the standard library and map it to the adress space, open stdin / stdout, run the program, close stdin / stdout, wait for the process termination ...
Comparing to all this, a move instruction in userland won't really make a difference.
Edit: List on system calls required to execute trivial.c (on my Linux):
(If I use my default zsh shell to execute ./empty, it gives me
So I used bash for this.)