1 个不稳定版本
0.1.0 | 2021 年 3 月 13 日 |
---|
#15 in #amd64
38KB
710 行
regmap
一些知名且公认良好的计算机架构,例如微芯科技的 PIC 产品线,或者许多 AVR 处理器系列,有幸拥有理解处理器寄存器文件与主存之间战略对齐力量的架构师。在这些架构中,将寄存器和内存访问协同起来的远见卓识降低了指令的复杂性:要加载或存储寄存器,开发人员只需要知道操作内存的指令。
不幸的是,设计 8086 的英特尔架构师没有吸取这些架构的教训,也没有将寄存器文件与主存协同。 regmap
通过允许用户将处理器的一般寄存器 (GPR) 映射到内存来解决这一设计疏忽。
将 regmap
想象成是 "填补空白的,但针对主存。
用法
调用 regmap::map_registers()
,然后使用 0 到 4096 之间的内存。你可能希望以 regmap
的形式运行 --release
;如果你使用 RegU64
并且没有积极内联像 add_assign
这样的辅助函数,结果将是不可预测的。
由于你永远不会在其他页面的内存中使用地址,你可能甚至想添加一个类似的存根
#[cfg_attr(link_section = ".init_array")]
static MAP_REGS: extern fn() = {
unsafe { regmap::map_registers(); }
};
这样,寄存器映射始终是开启的,你不会忘记在应用程序中实际运行该函数。然而,如果你是一个依赖 regmap
的库,首先,非常感谢!但是,在你的库中尝试使用 .init_array
带来许多问题。你可能会想鼓励你库的下游用户自己 regmap::map_registers()
。
regmap
的另一个有趣用法可以作为手写汇编的支持机制。只要在进程中调用了 regmap::map_registers()
,任何引用已映射寄存器的指令都将被正确解释。用户可以编写优化的汇编代码,调用 regmap::map_registers
,然后无问题地使用内存映射寄存器。
如果您打算以独立的方式(例如作为C程序中的支持库)使用regmap
,则cargo build --workspace --release
将生成一个./target/release/libregmap.a
,该文件适用于链接。
存在示例。可以使用以下命令运行examples/hello_world.rs
示例:cargo run --example hello_world --release
。要演示在Rust程序外使用regmap
,请运行make joy
,这将构建并运行examples/example.s
中的示例。
为什么
因为很有趣
如何
0页面通常被保留为不可执行不可写,因此对其的访问(通过空指针)不会导致“非常奇怪”的内存损坏。regmap
重新使用了这个4k(或更大,对于大页面,我想)区域来映射amd64寄存器文件的一部分。故障被转换为一个引用地址,指令被评估为如果它是针对指定寄存器的,然后继续执行而毫不察觉。
而不是重写指令流或生成要执行的指令,regmap
模拟了具有内存引用的指令。这意味着regmap
在处理时不需要进行任何额外分配,并且在该功能依赖的信号处理实现中相当自包含。
在哪里
regmap
目前对ucontext布局做出了一些假设,并且仅知其在Linux上正确工作。将来,这种限制可能会放宽。regmap
也不能用于执行SSE指令。这种限制也可能会在未来放宽。
错误?
regmap
可能没有错误。它只是一个与信号处理程序连接的x86反汇编器和模拟器。会发生什么错误。如果regmap
错误地模拟了指令,或者应该根据其特殊的执行环境以不同的方式模拟指令,请提交一个问题或发送电子邮件到该仓库提交时使用的电子邮件地址。
待办事项
[ ] 应处理对寄存器映射的非对齐访问。它们目前会引发恐慌。理想情况下,regmap应像从被寻址的区域形成适当大小的寄存器一样操作。[ ] 错误地模拟了非qword操作。由于RegU64
强制u64操作,regmap
不会立即受到影响,但应支持其他大小。[ ] 未处理SSE操作。如果处理了它们,它们似乎应该在GPR字节上工作。同样。
依赖关系
~8.5MB
~110K SLoC