*Any* program exists in the context of its run-time environment, and programs make all sorts of assumptions about that environment. These assumptions are not in the code, because there is no way to write them in the code. Even if were possible, in this case, to tell the compiler at the memory at 0x8000 works as you want, then there would still be other assumptions.
At what point do you start to accept these external assumptions? Do you accept that the memory interfaces on the card work (there may be hardware errors, or occasional ram bit errors)? Do you accept that the processor works (they've been known to have bugs)? Do you accept that integer arithmetic "works" at a mathematical level (you can't prove it)?
Back here in the real world, it's fair to assume that the memory at
0x8000 works as expected. It's possible that the code will contain comments to that effect, but it might be implied by the platform in use. It should of course be clear what is going on - that's part of writing good code.
Are you happy then that "foo" is correct code, while foo2 below is not? And incidentally, does a C99 compliant compiler suddenly become non-compliant if the linker script does not provide 64k of stack space?
void foo2(void) { char buffer[10000]; bar(&buffer[999]); }
mvh.,
David