llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.63k stars 11.84k forks source link

when casting pointer to larger integer type, clang zero-extends where gcc sign-extends #20815

Open hjl-tools opened 10 years ago

hjl-tools commented 10 years ago
Bugzilla Link 20441
Version trunk
OS Linux
CC @pmatos,@zygoloid

Extended Description

There are codes like

void *Addr; ... ... (uint64_t)Addr ...

When pointer size is 32 bits and pointer value is >= 2GB, pointer value is sign-extended to 64 bits, i.e.:

(void*) 0xf0000000 -> (int) 0xf0000000 -> (int64) 0xfffffffff0000000 -> (uint64) 0xfffffffff0000000

It should be casted to uintptr_t first, (uint64_t)(uintptr_t)Addr:

(void*) 0xf0000000 -> (uint) 0xf0000000 -> (uint64) 0x00000000f0000000

hjl-tools commented 10 years ago

I was informed that "A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined." Both clang and GCC are correct.

hjl-tools commented 10 years ago

There are many codes like

lib/ExecutionEngine/RTDyldMemoryManager.cpp: if (Name == "stat") return (uint64_t)&stat; lib/ExecutionEngine/RuntimeDyld/RuntimeDyld.cpp: uint64_t AlignOffset = OffsetToAlignment((uint64_t)Addr, Align);

in llvm source tree.

hjl-tools commented 10 years ago

GCC will sign-extend 32 bit pointer to 64 bits:

[hjl@gnu-6 tmp]$ cat c.cc

include

void foo (void *p) { printf ("%llx\n", (unsigned long long) p); }

void bar (void *p) { printf ("%llx\n", (unsigned long long) (unsigned int) p); }

int main () { foo ((void ) 0xf0000000); bar ((void ) 0xf0000000); return 0; } [hjl@gnu-6 tmp]$ gcc -m32 c.cc [hjl@gnu-6 tmp]$ ./a.out fffffffff0000000 f0000000 [hjl@gnu-6 tmp]$

ec04fc15-fa35-46f2-80e1-5d271f2ef708 commented 10 years ago

Why?