在一些進一步的想法,我認爲這可以通過使用被調用者清除約定和手動管理我所有的返回地址來完成。它與stdcall類似,但不完全相同,因爲call/ret不能使用(?)。
僞代碼:
main:
; create stub, copy in 0x02 and &add, the resulting function pointer goes in add2
local add2 = _create_trampoline
; make the call
push [return address]
push 0x03 ;arg1
jmp add2
; the resulting stub, held on the heap somewhere
add2:
push 0x02 ;bound argument
jmp add
; var add(x,y)
add:
local x = pop
local y = pop
eax = x + y;
jmp pop
這樣,add
知道堆棧佈局爲y x [ptr]
和執行正確返回。
看起來有點激烈,失去了這個呼叫/ ret,並且功能add
的堆棧框架非常脆弱,所以我將問題打開至少24小時,希望有更好的解決方案。
編輯:在一些進一步的思考,你可以保持CDECL,來電,清理,呼叫/ RET,一切由綁定蹦牀一起返回地址,只需攜帶(只需要重挫一個寄存器,或將它移動到堆棧並返回)。
僞代碼:
main:
; create stub, copy in 0x02 and &add, the resulting function pointer goes in add2
local add2 = _magic(0x02, &add);
; make the call
push 0x03;
call add2;
add2:
ebx = pop; ;the return address goes in a temporary
push 0x02;
push ebx;
jmp add
; var add(x,y)
add:
push ebp;
mov ebp, esp;
; local variables are [ebp+8] and [ebp+12]
perform calculation into eax
leave
ret
在那裏,結果是實現綁定功能參數在堆上可執行對象,保持cdecl調用約定一個相當簡潔的技術。毫無疑問,這種方法在實施時會有問題,但我認爲這是可行的,而且效率不高。
我沒有看到序列'push parameter' +'call function'的任何問題。這是使用參數調用函數的一種相當典型的方式。我不明白返回地址的問題。函數忽略它,它們只用它來返回調用者。 –
在這種情況下使用'push'和'call',我認爲堆棧包含2,[ptr],3。原始函數add()'期待堆棧頂部有兩個int作爲參數,但已經結束使用2和[ptr] ...以及多次調用'bind()'時,返回地址都與您想要的實際參數交錯。 – mappu
如何簡單地按正確的順序推參數?順便說一句,你不能在調用之後在調用者中推送任何額外的參數,因爲'call'傳遞了控制權。所以,只需按照正確的順序排列所有參數(包括綁定的參數),然後調用。 –