将MPX边界寄存器中的值提取到通用寄存器中

Mat*_*ole 1 assembly x86-64 intel

Intel的存储器保护扩展提供了四个新的128位界定寄存器,BND0BND3每个存储对64位下界(LB)和上界(UB)的缓冲液中的值.

如何提取下界的64位值(即%BND0[0-63]进入64位通用寄存器(即%RAX))?

据我所知,问题在于英特尔的指令集没有提供直接执行此操作的方法.我已经查阅了英特尔的MPX支持指南(参见本链接底部的下载),发现有一条BNDMOV b/m, b指令可以将边界寄存器中的下界和上界存储到存储器或其他寄存器中.但是看起来另一个寄存器必须是一个边界寄存器本身,因为它不可能将128位边界寄存器装入64位通用寄存器.

另外,据我所知,通过使用半宽同级寄存器(即%EAX包含下半部分的值),无法从边界寄存器中获得下限%RAX.同样,没有寻址%BND#.LB,即使无花果.14 on pg." MPX启用指南"中的50个显示了一个监视这些值的调试器.

Mar*_*oom 5

这是一个实验性解决方案,我手头没有带MPX支持的CPU.
我的工作纯粹是理论上的,我不知道由于真正的硬件上有些狡辩,它是否会失败.


正如Igor所说,完全回答没有指令在bnd不通过内存的情况下读取寄存器.
这就是故事的结局.

由于Mattew表达了他对溢出bnd寄存器值的担忧,我通过间接方式读取bnd寄存器.

该行的底部是由于它们的性质,MPX让程序员对寄存器的值执行二分法搜索bnd.

我将bndcl在整个答案中作为参考.对于bndcu一种补码格式的考虑,双重性是相似的.

bndcl如果寄存器下限LB的值高于测试的地址A,则该指令产生异常#BR.
所需要的是将条件A <LB和A≥LB转换为寄存器或标志中的数值.
基本上,如果可用且可访问,bndstatus寄存器的字段EC(错误条件)就是我们要寻找的:如果bndcl失败则为1 ,否则为0.
或者,可以bndcl通过将变量/寄存器设置为1来处理#BR异常(或操作系统仅作为#BF和#UD生成的任何异常).如果在执行之前重置所述寄存器,bndcl则它将反映检查的结果.
必须注意作为rip违规bndcl指令的要点.

长话短说,需要类似的东西

 bndcl:
    A < LB ? ECX = 1 
    A ? LB ? ECX = 0 
Run Code Online (Sandbox Code Playgroud)

有了这些先决条件,我们就可以对下限的值执行二进制搜索.
有一个小警告:我们不能测试相等,只能大于或等于.
这意味着:1)我们执行固定数量的比较(略大于64)和2)我们需要额外的最后一步来确定确切的地址.

要理解第2点)只考虑在0到15之间的数组中搜索值14和15:

       15                          14

Pivot    Step   Cmp         Pivot    Step   Cmp
 8        4      ?           8        4      ?
 12       2      ?           12       2      ?
 14       1      ?           14       1      ? (Can't stop here)
 15       0      ?           15       0      ?
Run Code Online (Sandbox Code Playgroud)

我的CPU不支持MPX,所以我假设存在一个bndclex执行上述检查bndcl和设置的宏ecx.

;Get the bnd0 lower bound without storing it into memory
;It uses a dichotomy search

get_bnd0_lb: 
 mov rax, 4000_0000_0000_0000h  ;Half-range
 lea rbx, [rax*2]               ;Address to check


_check:

 ;D O   T H E   B O U N D    C H E C K 

 bndclex _bnd0, rbx

 ;ecx = 01 if rbx < bnd0.lb
 ;ecx = 00 if rbx >= bnd0.lb

 ;S E T   T H E   C F 

 not ecx
 shr ecx, 1                     ;CF = 0   IF rbx < bnd0.lb
                                ;     1   IF rbx >= bnd0.lb

 ;A D D / S U B   T H E   H A L F   R A N G E 

 sbb rcx, rcx           ;rcx =  0 IF rbx < bnd0.lb
                                ;      -1 IF rbx >= bnd0.lb

 sub rbx, rcx                   ;rbx = rbx     IF rbx < bnd0.lb
                                ;      rbx +1  IF rbx >= bnd0.lb

 xor rcx, rax                   ;rcx = rax     IF rbx < bnd0.lb
                                ;      NOT rax IF rbx >= bnd0.lb

 add rbx, rcx                   ;rbx = rbx + rax      IF rbx < bnd0.lb
                                ;      rbx + NOT rax + 1 
                                ;    = rbx + (-rax)   IF rbx >= bnd0.lb

 shr rax, 1                     ;Halve half-range
jnz _check

 ;C H  E C K    T H E   E X A C T   A D D R E S S

 bndclex _bnd0, rbx

 ;ecx = 01 if rbx < bnd0.lb
 ;ecx = 00 if rbx >= bnd0.lb

 lea rax, [rbx + rcx]

 ret 
Run Code Online (Sandbox Code Playgroud)

该算法通过将初始枢轴P 0设置为64位地址范围的一半并且初始S 0步长等于地址范围的1/4来工作.
然后在每一步,它将枢轴移动到P i + 1 = P i ±S i并将步骤S i + 1 = S i/2 减半.

该算法将bnd寄存器下限中的零个数泄漏为生成的异常数,但不将该值存储在内存中.
可以生成合成的#BR异常来解决这个问题.


bndclex宏观的实施- 或者更好地消除宏观 - 留给了OP,因为它在很大程度上取决于环境.
我很简单

%macro bndclex 2

 xor ecx, ecx           ;RCX = 0
 lea r8, [rcx+1]        ;r8 = 0

 cmp %2, QWORD [REL %1 %+ .lb]            
 cmovb rcx, r8          ;RCX = 1 if %2 < lower bound

%endmacro
Run Code Online (Sandbox Code Playgroud)

  • 至于测试 - 英特尔SDE支持MPX:https://software.intel.com/en-us/articles/intel-software-development-emulator (2认同)