13

I want to assign some value (say 2345) to a memory location(say 0X12AED567). Can this be done?

In other words, how can I implement the following function?

void AssignValToPointer(uint32_t pointer, int value)
{

}
GManNickG
  • 494,350
  • 52
  • 494
  • 543
Gopinath
  • 241
  • 1
  • 2
  • 7
  • 9
    `*(int*)0x12AED567 = 2345` But you better know what you're doing... – Mysticial Feb 21 '12 at 06:04
  • better do not try unless you are sure the memory is unused – Rohit Vipin Mathews Feb 21 '12 at 06:05
  • 1
    Not only must the memory be unused for any other purpose, but it must be mapped. On *nix at least, if you try to write to an unmapped page your app segfaults and crashes. – Adam Mihalcin Feb 21 '12 at 06:13
  • Why are people upvoting the first comment? It takes a lot of assumptions to be right! @Gopinath: Are you using an operating system Is this memory address physical or virtual? – jweyrich Feb 21 '12 at 06:28
  • @jweyrich: it is physical address. – Gopinath Feb 21 '12 at 06:33
  • @Gopinath: and what's the environment you are running? Which system? – jweyrich Feb 21 '12 at 06:42
  • 1
    @jweyrich They are upvoting it because they are desktop programmers. – Lundin Feb 21 '12 at 07:53
  • @Lundin: that's one reason why they should NOT be upvoting it. Desktop applications rely on memory mapping. – jweyrich Feb 21 '12 at 08:41
  • 1
    @Mysticial post seems fine to me. Poking at explicit memory locations like this is almost unheard of in desktop apps but almost a requirement on uControllers with memory-mapped peripheral registers. So, if you have read the nighmarish user manual and made sense of the obscure, badly-explained peripheral register contents, then you know what you're doing, (sometimes, anyway). – Martin James Feb 21 '12 at 12:49

7 Answers7

18

The fact that you are asking this question kind of indicates that you're in over your head. But here you go:

*(int *)0x12AED567 = 2345;
rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • 1
    This is perfectly fine in a generic C program (although the literal should be written as `0x12AED567`). It makes no assuptions about the platform. Some OS might not allow direct addressing, but _that_ is system-specific assumptions and no concern of a general, standard C program. – Lundin Feb 21 '12 at 07:57
  • @Lundin - yes, question is tagged C, mmory, pointers. No mention of OS, CPU, platform. – Martin James Feb 21 '12 at 08:57
5

The answer depends on some factors. Is your program running on an operating system? If yes, does the OS implement memory segmentation?

If you answered yes to both questions, trying to access a memory area that is not mapped or that it doesn't have permission to write will cause a memory access violation (SIGSEGV on POSIX based systems). To accomplish that, you have to use a system specific function to map the region of memory that contains this exact address before trying to access it.

jweyrich
  • 31,198
  • 5
  • 66
  • 97
  • You are making assumptions that this runs on a specific system. As far as I know, SIGSEGV is something that only happens in POSIX-based operative systems. – Lundin Feb 21 '12 at 08:00
  • 1
    I do not assume a specific operating system. However, I assume a modern operating system implements POSIX signaling, or at least use the same terminology for its signaling - which is true for Windows. That's the reason for the question on the 1st line. – jweyrich Feb 21 '12 at 08:31
  • http://en.wikipedia.org/wiki/List_of_real-time_operating_systems. There is a whole world outside the branch of PC programming. – Lundin Feb 21 '12 at 10:12
  • Fair point :) But I'll refrain myself from discussing this any further unless OP discloses which system/environment he's using. And to whoever downvoted: if you have something to add, or even would like to fix the terminology I used, please, feel free to edit. – jweyrich Feb 21 '12 at 10:49
3

C99 standard draft

This is likely not possible without implementation defined behavior.

About casts like:

*(uint32_t *)0x12AED567 = 2345;

the C99 N1256 standard draft "6.3.2.3 Pointers" says:

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)

