Open hjl-tools opened 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.
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.
GCC will sign-extend 32 bit pointer to 64 bits:
[hjl@gnu-6 tmp]$ cat c.cc
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]$
Why?
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