Hello experts, I'm a beginner of embedded system development.
I have question.about difference of two code.
at first, suppose there is function like
int SomeFunction(void) {
......
return (some integer);
}
And using this function return value like these
retval = SomeFunction();
if (retval == {some Variable}) {
. . .
....
former one doesn't make any problem, but when i used like latter one.. some times, retval is not correct and some strange value remains on r0 register...;
I don't know what is problem on latter one exactly...;
Could explain what is the problem of these?
Thank you very much for reading this..... though it is written by pool english...
As you said, (because of my situation.. i can't open the assem code which makes problem.. really sorry.)
There is no big difference of two case assembly code.. but problem happen on RUNTIME. (+ second one line 16 is just my mistake.. originally line 16 must be deleted.)
In second case, I just confirm SomeFunction's return value is correct before it calls pop instruct, but, it happen when return caller (in case of above code, it is main).
so that makes me so confused, though there is no difference of assembly code but r0 value is changed.....
Thank you for ur answer.
As far as I am aware, casting the result of, or declaring a function as volatile is meaningless within the C standard; however, I believe early versions of GCC used this as an alternative to __attribute__((noreturn)), i.e. an indication that the function in question should never return, and thus the compiler could make optimisations based on this assumption.
If your compiler is implementing this functionality, then this could be the cause of the behaviour you are seeing, i.e. the compiler simply isn't expecting the function to return, and thus it isn't generating the code required to either robustly get the return value back to the caller, or to preserve any of the caller's variables while calling the "volatile" function.
Simon.
As a general observation, the compiler can not eliminate a function call without ensuring that it implements all of the side-effects that calling that function at that specific time may have produced.
As a simple example, the following code compiled without access to the body of func_one() will produce code that calls func_one() twice:
extern int func_one(void); void example1(void) { func_one(); func_one(); }
This is the case even if func_one() has no side-effects simply because the compiler has no way of knowing this.
If, however, the body of func_one() is available, then its side-effects can be inlined and the calls subsequently optimised away, e.g.:
int func_one(void) { return 0; } void example2(void) { func_one(); func_one(); }
can compile such that example() makes no calls whatsoever, and just returns, i.e. the compiler can legitimately interpret this as:
void example2(void) { }
Conversely, if we replace func_one() with func_two() which does have side-effects, then even if it is inlined the effects must remain, e.g.:
int func_two(void) { return *(volatile int*)0xE000E010u; } void example3(void) { func_two(); func_two(); }
Could be implemented by the compiler as:
void example3(void) { *(volatile int*)0xE000E010u; *(volatile int*)0xE000E010u; }
which retains all of the side-effects, but could not be optimised to a single volatile access, or an empty function.
As such, there appears to be no requirement to need to be able to mark a function as volatile.
Beyond what is specified in the C standard, some tool chains do provide the opposite feature, i.e. the ability to tell the compiler that the function either has no side-effects and/or that its return value is dependent only on the arguments passed to the function and not on global variables / volatile memory accesses. Significant care must be taken, as these can potentially produce very strange results if used incorrectly, e.g:
extern int func_two(void) __attribute__((pure)); int example4(void) { return func_two() + func_two(); }
Might be expected to perform two separate reads of 0xE000E010, add them together and return the result, however, due to erroneously marking our previous func_two() as "pure", the compiler is free to implement this as:
int example4(void) { return func_two() * 2; }
i.e., reuse the value from the first call/read, and simply multiply it be two.
I just... admire your knowledge simon...
Relly Rellay Thanks!!!!!