On 22/09/16 17:30, Richard Biener wrote:
On September 22, 2016 5:20:56 PM GMT+02:00, paul.kon...@dell.com
wrote:
On Sep 22, 2016, at 11:16 AM, David Brown
<da...@westcontrol.com>
wrote:
On 22/09/16 16:57, paul.kon...@dell.com wrote:
On Sep 22, 2016, at 6:17 AM, David Brown
<da...@westcontrol.com>
wrote:
... Your trouble is that your two pointers, cur and end, are
pointing at different variables. Comparing two pointers that
are independent (i.e., not pointing to parts of the same
aggregate object) is undefined - the compiler can assume that
these two external objects could beanywhere in
memory, so there is no way (in pure C) for you to know or
care how they are related. Therefore it can assume that you
will never reach "cur == end".
Would making them intptr_t instead of pointers fix that?
With care, yes. But I think it still relies on gcc not being
quite
as
smart as it could be. This seems to generate working code, but
the compier could in theory still apply the same analysis:
void rtems_initialize_executive(void) { uintptr_t cur =
(uintptr_t) _Linker_set__Sysinit_begin; uintptr_t end =
(uintptr_t) _Linker_set__Sysinit_end;
I would not expect the compiler to apply pointer rules for code
like this. (u)intptr_t is an integer type; it happens to be one
whose width is chosen to match the width of pointers on the
platform in question, but that doesn't change the fact the type is
integer. For example, it is perfectly valid for an intptr_t
variable to contain values that could not possibly be pointers on
a given platform.
The compiler /can/ perform such analysis and see the undefined behaviour
of the code, and use that to optimise away the check for the loop. It
is legal to convert (by cast or initialisation) an intptr_t or uintptr_t
variable to a pointer - but it is /not/ legal to dereference it unless
the intptr_t or uintptr_t was set from a legal pointer. Thus when the
compiler is considering the validity of access through the casted
uintptr_t variable, it can look back to where the contents of that
variable came and consider those pointers. Since the compiler can
assume that incrementing one pointer repeatedly never matches the other
pointer (as they point to unrelated objects), the same applies even if
the values have been cast back and forth through intptr_t variables.
In general, I find that if you can't figure out a simple way to express
your desires for this sort of thing using fully defined standard C
behaviour, then complex methods with castings and the like will not be
entirely correct either. They might work at the moment - gcc is a smart
compiler, but it has its limits - but they might not work in the future
(as the compiler gets better all the time). Compiler-specific
workarounds like the assembly macro proposed are often the safest
methods. Alternatively, you accept a slight performance hit by using an
extra "volatile" step to limit the optimisation. Or you change the
requirements, by finding a different way to handle it - such as by
letting the linker figure out the size of the table and including it as
a readable constant.
I can't see how it could either. BTW your testcase contains another
fragility, the order of two global vars.
That is, in fact, the crux of the problem - the two linker symbols are
unrelated, so by the rules of C pointers they are incomparable as are
all pointers derived from them.