GCC implementation

GCC documents its int to pointer implementation at: https://gcc.gnu.org/onlinedocs/gcc-5.4.0/gcc/Arrays-and-pointers-implementation.html#Arrays-and-pointers-implementation

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.

so the cast will work as expected for this implementation. I expect other compilers to do similar things.

mmap

On Linux you can request allocation of a specific virtual memory address](How does x86 paging work?) with the first argument of mmap, man mmap reads:

If addr is NULL, then the kernel chooses the (page-aligned) address at which to create the mapping; this is the most portable method of creating a new mapping. If addr is not NULL, then the kernel takes it as a hint about where to place the mapping; on Linux, the kernel will pick a nearby page boundary (but always above or equal to the value specified by /proc/sys/vm/mmap_min_addr) and attempt to create the mapping there. If another mapping already exists there, the kernel picks a new address that may or may not depend on the hint. The address of the new mapping is returned as the result of the call.

So you could request for an address and assert that you got what you wanted.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
2

Just treat the memory location as a pointer

int* pMemory =  OX12AED567;
*pMemory = 2345;

Note: This will only work if that memory location is accessible and writable by your program. Writing to an arbitrary memory location like this is inherently dangerous.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • That would cause a `SIGSEGV` if this memory region is not mapped. – jweyrich Feb 21 '12 at 06:09
  • 1
    if the address is not in the range of the process memory, won't it crash? – Gopinath Feb 21 '12 at 06:12
  • 1
    @Gopinath it's implementation dependent but generally speaking yes it will crash. – JaredPar Feb 21 '12 at 06:13
  • @jweyrich I'm pretty sure there is no such thing as SIGSEGV on any embedded system in the world. I'm fairly sure there is no such thing in 90% of all operative systems either. – Lundin Feb 21 '12 at 08:02
  • 1
    @Lundin: I do not know whether OP is talking about embedded systems or not. Do you? [SIGSEGV](http://en.wikipedia.org/wiki/SIGSEGV) is used by all Unix/Linux I know. It's defined by POSIX, and is also adopted by Microsoft on its operating system. And these represent more than 90% of all existing OSs, as far as I know. – jweyrich Feb 21 '12 at 08:19
1

As far as C is concerned, that's undefined behaviour. My following suggestion is also undefined behaviour, but avoids all the type-based and aliasing-based problems: Use chars.

int a = get_value();
char const * const p = (const char * const)&a;
char * q = (char *)0x12345;

memcpy(q, p, sizeof(int));

Alternatively, you can access bytes q[i] directly. (This is the part that is UB: the pointer q was not obtained as the address-of an actual object or as the result of an allocation function. Sometimes this is OK; for instance if you're writing a free-standing program that runs in real mode and accesses the graphics hardware, you can write to the graphics memory directly at a well-known, hard-coded address.)

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
1

You've indicated, that the address is a physical address, and that your code is running in a process.

So if you're

  1. in kind of high level operating system, e.g. Linux, you'd have to get a mapping into the physical address space. In Linux, /dev/mem does that for you.

  2. within the kernel or without operating system and with a MMU, you have to translate the physical address into a virtual address. In the Linux kernel, phys_to_virt() does that for you. In the kernel, I assume, this address is always mapped.

  3. within the kernel or without operating system and without MMU, you write directly to that address. There's no mapping to consider at all.

Now, you have a valid mapping or the physical address itself, that you pass to your function.

void AssignValToPointer(uint32_t pointer, int value)
{
    * ((volatile int *) pointer) = value;
}

You might want to add the volatile keyword as the compiler might optimize the write-operation away if you do not read from that location afterwards (likely case when writing to a register of a memory-mapped hardware).

You might also want to use the uintptr_t data type instead of uint32_t for the pointer.

svenfx
  • 501
  • 3
  • 5
0

With the proviso that it's not portable or safe (at all):

*((int *)0x12AED567) = 2345;
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111