我想编写一个小thunk,它将调用底层函数,然后在调用之前和之后比较rsp
的值。关键的是,这段代码不应该破坏任何寄存器。
明显的实现是在调用之前简单地push rsp
,然后进行比较。问题是push rsp
本身会从堆栈中减去8,因此您应该将保存的rsp
值与调用加上8 之后的值进行比较。
这是一种方法:
foo_thunk:
push rsp ; save the value of rsp
call foo ; call the underlying function
add rsp, 8 ; adjust rsp by 8, popping the saved value
cmp rsp, [rsp - 8]
jne bad_rsp ; bad foo!
ret
问题是,这会访问一个高于[rsp - 8]
的值rsp
- 即,不是在堆栈上,而是模糊区域在之上堆。这应该是你有红区的地方,但不是你没有的地方。
有哪些替代方案?性能和代码大小很重要。
答案 0 :(得分:0)
我想一个简单的解决方案就是使用sub
和mov
来调整堆栈,而不是push
:
foo_thunk:
sub rsp, 8 ; 16 to maintain alignment
mov [rsp], rsp ; save the value of rsp
call foo ; call the underlying function
cmp rsp, [rsp]
jne bad_rsp ; bad foo!
add rsp, 8 ; pop the stack
ret
当然,如果被调用者foo
弄乱了堆栈指针,它可能won't return到调用thunk,所以这个检查的用处有限。作为ret
之前的检查,在被叫方会更好。
原始调用者已将任何参数放在堆栈上really screwed。检查callee
也解决了这个问题。
答案 1 :(得分:0)
我从原始问题中假设你想在错误时将分支到bad_rsp之前的8 调整rsp,你可以用
foo_thunk:
sub rsp, 8
mov [rsp], rsp
call foo
cmp rsp, [rsp]
lea rsp, [rsp+8]
jne bad_rsp
ret
(当然,一旦你确定rsp没有被保留,那么可能没有必要对它进行调整,但我认为这种方法非常有用,值得一提。)
答案 2 :(得分:-2)
自我替换,只检查rsp
的低32b部分:
foo_thunk:
mov [cs:check_esp_part+2],esp
call foo ; call the underlying function
check_esp_part:
cmp esp,0x12345678
jne bad_rsp ; bad foo!
ret