【发布时间】:2012-07-15 18:10:54
【问题描述】:
我正在实现一个简单的虚拟机,目前我正在使用运行时算法来计算单个程序对象地址作为基指针的偏移量。
我今天就这个主题问了几个问题,但我似乎无处可去。
我从第一个问题中学到了一些东西- Object and struct member access and address offset calculation - 我了解到现代处理器具有虚拟寻址功能,无需任何额外的算术周期即可计算内存偏移量。
从问题二 - Are address offsets resolved during compile time in C/C++? - 我了解到手动执行偏移时无法保证会发生这种情况。
现在应该很清楚,我想要实现的是利用硬件的虚拟内存寻址功能并从运行时卸载这些功能。
我正在使用 GCC,至于平台 - 我正在 windows 中的 x86 上进行开发,但由于它是一个 VM,我希望它能够在 GCC 支持的所有平台上高效运行。
因此,欢迎提供有关该主题的任何信息,我们将不胜感激。
提前致谢!
编辑:关于我的程序代码生成的一些概述 - 在设计阶段,程序被构建为一个树层次结构,然后递归序列化为一个连续的内存块,以及索引对象并计算它们从开头的偏移量程序内存块。
编辑 2:这是虚拟机的一些伪代码:
switch *instruction
case 1: call_fn1(*(instruction+1)); instruction += (1+sizeof(parameter1)); break;
case 2: call_fn2(*(instruction+1), *(instruction+1+sizeof(parameter1));
instruction += (1+sizeof(parameter1)+sizeof(parameter2); break;
case 3: instruction += *(instruction+1); break;
案例 1 是一个带有一个参数的函数,该参数在指令之后立即找到,因此它作为指令的 1 个字节的偏移量传递。指令指针递增 1 + 第一个参数的大小以查找下一条指令。
案例 2 是一个接受两个参数的函数,和之前一样,第一个参数作为 1 字节偏移量传递,第二个参数作为 1 字节偏移量加上第一个参数的大小传递。然后指令指针会增加指令的大小加上两个参数的大小。
情况 3 是 goto 语句,指令指针增加一个偏移量,该偏移量紧跟 goto 指令。
编辑 3:据我了解,操作系统将为每个进程提供自己专用的虚拟内存寻址空间。如果是这样,这是否意味着第一个地址总是......以及零,所以从内存块的第一个字节的偏移实际上就是这个元素的地址?如果内存地址专用于每个进程,并且我知道我的程序内存块的偏移量以及每个程序对象相对于内存块第一个字节的偏移量,那么对象地址是否在编译时解析?
问题是那些偏移量在编译 C 代码期间不可用,它们在“编译”阶段和转换为字节码时被知道。这是否意味着没有办法为“free”做对象内存地址计算?
这是如何在 Java 中完成的,例如,只有虚拟机被编译为机器代码,这是否意味着对象地址的计算会因为运行时算法而降低性能?
【问题讨论】:
-
这不是一个真正的问题吗?或者也许“这不是一个真正的问题吗?”也不是一个真正的问题?
-
一方面,您混合了一堆不同的问题。 CPU 能够非常有效地计算地址偏移量。但这与虚拟寻址无关,它处理的是完全不同的问题(主要是为每个进程提供自己的地址空间,并与内存碎片作斗争)。你关于地址偏移是否在编译时解决的问题是完全不同的事情再次。同样,处理器可以非常有效地计算地址,但这发生在运行时,而不是编译时。这可能就是为什么有人投票关闭
-
只是不清楚您要做什么,您对 CPU 和编译器的期望,以及您知道什么和假设什么。但是,我认为您正在寻找的代码生成方式是
lea指令,它可以计算诸如x[y].z之类的地址(即偏移一个操作数的某个倍数,加上一个恒定的偏移量)在单个周期(IIRC)中。如果您自己生成代码,请使用它来计算地址偏移量。如果你依赖于一些现有的编译器,你只需要相信它会正确地完成它的工作。 :) -
这还不是很清楚。虚拟地址映射是由硬件(通常)完成的,与计算结构的偏移量等无关。您能否添加一个您希望优化的具体示例?
-
但要回答标题中的问题:“你不能,除非你有时光机”。如何将常数添加到未知值?您知道编译时的偏移量,但您不知道应该添加它的指针值。那么如何将两者相加呢?您必须等到您真正知道要加在一起的两个值。
标签: c++ c offset virtual-memory addressing