欢迎任何建议/讨论!
问题实际上是简短的标题,但我会解释为什么我需要实际地址.
背景:
这些天我对缓存和多核架构着迷,现在我很好奇缓存如何影响我们的程序,在并行环境下.
在某些CPU型号(例如,我的英特尔酷睿双核T5800)中,L2缓存在核心之间共享.所以,如果程序A正在访问像物理地址那样的内存
0x00000000, 0x20000000, 0x40000000...
和程序B访问数据
0x10000000, 0x30000000, 0x50000000...
由于这些地址共享相同的后缀,因此L2缓存中的相关集将经常刷新.我们期望看到两个程序相互争斗,从内存缓慢读取数据而不是缓存,尽管它们在不同的核心中分开.
然后我想在实践中验证结果.在这个实验中,我必须知道物理地址而不是虚拟地址.但我怎么能应付这个呢?
第一次尝试:
从堆,面具吃一大块空间,并获得一定的地址.
我的CPU有一个L2缓存,大小= 2048KB,关联性= 8,因此物理地址类似于0x12340000, 0x12380000, 0x123c0000L2缓存中的第一个设置.
int HEAP[200000000]={0};
int *v[2];
int main(int argc, char **argv) {
v[0] = (int*)(((unsigned)(HEAP)+0x3fffc) & 0xfffc0000);
v[1] = (int*) ((unsigned)(v[0]) + 0x40000);
// one program pollute v[0], another polluting v[1]
}
Run Code Online (Sandbox Code Playgroud)
遗憾的是,在虚拟内存的"帮助"下,变量HEAP在物理内存中并不总是连续的.v[0]并且v[1]可能与不同的缓存集有关.
第二次尝试
访问/proc/self/mem,并尝试获取内存信息.
嗯......似乎结果仍然是关于虚拟内存.
在阅读英特尔手册时,我遇到了以下情况:
*在支持Intel 64体系结构的处理器上,IA32_SYSENTER_ESP字段和IA32_SYSENTER_EIP字段必须包含规范地址.
我不明白'规范地址'的含义......?
很想得到一个解释;)找不到任何东西@ google
谢谢
我已经用Radare2反汇编了一个C程序。在此程序内,有许多调用scanf类似于:
0x000011fe 488d4594 lea rax, [var_6ch]
0x00001202 4889c6 mov rsi, rax
0x00001205 488d3df35603. lea rdi, [0x000368ff] ; "%d" ; const char *format
0x0000120c b800000000 mov eax, 0
0x00001211 e86afeffff call sym.imp.__isoc99_scanf ; int scanf(const char *format)
0x00001216 8b4594 mov eax, dword [var_6ch]
0x00001219 83f801 cmp eax, 1 ; rsi ; "ELF\x02\x01\x01"
0x0000121c 740a je 0x1228
Run Code Online (Sandbox Code Playgroud)
这是从行传递给它scanf的字符串的地址。我假设是exectable文件中的位置,因为如果我以调试模式()重新启动Radare2,则将其替换为。"%d"lea rdi, [0x000368ff]0x000368ff"%d"r2 -d ./execlea rdi, [0x000368ff]lea rdi, [someMemoryAddress]
如果文件中lea rdi, [0x000368ff]有什么硬编码,那么在运行时指令如何更改为实际的存储器地址?
我想知道64位和32位多线程Linux进程的地址空间布局的完整细节.链接到任何描述它的文章将不胜感激.请注意,我需要了解完整的详细信息,而不仅仅是概述,因为我将直接处理它.所以我需要知道,例如,线程堆栈位于何处,堆,线程私有数据等...
我在SO上看到了很多这个问题.也许没有那么多的话......但是一次又一次地存在关于数组如何与指针不同的混淆.所以我想我会花一点时间来问这个问题.
出于本Q&A的目的,我们将假设一个32位系统,并且已声明以下内容:
char * ptr = "hello";
char arr[10] = "hello";
int iarr[10] = {0};
Run Code Online (Sandbox Code Playgroud)
这是一个问题列表,可以推测我在SO上看到的困惑.当我看到新的问题时,我会添加到我的问答清单中(其他人也可以随意,如果你发现任何错误,请纠正我!)
*(ptr)和*(arr),或ptr[0]和arr[0]给予同样的事情,为什么呢?arr和&arr同样的价值?arr+1vs &arr+1?假设我有一个SomeManager用于跟踪另一个类的实例的主类SomeClass.在SomeClass构造时,它调用一个SomeManager将指针传递给它的方法.然后SomeManager获取该指针并将其推入向量.SomeClass调用析构函数的另一个函数是SomeManager从向量中删除它的指针.
所以,我的问题是.当一个实例SomeClass通过move运算符或构造函数移动时.这是地址更改,我必须删除旧地址并添加新地址吗?
我从我读过的内容中得到了一些想法,但我不确定,我不想搞砸.
我试图理解C如何在堆栈上分配内存.我一直认为堆栈上的变量可以描述为结构成员变量,它们占用堆栈中连续的,连续的字节块.为了帮助说明我在某个地方发现的这个问题,我创建了这个小程序来重现这个现象.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void function(int *i) {
int *_prev_int = (int *) ((long unsigned int) i - sizeof(int)) ;
printf("%d\n", *_prev_int );
}
void main(void)
{
int x = 152;
int y = 234;
function(&y);
}
Run Code Online (Sandbox Code Playgroud)
看看我在做什么?假设sizeof(int)是4:我在传递的指针后面看了4个字节,因为它会int y在调用者堆栈中的位置之前读取4个字节.
它没有打印152.奇怪的是当我看下4个字节时:
int *_prev_int = (int *) ((long unsigned int) i + sizeof(int)) ;
Run Code Online (Sandbox Code Playgroud)
现在它可以工作,打印x调用者堆栈内的任何内容.为什么x地址低于y?堆栈变量是否颠倒存储?
在系统内存映射(也称为 cpu 内存映射)中,地址范围被分配给 RAM 内存范围,MMIO 用于 PCI 设备等。
让我们举一个例子,其中 RAM 的地址范围从地址 0 开始到 512MB,其中包括 DOS 兼容内存空间,从 0 开始到 1MB。
现在当我们说这 512MB 的区域将被映射到内存中时,这是否意味着 CPU 地址空间中的地址 0 将被映射到物理 RAM 中的地址 0,并且同样高达 512MB?如果不是那么映射是如何完成的?
CPU地址空间中分配的内存地址范围是否与系统中安装的RAM大小完全相等?如果不是这种情况,那么在这种情况下如何进行映射?
另外,DOS 兼容区域的内存映射将如何完成?如果使用 DOS 以外的操作系统,该区域是否会在内存中未被使用?
内存映射是否意味着当 CPU 生成从 0 到 512 MB 的地址时,只会重定向到 RAM 中?CPU 生成的任何其他地址永远不会被 MMU 定向到 RAM 中?在这种情况下,所有应用程序的地址都在 0 到 512MB 之间,以便访问内存?
我在这里考虑使用 x86 系统。
我对 C 指针如何实际引用变量的内存地址感到困惑。我可能在这里遗漏了一些东西,但是,例如,如果 int 是 32 位(如 C 中的),那么它将存储在 4 个字节中。
如果我没有记错的话,那么每个内存地址的大小往往是一个字节,因为这些通常是可寻址内存的最小单位。那么如果一个int占用4个字节,那么它不是就有4个内存地址吗?(因为它存储在 4 个 8 位内存地址上)。
如果是这样的话,那么为什么一个指针只保存一个内存地址呢?(或者更确切地说,如果它可以容纳更多内容,则在打印时仅显示一个?)。这只是存储 int 的第一个地址吗?(假设它们是连续存储的)。
我试图在网上寻找答案,但这只会导致进一步的混乱。