Home > Software engineering >  Invalid conversion from uint8_t* to uint32_t - when migrating from 32 to 64bit architecture?
Invalid conversion from uint8_t* to uint32_t - when migrating from 32 to 64bit architecture?

Time:12-18

I had a little function which converted virtual memory address to physical on a 32-bit architecture:

uint32_t VIRTBASE;

uint32_t getPhysForVirt(void* virt) {
  uint32_t offset = (uint8_t*)virt - VIRTBASE;
  return PHYSBASE   offset;
}

It compiled and worked without any single issue in last 10 years.

I've changed the compiler to build the repo for newer architectures (now with 64bit support for the first time).

Compilation fails stating

invalid conversion from ‘uint8_t*’ {aka ‘unsigned char*’} to ‘uint32_t’ {aka ‘unsigned int’} [-fpermissive]

Now, I understand the message, but I'm not sure about the necessary steps to make this compiling without errors.

I'm only sure in that I don't want to enable -fpermissive.

CodePudding user response:

You use the wrong types. C language has special types for casting pointers to integral values.

uintptr_t VIRTBASE;

uintptr_t getPhysForVirt(const void * restrict virt) {
  ptrdiff_t offset = (uintptr_t)virt - VIRTBASE;
  return PHYSBASE   offset;
}

If the rest of code is written the way as this function was - you have plenty work for Christmas.

CodePudding user response:

You are doing pointer arithmetic and casting it directly to a 32-bit unsigned integer.

On a 32-bit architecture, pointers are also 32-bit unsigned integers, so this was likely silently handled in the background.

Now, on your 64-bit architecture, you're subtracting two 64-bit pointers and storing the result in a 32-bit integer -- and therefore losing half of your address!

You probably don't actually want this function to be returning an integer at all, but rather a pointer to whatever datatype you're actually using (presumably uint8_t*, since that's explicitly stated in the function itself).

edit: Conversely, maybe you actually meant to dereference virt and subtract its value, rather than do pointer arithmetic? If so, you have the * operator in the wrong spot. Try:

  uint32_t offset = (uint8_t) *virt - VIRTBASE;

Though as another commenter pointed out, this would cause issues with dereferencing a void pointer. You'd have to cast it to something meaningful first.

  • Related