typedef struct { int x[500]; } bigthing;
bigthing MyFunction();
and a program using that library: int main() {
bigthing x = MyFunction();
}
C has no choice but to have MyFunction allocate a couple kilobytes on the stack and have main copy the structure from the stack to where it should eventually go. The equivalent Rust code, however, can pass the address of the object x to MyFunction, as if it were actually void MyFunction(bigstruct &output).If you have a #[no_mangle] but not extern function in Rust, the Rust compiler will generate code for that function that looks for this secret by-reference argument and fills it in. When you call it from C (or something that calls functions in a C-like manner, like Python's cffi), it won't be setting up the call like that at all, and it will expect to read the result off the stack like a C function would have done.
(I don't think there's a lot of use for #[no_mangle] without extern. The best I can think of is that, if you have a Rust application that dynamically loads a Rust library and runs a function from it, you don't have access to the mangling algorithm, once you find the function you'll call it according to the Rust ABI. But even that is risky since the Rust ABI can change between compiler versions; you're still better off shoveling things through the C ABI.)