Page 1 of 2

AMD64 sizeof(long) = 4? WTF?

Posted: Fri Apr 11, 2008 10:23 pm
by zerosum
Hi all,

Earlier I'd written a some code for i386. It wasn't so portable.

Now I'm trying to fix it up to work with x86-64 and I'm encountering a strange problem.

Should the size of a long not be 64-bits on amd64?

At the moment, I'm testing for the sign bit by bit-shifting 1<<63 (not portable, I know). g++ is telling me that the left shift is greater than the width of the type, which is a typedef'd long. It only ceases to tell me this when I try to shift only 31 bits, indicating that sizeof(long) = 4 instead of 8.

I've tried changing my typedef's so that my 'ui64' type is a long long instead (which it shouldn't be), but g++ won't compile it saying that the 'long long' type is illegal in ISO C++ 1998.

Further to this, my printf code (which is what I'm trying to port) is borked, even though I don't think it should be, with the changes I have made. I'm trying to printf("Blah %X\n",sizeof(long)) and I'm getting '4F4249544C550020' which is clearly not the sizeof(long).

Anyone got an idea as to what's going on?

Cheers,
Lee

Posted: Fri Apr 11, 2008 10:47 pm
by zerosum
I've just compiled some test code to see what gcc is doing with regard to long's in my 64-bit code. What follows is the c code and the disassembled code:

Code: Select all

  4000b0:       55                      push   %rbp
  4000b1:       48 89 e5             mov    %rsp,%rbp
  4000b4:       b8 05 00 00 00    mov    $0x5,%eax
  4000b9:       48 83 c0 02         add    $0x2,%rax
  4000bd:       c9                      leaveq 
  4000be:       c3                      retq   

Code: Select all

int main(void) {
        register long x;
        register long y;
        x = 5;
        y = x + 2;
        return(y);
}
As you can see, it's moving 5 into eax but then adding two to rax. WTF is with that?

Cheers,
Lee[/code]

Posted: Sat Apr 12, 2008 12:48 am
by thepowersgang
As far as i know the "long" type is defined as a 32bit integer, "int" on the other hand is 32 on a 32bit machine and 64 on a 64bit machine. "long long" is a fixed 64bit integer.

Posted: Sat Apr 12, 2008 12:50 am
by zerosum
That's the opposite of everything I have read and understand. See this page for instance:
http://www.osdev.org/wiki/Long_Mode

I will modify the test code to change them to ints and see what happens.

Cheers,
Lee[/url]

Posted: Sat Apr 12, 2008 1:12 am
by zerosum
Don't mind me, I'm an idiot. Or perhaps gcc is illogical-- who knows? Consider the following code:

Code: Select all

i64 bin;
 if (bin & (1<<63))
    printf("Negative.\n");
 else
   printf("Positive.\n");
For some reason, gcc treats the 1<<63 as though it is an int, which is just wrong as far as I'm concerned. Unless there's an explicit cast, it should treat it as being of the same type as the leftmost operand.

So yes, because it treats (1<<63) as an int, that actually equates to 0.

I've now done the obvious and sizeof(long) IS 8, not 4, it's just because of that strange auto-casting behaviour that that particular code was causing a warning/error.

Cheers,
Lee

Posted: Sat Apr 12, 2008 2:22 am
by Krox
zerosum wrote:As you can see, it's moving 5 into eax but then adding two to rax
Thats easy to explain: As you can read in the AMD64 Docs, whenever you put sth in a 32Bit Regsiter, the CPU will clear the upper 32Bit. Or maybe sign-extend. But anyway, it will be at a know state. So GCC is doing this simply for code-size minimizing.

And for the (bin & (1<<63)): Every literal without suffix is treated as "int", which is 32Bit on AMD64. Use (bin & (1L<<63)) instead. (And turn on all warnings, so GCC tells you about such stuff^^)

Posted: Sat Apr 12, 2008 2:47 am
by zerosum
Fair enough... thanks for clearing that up, Krox :-)

I have -Wall -pedantic, so I saw the warning. I was trying to figure out why... took me a while, because I expected 1<<63 to work out to a long, since that's what the other operand was and I didn't explicitly cast.

Cheers,
Lee

Re: AMD64 sizeof(long) = 4? WTF?

Posted: Sat Apr 12, 2008 2:57 am
by bluecode
zerosum wrote:I've tried changing my typedef's so that my 'ui64' type is a long long instead (which it shouldn't be), but g++ won't compile it saying that the 'long long' type is illegal in ISO C++ 1998.
-Wno-long-long fixes that :wink:

Posted: Sat Apr 12, 2008 3:07 am
by zerosum
Thanks, bluecode ;-)

They say you learn something new every day, but oh, has today been a fun day.

Finally figured out why my printf function no longer works now that I'm using 64-bit code. I just assumed that all parameters would be passed on the stack, same as on x86 :lol:

Posted: Sat Apr 12, 2008 6:34 am
by bluecode
zerosum wrote:Finally figured out why my printf function no longer works now that I'm using 64-bit code. I just assumed that all parameters would be passed on the stack, same as on x86 :lol:
Yea, I also had to learn that the painfull way... you should really use the header provided by gcc. I also looked into the varargs convention for x64 and imho it is pretty unimplementable as a macro, at least far away from fun.

Posted: Mon Apr 14, 2008 1:27 am
by Solar
zerosum wrote:Or perhaps gcc is illogical-- who knows? Consider the following code:

Code: Select all

bin & (1<<63)
Yes, consider it. Especially the parenthesis telling it to calculate "1 << 63" first. :wink:

Posted: Tue Apr 15, 2008 2:30 am
by zerosum
Solar wrote: Yes, consider it. Especially the parenthesis telling it to calculate "1 << 63" first. :wink:
What's your point?

Posted: Tue Apr 15, 2008 3:51 am
by Solar
For some reason, gcc treats the 1<<63 as though it is an int, which is just wrong as far as I'm concerned. Unless there's an explicit cast, it should treat it as being of the same type as the leftmost operand.
1 is an integer literal.

63 is an integer literal.

1 << 63 yields an integer result.

Whatever type "bin" has does not have any effect on this. Why - or how - should it?

Posted: Tue Apr 15, 2008 4:56 am
by zerosum
Ahh, so the point of your post was to simply reiterate what had already been stated by Krox, but in a far more patronising manner. Very good, thanks for your input ;)

Posted: Tue Apr 15, 2008 5:20 am
by Solar
Missed the smiley, apparently. Didn't want to sound patronizing, seldom do. I pointed the finger to the "think-o" in your reasoning, partly due to a slightly allergic reaction to "tool is broken" statements. Yes, the point had been cleared before. No, I didn't really realize that. No, it's not entirely wise to post in threads you haven't read calmly and completely.

Can we retire the flamethrowers?