这是一个实验性解决方案,我手头没有支持 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
基本上,如果可用且可访问,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
该算法通过将初始枢轴 P0 设置为 64 位地址范围的一半和初始 S0 步长等于地址范围。
然后在每一步,它将枢轴移动到 Pi+1 = Pi ± Si 并将步长 Si+ 减半1 = Si / 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