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

时间:2017-04-19 18:15:40

标签: assembly x86-64 intel

英特尔的内存保护扩展提供了四个新的128位边界寄存器BND0BND3,每个寄存器存储一对64位下限(LB)和上限(UB) )缓冲区的值。

如何将下界的64位值(即%BND0[0-63])提取到64位通用寄存器(即%RAX)? < / p>

我理解的问题是,英特尔的指令集并没有提供直接执行此操作的方法。我已经查阅了英特尔的MPX支持指南(参见this link底部的下载),发现有BNDMOV b/m, b指令将存储边界寄存器中的下界和上界记忆或另一个记录。但是,似乎另一个寄存器必须是一个边界寄存器本身,因为它不可能将128位边界寄存器装入64位通用寄存器。

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

2 个答案:

答案 0 :(得分:5)

  

这是一个实验性解决方案,我手头没有支持MPX的CPU。
  我的工作纯粹是理论上的,我无法判断它是否会由于在真实硬件上的狡辩而失败。

作为Igor said in is complete answer,没有指令在不通过内存的情况下读取bnd寄存器 这就是故事的结局。

作为Mattew expressed his concern about spilling the value of the bnd register我通过间接方式阅读bnd寄存器。

该行的底部是由于其性质,MPX允许程序员对bnd寄存器的值执行dichotomic search

我将在此答案中使用bndcl作为参考。双重bndcu与一个补码格式的考虑相似。

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

长话短说,需要像

这样的东西
 bndcl:
    A < LB ⇒ ECX = 1 
    A ≥ LB ⇒ ECX = 0 

根据这些先决条件,我们可以对下限的值执行二进制搜索 有一个小警告:我们无法测试相等性,仅适用于大于或等于 这意味着: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      ≥

我的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 

该算法的工作原理是将初始枢轴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

答案 1 :(得分:4)

显然你不能。如果您需要绑定寄存器的值,您似乎应该使用内存(BNDMOVBNDSTX)。 BND0.LB可能只是调试器符号而不是实际的寄存器。