繁体   English   中英

我们可以为给定的内存位置赋值吗?

[英]Can we assign a value to a given memory location?

我想为内存位置(比如 0X12AED567)分配一些值(比如 2345)。 这能做到吗?

换句话说,我如何实现以下功能?

void AssignValToPointer(uint32_t pointer, int value)
{

}

你问这个问题的事实表明你已经疯了。 但是你去吧:

*(int *)0x12AED567 = 2345;

答案取决于一些因素。 您的程序是否在现代操作系统中运行?

如果是,尝试访问未映射的内存区域将导致SIGSEGV 为此,您必须使用系统特定的函数来映射包含此确切地址的内存区域,然后再尝试访问它。

C99标准草案

如果没有实现定义的行为,这可能是不可能的。

关于演员表,如:

*(uint32_t *)0x12AED567 = 2345;

C99 N1256 标准草案“6.3.2.3 指针”说:

5 整数可以转换为任何指针类型。 除了前面指定的,结果是实现定义的,可能没有正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示。 56)

海湾合作委员会实施

GCC 将其 int 指针实现记录在: https : //gcc.gnu.org/onlinedocs/gcc-5.4.0/gcc/Arrays-and-pointers-implementation.html#Arrays-and-pointers-implementation

如果指针表示小于整数类型,则从整数到指针的转换会丢弃最高有效位,如果指针表示大于整数类型,则根据整数类型的符号进行扩展,否则位不变。

所以演员表将按预期工作。 我希望其他编译器做类似的事情。

映射

在 Linux 上,您可以使用mmap的第一个参数请求分配特定的虚拟内存地址]( x86 分页如何工作? ), man mmap读取:

如果 addr 为 NULL,则内核选择(页面对齐的)地址来创建映射; 这是创建新映射的最便携方法。 如果 addr 不为 NULL,则内核将其作为关于放置映射位置的提示; 在 Linux 上,内核将选择附近的页面边界(但始终高于或等于 /proc/sys/vm/mmap_min_addr 指定的值)并尝试在那里创建映射。 如果那里已经存在另一个映射,内核会选择一个可能取决于也可能不取决于提示的新地址。 新映射的地址作为调用结果返回。

所以你可以请求一个地址并断言你得到了你想要的。

只需将内存位置视为指针

int* pMemory =  OX12AED567;
*pMemory = 2345;

注意:这仅在您的程序可以访问和写入该内存位置时才有效。 像这样写入任意内存位置本质上是危险的。

就 C 而言,这是未定义的行为。 我的以下建议也是未定义的行为,但避免了所有基于类型和基于别名的问题:使用字符。

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

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

或者,您可以直接访问字节q[i] (这是 UB 的部分:指针q不是作为实际对象的地址或分配函数的结果获得的。有时这是可以的;例如,如果您正在编写一个独立的程序以实模式运行并访问图形硬件,您可以直接在众所周知的硬编码地址写入图形内存。)

您已经指出,该地址是一个物理地址,并且您的代码正在一个进程中运行。

所以如果你是

  1. 在某种高级操作系统中,例如 Linux,您必须获得到物理地址空间的映射。 在 Linux 中, /dev/mem 会为你做这件事。

  2. 在内核中或没有操作系统以及使用 MMU 时,您必须将物理地址转换为虚拟地址。 在 Linux 内核中, phys_to_virt() 为你做这件事。 在内核中,我假设这个地址总是被映射的。

  3. 在内核或没有操作系统和 MMU 的情况下,您可以直接写入该地址。 根本没有要考虑的映射。

现在,您有一个有效的映射或物理地址本身,您可以将其传递给您的函数。

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

您可能想要添加 volatile 关键字,因为如果您之后不从该位置读取,编译器可能会优化写操作(可能是写入内存映射硬件的寄存器时的情况)。

您可能还想使用 uintptr_t 数据类型而不是 uint32_t 作为指针。

附带条件是它不便携或不安全(根本):

*((int *)0x12AED567) = 2345;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM