[Bug c++/45265] GCC has an intermittent bug when computing the address of function parameters

rogerio at rilhas dot com gcc-bugzilla@gcc.gnu.org
Fri Aug 13 12:14:00 GMT 2010



------- Comment #34 from rogerio at rilhas dot com  2010-08-13 12:14 -------
(In reply to comment #33)

> > Not really, you could always subtract. However, far pointers gave
> > predictable addresses, just like C99 says they pointer arithmetic should.
> They didn't.  If you subtracted far pointers that pointed into different
> segment, the segment difference was ignored.  If you include real segmentation
> like on 80286, where there's no linear relationship between effective address
> and segment+offset, subtraction would have been prohibitively expensive to
> implement anyway.

That's just ignorance on your part (nothing new, I guess I'm becoming used to
that). You are saying things that you don't know. You said that without even
knowing if there were any compilers back then that didn't do what you said. You
just took your personal experience with some crappy compiler and generalized it
for everyone. Wrong.

What you don't know is that when you subtracted far pointers the compiler
generated the code to change seg16:ofs16 into abs20. What you think is
"prohibitively expensive" would come down to 4 instructions or something like
that (2 shifts, 2 additions). But lets say 10. Is that "prohibitively
expensive"?? If the user requested a pointer difference you would be happy as a
compiler developer to just not compile (or produce an incorrect difference)
instead of generating 10 machine instructions? Or 20?

A compiler should NEVER EVER EVER refuse to compile (or compile bad code)
because the resulting number of instructions is large. Your comment and opinion
thus don't deserve any respect because we are defending the way to do a bad
compiler. That claim is not just wrong, it is dumb. I'm not trying to offend
you, I'm sure you are not dumb, but you let a dumb comment slip out.

Anyway, again you are just plain wrong. The compilers I used back then did this
operation well. In those days there were no real standards that developers
would generally follow, and programmers used to rely on what they knew about a
compiler. So I guess you might have used some crappy one that failed miserably
at pointer arithmetic, and based your whole opinion that it is beller to
compile bad arithmetic or not compile at all than to add 10 instructions to the
code.

Your ignorance is in not knowing that segmented addresses were already being
abstracted to C programmers by mid-range compilers. I remember this being
already done on 8088 compilers, abstraction of the underlying hardware was
something every C compiler strived to do. No compiler I knew of didn't do an
operation correctly because it had to generate 10 instructions or 20. or a
loop. So you stated something as an absolute truth but failed to see that one
single exception would prove you wrong. So you you threw yourself head on
against the wall again.

But don't worry, I think I know your type fairly well. You will probably just
get right back up on the horse, shake it all off, forget about what you did
wrong, and start anew with some other wrong statement. I'm basing this on your
track record in our conversations, where almost 100% of your claims are wrong
or miss the point. That is just impressive. In case I'm wrong about you my
apologies.


>  And you still wouldn't get around the size limitation of ptrdiff_t that was 16bit.


What the hell are you talking about????? I personally disassembled code in the
late 80's to see how the compiler implemented 32-bit arithmetic on a 286. It
did, and it did it well. You weren't able to go beyond 16 bits in the 80's? Or
are just making this stuff up? I'm sure you are making it up, on an 8-bit PIC I
have written assembly code to do 32-bit shift-add and it uses up something like
12 instructions or so. Not hard at all. Not "prohibitive" at all.

Again: you wished you were right, but you are wrong. You think you known, but
you don't. But are you careful? No, you just keep throwing yourself against a
wall. And you don't seem to realise that that is becomming a recurring pattern
for you. Keep it up, it is fun to watch.


> And of course the subtraction of addresses of parameter is always meaningless
> in C, segmented or not, as pointed out multiple times.  With or without cdecl.


Yup, and multiple times you have been wrong. The cute C99 box you live in
doesn't let you see beyond that. But &param is not meaningless if the compiler
adheres to cdecl, I've shown that numerous times, you are just unable to see
(your bad).

