forked from cosimo/perl5-win32-api
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcall_asm_x86_msvc.asm
193 lines (172 loc) · 5.42 KB
/
call_asm_x86_msvc.asm
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
.386P
.model FLAT
PUBLIC @Call_asm@16
EXTRN __imp__IsDebuggerPresent@0:NEAR
IFDEF PERL_IMPLICIT_CONTEXT
EXTRN __imp__Perl_croak_nocontext:NEAR
ELSE
EXTRN __imp__Perl_croak:NEAR
ENDIF
EXTRN _bad_esp_msg:NEAR
; Function compile flags: /Ogsy
; COMDAT @Call_asm@16
_TEXT SEGMENT
_control$ = 8 ; size = 4
_retval$ = 12 ; size = 4
T_DOUBLE = 11
T_FLOAT = 10
@Call_asm@16 PROC NEAR ; COMDAT
param equ ecx
params_start equ edx
retval equ edi
; 51 : {
push ebp
mov ebp, esp
push esi
push edi
; 128 : #if (defined(_MSC_VER) || defined(BORLANDC))
; 129 : __asm {
mov esi, DWORD PTR _control$[ebp]
jmp SHORT gt_param_test
loop_body:
; 72 : param--;
sub param, 16 ; 00000010H
; 73 : p.qParam = param->q;
mov al, BYTE PTR [param+8]
; 74 : switch(param->t) {
cmp al, T_DOUBLE-1 ;T_DOUBLE and higher are 64 bit types
; -1 bc in params are --ed to remove T_VOID hole
jb SHORT push_low_dword
push_high_dword:
push DWORD PTR [param+4]
push_low_dword:
push DWORD PTR [param]
; 128 : #if (defined(_MSC_VER) || defined(BORLANDC))
; 129 : __asm {
gt_param_test:
; 52 :
; 53 : /* int iParam; */
; 54 : union{
; 55 : long lParam;
; 56 : float fParam;
; 57 : double dParam;
; 58 : /* char cParam; */
; 59 : char *pParam;
; 60 : LPBYTE ppParam;
; 61 : __int64 qParam;
; 62 : } p;
; 63 :
; 64 :
; 65 : /* #### PUSH THE PARAMETER ON THE (ASSEMBLER) STACK #### */
; 66 : /* Start with last arg first, asm push goes down, not up, so first push must
; 67 : be the last arg. On entry, if param == params_start, it means NO params
; 68 : so if there is 1 param, param will be pointing the struct after the
; 69 : last one, in other words, param will be a * to an uninit APIPARAM,
; 70 : therefore -- it immediatly */
; 71 : while(param > params_start) {
cmp param, params_start
ja SHORT loop_body
; 133 : };
; 134 : #elif (defined(__GNUC__))
; 146 : #endif /* VC VS GCC */
; 147 :
; 148 : break;
; 149 :
; 155 : }
; 156 : }
; 157 :
; 158 : /* #### NOW CALL THE FUNCTION #### */
; 159 : //todo, copy retval->t to a c auto, do switch on test c auto, switch might optimize
; 160 : //to being after the call instruction
; 161 : {
; 162 : unsigned char t = control->out;
; 163 : switch(t WIN32_API_DEBUGM( & ~T_FLAG_UNSIGNED) ) { //unsign has no special treatment here
;use no C stack *s after call, they might be corrupt on a prototype mistake
mov retval, DWORD PTR _retval$[ebp] ;edi is retval
call DWORD PTR [esi+8] ; esi is var control
movzx ecx, BYTE PTR [esi+3] ; return type, can't use eax or edx
sub ecx, T_FLOAT
je SHORT get_float
dec ecx
je SHORT get_double
; EAX EDX returner (an integer)
mov DWORD PTR [retval], eax
mov DWORD PTR [retval+4], edx
jmp SHORT cleanup
get_double:
fstp QWORD PTR [retval]
jmp SHORT cleanup
get_float:
fstp DWORD PTR [retval]
cleanup:
; 274 : {
; 275 : unsigned int stack_unwind = (control->whole_bf >> 6) & 0x3FFFC;
mov eax, DWORD PTR [esi]
shr eax, 6
and eax, 3FFFCh
; 276 : #if (defined(_MSC_VER) || defined(__BORLANDC__))
; 277 : _asm {
; 278 : add esp, stack_unwind
add esp, eax
; when C stack corruption, edi and esi will be restored with garbage
; but we dont care since we dont return to caller, also balance stack
; for ebp esp comparison later
pop edi
pop esi
; this only detects stdcall vs cdecl mistakes, and wrong num of params
; on stdcall, it does NOT detect wrong number of params for cdecl
; that is more complicated, and random to detect, the only way to detect
; it with a long security cookie infront of the stack params, and even
; then, there is no guarentee the compiler or func being called will
; assign to incoming arg stack slots (infront of the return address)
; automatically detecting a read would be very difficult, and would
; require swapping C stacks, and position a NO_ACCESS page right
; infront of C stack params, bulk88 doesnt think there is any interest
; in this idea
cmp ebp, esp
jnz SHORT bad_esp
; 279 : };
; 280 : #elif (defined(__GNUC__))
; 289 : #endif
; 290 : }
; 291 : }
;leave ; get C stack working again, if ESP is too high, doing the call
; will corrupt our retaddr or our saved esi, or caller's vars, techincally
; this leave will fix the corrupt esp problem and allow execution to
; resume
pop ebp
ret 8
bad_esp:
call DWORD PTR __imp__IsDebuggerPresent@0
test eax, eax
jnz break
push esp ;esp must be always first, since the push modifies esp, after
;sampling its value
push ebp
push OFFSET FLAT:_bad_esp_msg ;defined in C for preprocessor
IFDEF PERL_IMPLICIT_CONTEXT ;complicated but seems to work to pass C defs to
; ASM. The alternative is define a const C void * that does = to the
; Perl croak_nocontext macro, which on no-thread perl is defed to Perl_croak
call DWORD PTR __imp__Perl_croak_nocontext
ELSE
call DWORD PTR __imp__Perl_croak ;no pTHX_ in unthreaded perl, so Perl_croak_nocontext doesn't exist
ENDIF
break:
db 0Fh
db 0Bh
; an int 3 can resume exec, a ud2 cant
; no return
@Call_asm@16 ENDP
__alloca_probe PROC NEAR
neg eax
add eax, esp
and al, 0F0h ;align to 16
;add eax, 4
xchg eax, esp
;jmp dword ptr [eax] ; 0.2 us slower
mov eax, [eax]
push eax
retn
__alloca_probe ENDP
_TEXT ENDS
END