There are a bunch of questions here which I will try to unpack.
1. How to get its return value?
When a contract terminates in the EVM, it has a halting state, denoted
H. This halting state takes three possible values:
() when execution needs to halt without return value
- the empty set, let's call it
None when execution needs to continue
- or a list of two numbers
(offset, length) which correspond to a returning value
The convention is for
length to correspond to the bytes in memory
mem[offset, offset + length - 1] corresponding to return data.
2. Where is the return value stored?
Your question though is how does the return data get there? Well, typically the compiled contract will populate the machine memory with the required data before termination.
3. Is it necessary to use
RETURNDATACOPY is actually for the special case where one contract calls another and needs to collect the return data from that other contract. Conceptually, when another contract is called, the parent contract can access the return data in a variable called
mu_o in yellow paper notation.
The goal of
RETURNDATACOPY is to copy data from
mu_o into the current memory
mu_m so that it can be returned.
4. If it's on the stack, how to know if the contract exited because of a problem in execution?
So as discussed above, the return data is stored in memory before halting the contract. There are other ways of understanding how the contract halted, notably the halting state, exceptional halting function and others.
5. Where is the data after the call returned to the parent contract?
In memory. This is an excerpt from the definition of
CALL in the yellow paper.
As you see the output data is saved in memory and then
mu_o is introduced as a short-hand/pointer to that part in memory.