AMD64 sizeof(long) = 4? WTF?

Programming, for all ages and all languages.
zerosum
Member
Member
Posts: 63
Joined: Wed Apr 09, 2008 6:57 pm

AMD64 sizeof(long) = 4? WTF?

Post 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
zerosum
Member
Member
Posts: 63
Joined: Wed Apr 09, 2008 6:57 pm

Post 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]
User avatar
thepowersgang
Member
Member
Posts: 734
Joined: Tue Dec 25, 2007 6:03 am
Libera.chat IRC: thePowersGang
Location: Perth, Western Australia
Contact:

Post 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.
zerosum
Member
Member
Posts: 63
Joined: Wed Apr 09, 2008 6:57 pm

Post 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]
zerosum
Member
Member
Posts: 63
Joined: Wed Apr 09, 2008 6:57 pm

Post 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
Krox
Posts: 23
Joined: Fri Mar 21, 2008 3:52 am
Location: Germany

Post 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^^)
21 is only half the truth...
zerosum
Member
Member
Posts: 63
Joined: Wed Apr 09, 2008 6:57 pm

Post 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
User avatar
bluecode
Member
Member
Posts: 202
Joined: Wed Nov 17, 2004 12:00 am
Location: Germany
Contact:

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

Post 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:
zerosum
Member
Member
Posts: 63
Joined: Wed Apr 09, 2008 6:57 pm

Post 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:
User avatar
bluecode
Member
Member
Posts: 202
Joined: Wed Nov 17, 2004 12:00 am
Location: Germany
Contact:

Post 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.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post 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:
Every good solution is obvious once you've found it.
zerosum
Member
Member
Posts: 63
Joined: Wed Apr 09, 2008 6:57 pm

Post by zerosum »

Solar wrote: Yes, consider it. Especially the parenthesis telling it to calculate "1 << 63" first. :wink:
What's your point?
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post 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?
Every good solution is obvious once you've found it.
zerosum
Member
Member
Posts: 63
Joined: Wed Apr 09, 2008 6:57 pm

Post 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 ;)
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Post 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?
Every good solution is obvious once you've found it.
Post Reply