File: StackCallX86.asm

package info (click to toggle)
storm-lang 0.7.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 52,028 kB
  • sloc: ansic: 261,471; cpp: 140,432; sh: 14,891; perl: 9,846; python: 2,525; lisp: 2,504; asm: 860; makefile: 678; pascal: 70; java: 52; xml: 37; awk: 12
file content (83 lines) | stat: -rw-r--r-- 2,626 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
.386
.model flat, c

doStackCall PROTO C
fnCallCatch PROTO C

assume fs:nothing

.code

doStackCall proc
	;; "current" is at [ebp+8]
	;; "callOn"  is at [ebp+12]
	;; "fn"      is at [ebp+16]
	;; "fnCall"  is at [ebp+20]
	;; "member"  is at [ebp+24]
	;; "result"  is at [ebp+28]

	;; We can trash eax, ecx and edx

	;; Prolog. Saves ebp
	push ebp
	mov ebp, esp

	;; Store the stack description in the thread. Note: we don't save fs:[0], as we want
	;; exceptions to be able to pass through the thread call.
	push DWORD PTR fs:[4]	; Stack base (high address)
	push DWORD PTR fs:[8] 	; Stack limit (low address)
	lea eax, [esp-4]
	push eax 		; Current stack pointer. Allows the GC to scan this stack.

	;; Store the state in the old stack description. This tells the GC to scan it using that
	;; description rather than our esp.
	mov eax, [ebp+8]
	mov [eax+8], esp 	; current.desc = esp
	mov ecx, [ebp+12]
	mov [eax+16], ecx 	; current.detourTo = callOn

	;; Switch to the other stack.
	mov eax, [ecx+8] 	; eax = callOn.desc
	mov esp, [eax]		; esp = callOn.desc->low
	mov DWORD PTR [ecx+8], 0; callOn.desc = 0

	;; We need to fix fs:[4] and fs:[8], otherwise exceptions won't work properly. It seems
	;; it is not enough to just set them to the max and min of the multiple stacks in use.
	;; That breaks exception handling. So, we fix it by catching the exception at the bottom
	;; of the original stack and re-throwing it later.
	mov edx, [eax+8]	; Load high address of the new stack
	mov fs:[4], edx 	; Set it in the TIB.
	mov edx, [eax+4] 	; Load low address...
	mov fs:[8], edx		; And set it.

	;; Now we're done with the updates of the stack, so now we can go on to call 'callRaw':
	push ebp		; Save EBP in case we get an exception thrown at us.
	push [ebp+28]		; result
	push 0			; first
	push [ebp+24]		; member
	push [ebp+16]		; fn
	push [ebp+20]		; me
	call fnCallCatch
	; add esp, 24 		; clean up the stack, we don't need to as we will replace esp anyway

	;; Now we need to switch back to the old stack. We need to be a bit careful with the
	;; order here as well. Otherwise, the GC might scan the two stack in an inconsistent
	;; state with relation to our esp.
	mov ecx, [ebp+8] 	; Load "current"
	mov DWORD PTR [ecx+16], 0; current.detourTo = 0
	mov eax, [ecx+8] 	; load current.desc.
	mov esp, [eax] 		; restore our stack pointer from current.desc->low

	;; Now, we just need to restore the fs:[4] and fs:[8], then we're ready to go!
	add esp, 4 		; "pop" the esp
	pop DWORD PTR fs:[8] 	; Stack limit
	pop DWORD PTR fs:[4] 	; Stack base

	;; Epilog. Restores ebp
	mov esp, ebp
	pop ebp
	ret

doStackCall endp

end