0

I am using the gcc cross compiler on a windows machine for an ARM CortexA9 for a bare metal application. For direct memory mapping I need to access the address 0x8000_0000. I use the following C-Code:

#define PORTBASE_A 0x80000000 
unsigned int volatile * const portA = (unsigned int *) PORTBASE_A;
#define PORTBASE_B 0x70000000
unsigned int volatile * const portB = (unsigned int *) PORTBASE_B;
#define PORTBASE_C 0x080000000
unsigned int volatile * const portC = (unsigned int *) PORTBASE_C;

printf("Portbase_A %p \n",(unsigned int *) portA); // Portbase_A 0xffffffff80000000 
printf("Portbase_B %p \n",(unsigned int *) portB); // Portbase_B 0x70000000 
printf("Portbase_C %p \n",(unsigned int *) portC); // Portbase_C 0xffffffff80000000 
printf("%d\n", sizeof(unsigned int *));     //4    

Using printf("Portbase_A %p \n",(unsigned int *) portA); leads to the output Portbase_A 0xffffffff80000000.

Question

Why do I get 64bit address (0xffffffff80000000) despite the fact that my target machine is a 32-bit machine. I realise that in 0x8000_0000 the leading bit is a one, but why does this result in a 1-padding of 32 leading bits? Is this some sort of an artefact due to cross compilling?

Many thanks for replies.

For completeness this is a visualization of my scatter-file. scatter-file visualisation

Andrej
  • 1
  • 2
  • 1
    Can you show your command line? That's pretty weird. What does `printf("%zu\n", sizeof(unsigned int *))` say? – Carl Norum Dec 13 '19 at 18:04
  • 1
    How exactly are you compiling and linking the code? – KamilCuk Dec 13 '19 at 18:08
  • `printf("%zu\n", sizeof(unsigned int *)); // u` `printf("%d\n", sizeof(unsigned int *)); //4` 4 and u are the outputs I get for the mentioned calls – Andrej Dec 13 '19 at 18:24
  • For compiling and linking I use the ARM DS-5 SDK. – Andrej Dec 13 '19 at 18:35
  • Do you see compiler call when compiling with all the options in that SDK, when building the file? – KamilCuk Dec 13 '19 at 18:37
  • For the Arm C - Compiler: `armcc --cpu=Cortex-A9.no_neon --apcs=/hardfp --fpmode=fast --arm -Dsoc_cv_av -DPRINTF_UART -DDEFAULT_term0 -DPRINTF_FLOAT_ENABLE=1 -DDEBUG -DINFO -I" .............. `And linker is executed with: `armlink --cpu=Cortex-A9.no_neon --scatter="..._SDRAM.scat" --info=sizes --entry=alt_interrupt_vector -o` – Andrej Dec 13 '19 at 18:41
  • 1
    Oook. What would be the output of `printf("%d %d %d %d\n", sizeof(int), sizeof(long), sizeof(long long), sizeof(uintptr_t));` and `printf("%ld %lx %lld %llx\n", (long)-1, (long)-1, (long long)-1, (long long)-1);` and `printf("%s\n", _NEWLIB_VERSION )`? Are macros like `_WANT_IO_C99_FORMATS`, `_WANT_IO_LONG_LONG` and `_NANO_FORMATTED_IO` defined? – KamilCuk Dec 13 '19 at 19:50
  • 'printf("%d %d %d %d\n", sizeof(int), sizeof(long), sizeof(long long), sizeof(uintptr_t)); // 4 4 8 4 ' – Andrej Dec 14 '19 at 07:07
  • 'printf("%ld %lx %lld %llx\n", (long)-1, (long)-1, (long long)-1, (long long)-1); // -1 ffffffffffffffff -1 ffffffffffffffff' – Andrej Dec 14 '19 at 07:09

1 Answers1

0

From a standard point of view, according to C99: 6.3.2.3 quote:

5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.56)

As the result is implementation-defined, it should be described by the implementation. Ie. by the compiler. gcc documentation about implementation defined behavior of pointers says that:

The result of converting a pointer to an integer or vice versa (C90 6.3.4, C99 and C11 6.3.2.3).

A cast from pointer to integer ....

A cast from integer to pointer discards most-significant bits if the pointer representation is smaller than the integer type, extends according to the signedness of the integer type if the pointer representation is larger than the integer type, otherwise the bits are unchanged.

I assume (read as: guess) that on your platform:

  • twos complement is used represent numbers and pointers
  • int is 4 bytes
  • all pointers have 8 bytes

Both constants 0x80000000 and 0x70000000 have the type int. The pointer has 8 bytes. When you do (unsigned int *)PORTBASE_A the compiler has to cast an int variable to 8 bytes. Your compiler generates code that does twos complement sign extension, ie. the most-significant bit is repeated for all the extra bits in the extra 4 bytes when casting from int to a pointer. Because of that, the resulting value has the extra bits set to 1.

Community
  • 1
  • 1
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • But OP says his platform has 32-bit pointers. Also: https://stackoverflow.com/questions/4737798/unsigned-hexadecimal-constant-in-c – Carl Norum Dec 13 '19 at 18:05