英特尔的内存保护扩展提供了四个新的128位边界寄存器BND0
到BND3
,每个寄存器存储一对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 显示调试器正在观看这些值。
答案 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)
显然你不能。如果您需要绑定寄存器的值,您似乎应该使用内存(BNDMOV
或BNDSTX
)。 BND0.LB
可能只是调试器符号而不是实际的寄存器。