Not able to print the absolute address of global variable address

175 Views Asked by At

Baremetal riscv gcc compiled code and linked. I can load my program at any address. firmware calls my program using pointer to my function. I am not able to print the global variables address, its printing offsets instead of absolute address. what to do? running on qemu. If I am giving fixed address to ram in memory map. I am getting correct address but without giving memory map I am getting offset as its actual absolute address. But thats not I wanted.

this is the below code

void fun() {
      __attribute__((used)) static const int lsc = 0x55; //.const
      printf("%d %x %x\n",lsc,lsc,&lsc);
}

when printing the address of local_static_const, I am getting some offset 0xd0, but not absolute address.

I randomly found out that -Wl,-mno-relax giving me correct output but if I am removing then again its giving me wrong output .i.e giving offset address. I am not able to understand why.

Note: %p is not the issue, I have changed it to %x, its working in the same way listed above.

3

There are 3 best solutions below

0
Vlad from Moscow On

It seems the problem is that you are using an incorrect conversion specifier to output a pointer. The conversion specification %x is designed to output objects of the type unsigned int that usually occupy 4 bytes while pointers in 64-bit systems occupy 8 bytes. To convert a pointer to an unsigned integer type you need to use type specification uintptr_t defined in header <stdint.h>. As a result the function printf is just even unable to access all 8 bytes using the convefrsion specification %x.

Instead try the following using conversion specifier p specially designed to output pointers

printf("%d %x %p\n",lsc,lsc, ( void * )&lsc);

An alternative approach is to include header <inttypes.h> and write

#include <inttypes.h>

//...

printf("%d %x %" PRIxPTR "\n",lsc,lsc, ( uintptr_t )( void * )&lsc);
5
chqrlie On

The printf format for pointers is %p and the address must be cast as (void *). Try this:

void fun() {
      __attribute__((used)) static const int lsc = 0x55; //.const
      printf("%d %x %p\n", lsc, lsc, (void *)&lsc);
}

If the above code prints 0x000000d0 for the third argument, that is the address of the static variable lsc, which should be part of the data segment. You say the program is loaded at a fixed address: you might want to print the address of the function fun itself to see if the text or code segment is loaded as requested.

12
John Bollinger On

As other answers have explained, you are misusing printf() by not properly type matching the other arguments with the format. The other answers don't quite say so, but it is relevant that this causes the program to exhibit undefined behavior. The C language specifications therefore provide no answer about why that erroneous program behaves as it does. For the record, the correct printf call would be:

    printf("%d %x %p\n", lsc, (unsigned int) lsc, (void *) &lsc);

Inasmuch as you have added the information that adding -Wl,-mno-relax to the compilation command causes the program to emit the output you expect, we can suppose that this may be a facet of the UB elicited by misuse of printf. The -mno-relax disables an optimization that the linker can perform to transform an absolute addressing mode into a PC-relative mode, so it is thematically linked to the actual behavior difference you observe.

It may be that switching to the correct call, above, will give you the expected output regardless of -mno-relax. At the end of the day, however, your expectation that you can obtain a representation of an absolute address that way is not supported by the language spec. Where C equates pointer values with addresses, that does not require such values to be absolute addresses in a flat address space. Historically, there have been many implementations where sometimes (or always) it isn't. The only requirement on an address in the C sense is that it can be used to access the pointed-to object during the lifetime of that object.