In the meantime you have 2 options. The first is to use POSIX and then call POSIX::_exit. This will skip all DESTROY and END blocks. The other is to make the following module the very first thing that you use. It will fix this bug.
\npackage FixExit;\nmy $exit_value;\nEND {\n$? = $exit_value if defined($exit_value);\n}\n\nsub my_exit {\n$exit_value = shift;\nCORE::exit();\n}\n\n*CORE::GLOBAL::exit = &my_exit;\n
(The latter is probably the best solution.)
Cheers,
Ben
PS This is something that was changed in the 5.8 series. In 5.6 and before, exit() did not run END blocks so the question never arose. Undoubtably someone made the change, thought that overriding $? in END blocks could be useful, and nobody thought about the fact that $? is set implicitly in lots of places, leading to surprising behaviour.