Domanda

I want to pretend that an array in C is an area of memory in a microprocessor, so I can compile some code on a PC. I've written a small program to try to get the syntax correct, but the program won't run, it either crashes or won't compile when I change the way I access the variable - it's late and I can't see why. What is wrong with this please?

// original code in microprocessor header that I need to change if I compile on the host
// BASE is simply a hex value that is later used as an address or a hex value
#define BASE (0x0000)
// used later in header like this (cannot change the way this is done)
#define OFFSET 0x0001
#define PERIPHERAL (BASE + OFFSET)
// also used like (also cannot change):
uint32_t var = PERIPHERAL | HEXMASK;

// here is how I intend to replace the uC specific code
// replace the BASE DEFINE with the next 2 lines of code:

// instead of writing to memory location, write to array of bytes instead, so declare it:    
uint8_t BASE_memory[4] = {0, 0, 0, 0};
// define BASE as hex value that can be used as drop-in replacement in either of the 2 uses shown above
#define BASE ((uint32_t)(BASE_memory))

// now test usage
// access contents of BASE_memory[0]
printf("contents of  BASE_memory[0] == %02x\n", *((uint32_t *)(BASE)));


// now I want to access PERIPHERAL, the second element of the array, i.e. BASE_memory[1]
printf("contents of  BASE_memory[1] == %02x\n", *((uint32_t *)(PERIPHERAL)));
È stato utile?

Soluzione

I think you are on a 64-bit system.

#include <stdint.h>

uint8_t BASE_memory[4] = {1, 2, 3, 4};

int func1()
{
    return *(uint32_t *) (uint32_t) BASE_memory;
}

int func2()
{
    return *(uint32_t *) (uintptr_t) BASE_memory;
}

Here's the assembly output for func1:

leaq    _BASE_memory(%rip), %rax
movl    %eax, %eax
movl    (%rax), %eax

Here's the assembly for func2:

movl    _BASE_memory(%rip), %eax

You can see that if you cast the address to uint32_t, then there's an extra step where the high bits are set to zero. The address is then wrong, and you get a segmentation fault. That's why you use uintptr_t or intptr_t instead of uint32_t.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top