毫无意义地试图在不使用寄存器的情况下比较呼叫中的rsp

时间:2017-10-24 22:23:14

标签: assembly x86 x86-64 thunk

我想编写一个小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 - 即,不是堆栈上,而是模糊区域之上堆。这应该是你有红区的地方,但不是你没有的地方。

有哪些替代方案?性能和代码大小很重要。

3 个答案:

答案 0 :(得分:0)

我想一个简单的解决方案就是使用submov来调整堆栈,而不是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