operation 1 - place parameters as cdecl (try to learn something here please, it
is important that you don't run away and hide inside C99):

push param3 to address X+8 on the stack
push param2 to address X+4 on the stack
push param1 to address X on the stack
call function

function:
get address of param1: MUST BE X!!!!!
get address of param2: MUST BE X+4!!!!!
get address of param3: MUST BE X+8!!!!!

But I guess you will just keep on losing yourself here because cdecl is outside
of C99. And if you try to leave the C99 box your brain crashes and you just
have to run back inside C99 and miss the point again. And shoot out some crappy
malformed argument about why I am oh just so wrong.

Colleagues of yours did confirm it, so that "With or without cdecl" is just you
making it up, not the truth. Do you want me to quote your colleagues? I think
it would look bad on you if I did that, but I will if you like.


> Or, another one:
> > No, optimizations take away room for assumptions.
> Um, huh?  That's completely backwards.  Optimizations make _use_ of the
> assumptions/guarantees that the relevant standard gives you.


c0=get_total_instructions_from_cpu();
for(i=0; i<strlen(big_string); i++) call_big_function();
c1=get_total_instructions_from_cpu();
selected_country=c1-c0;
while(1) launch_missile_to(selected_country);

You've developed, compiled it, and everytime you ran it it always bombed my
country, and you were happy. Then you optimized and it started bombing your
country. And you didn't know why. You simply didn't know. You didn't
understand, because you believe with all your heart that the compiler is
supposed to do "functionally equivalent" code, and that that equivalency is
guaranteed. You push your brain to the max, and you strugle and you strugle and
you strugle and go up and down on C99 and there is nothing there to tell you
what went wrong!

I do understand why. The compiler will make *a number of assumptions* about
what you want to do. And most of the times it will be right to do so. One of
the assumptions that the compiler makes is that you (as a programmer) don't
care about the number of CPU instructions executed. The compiler will be right
to assume so, because 99.99999% of all programmers really don't care about the
number of instructions executed, or, in the very least, they want the number to
be as low as possible.

But there will come some guy that really needs to know the number of CPU
instructions because he needs to synchronize the something to the whatever, and
so the compiler will not generate "functionally equivalent" code.

By definition, optimized code is not equivalent. So "functionally equivalent"
is something that you just made up and defined poorly because you don't know
what the function will be. This particular function needs the number of CPU
instructions executed, so this particular function will not be optimized to
another "functionally equivalent" function.

You think you know what "functionally equivalent" because you didn't step out
of your C99 box (which doesn't specify what functions people will want to do in
the whole wide world) but that just makes you wrong and careless in your
claims. And so I keep proving you wrong very easily, because in the real world
a function is something with a meaning that you cannot possible imagine that
you know everything about.

So you should be more careful because all this is leaving a permanent record
with your name on it for everyone to see how consistently wrong you always are
and how you don't think things through before you write something. Worse, the
GCC is bound to your claims, so everyone there should help you not make such
mistakes repeatedly.

I'm one of those guys: I want to get addresses of parameters. The compiler
expects that no one cares about the addresses of parameters (and it will be
right to do so 99.9999999% of the time), so it may feel free to change those
addresses when I ask it to optimize. (it shouldn't if I explicitly used the
cdecl keyword, but unfortunatelly many programers abused it so now the compiler
cannot optimize a lot from many libraries if it doesn't ignore cdecl when
optimizing).

So it would be dumb of me to get the addresses of parameters with optimized
code, like it would be dumb for the bomber to optimize his bombing code when he
relies on the number of instructions. He should know the optimizing compiler
could change the number of instructions and so should not optimize his code. So
I know that optimizing may make code not comply to cdecl anymore and, so, the
addresses of parameters may come out wrong.

Clear enough for you now? I think I've reached the limit of what words can
express, as is all fairly obvious and I don't see why you missed it.

BTW: in my "real world" applications built with Microsoft's compilers I was
always able to optimize the variable parameters functions and the compiler
still gave me the correct addresses. To prove this you can compile the code I
sent you in MS VS 2008, with optimizations on, and confirm by yourself that it
works. I've made many variations of it over the years and it never failed me,
so much so I trust it implicitly these days.

Maybe Microsoft has special code in the optimizing compiler to handle the
specific case of variable parameter arguments in a cdecl-conformat way always,
who knows? Or maybe they suspected that those types of functions could likelly
be used by users to access parameters directly and so they needed to respect
cdecl even when optimized.

So, the conclusion, is that MS made the right option to, at least, not mess up
cdecl in variable argument functions, and another right option of not
optimizing if the user didn't request it. By comparison GCC made zero good
options here.


> > Drink something with vitamins and get out more, it will do you good.
> That is certainly a good advise.  I OTOH would advise you to possibly drink
> more alcohol.  Much more.  Really much much more.


Why? So that we can be on the same page?? No, not me, I don't want to write
nonsense on the web, I prefer to be clear headed. One never knows when stuff
one wrote on the net will come back and bite one in the ass!!


> > Go and read C99 about the "far" qualifier so that you can see why it was
> > not smart of you to talk about DOS.
> C99 doesn't mention such qualifiers.


Exactly. Don't tell me you went there looking for it!! I was being sarcastic as
a short way to tell you that you were on your own for this discussion, C99
would not help you.


>  I said that the restrictions in the
> standard (in this case which pointers can be compared/subtracted) have their
> reason in wanting to support all imaginable memory models.


And in your mind a C standard cannot abstract from a sgmented memory model.
Right. I know what you think, I'm just glad it is not true, as it is very
confortable for me to have compilers abstract me from the underlying
architecture and always return valid and correct pointer diferences no matter
what. I'll keep on trying out compilers and platforms and will let you when I
find one combination of those that does what you say. I will then throw it
away, as a piece of crap that it will be, but I'll come back to let you know
that I found one.


>  Nevertheless
> those restriction apply to _all_ implementations, even those that have trivial
> memory models, like a flat address space.


Just to make sure you leave a useful contribution to the world (and because you
already lost track of the original issue) please tell me:

char* p1=(char*)0x3000; // address not pointing to any "C-object in the C99
sense"

char* p2=(char*)0x4000; // address not pointing to any "C-object in the C99
sense"

Can GCC users trust that p2-p1 will always return a predictable and well
defined integer value of 0x1000 on any platform with 16-bit or more that GCC
currently supports or that will come to support in the future?

[ ] Yes
[ ] No

Please think thoroughly before you answer, as I will feel free to use your
answer as GCC-binding in any public forum I like.

As you might have guessed by the tone of this comment I was wrong to think this
would be a fun game. I'm begining to feel your comments don't deserve any
respect. I'll come back to see if you answered "yes" or "no" to the question
above. If you answered correctly I'll just leave you alone then and won't try
to backtrace our conversation to my initial comment to show you I was right
from the start about the pointer arithmetic and that you were wrong to not look
beyond C99. If you select the wrong answer you will see your name posted on a
lot of public forums binding GCC to what you said. Sorry if I crossed any lines
with you, I tried hard not to be disrespectful (but it is a very difficult
task!!).


-- 


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45265



More information about the Gcc-bugs mailing list