[10409] | 1 | ; $Id: exceptutil.asm,v 1.26 2004-01-20 13:41:11 sandervl Exp $
|
---|
[620] | 2 |
|
---|
| 3 | ;/*
|
---|
| 4 | ; * Project Odin Software License can be found in LICENSE.TXT
|
---|
| 5 | ; * Win32 Exception handling + misc functions for OS/2
|
---|
| 6 | ; *
|
---|
| 7 | ; * Copyright 1998 Sander van Leeuwen
|
---|
| 8 | ; *
|
---|
| 9 | ; */
|
---|
| 10 | .386p
|
---|
| 11 | NAME except
|
---|
| 12 |
|
---|
[5557] | 13 | DATA32 segment dword use32 public 'DATA'
|
---|
| 14 | DATA32 ends
|
---|
| 15 | CONST32_RO segment dword use32 public 'CONST'
|
---|
| 16 | CONST32_RO ends
|
---|
| 17 | BSS32 segment dword use32 public 'BSS'
|
---|
| 18 | BSS32 ends
|
---|
| 19 | DGROUP group BSS32, DATA32
|
---|
| 20 | assume cs:FLAT, ds:FLAT, ss:FLAT, es:FLAT
|
---|
| 21 |
|
---|
| 22 | DATA32 segment dword use32 public 'DATA'
|
---|
| 23 |
|
---|
| 24 | CONST32_RO segment
|
---|
| 25 | align 04h
|
---|
| 26 | @CBE8 db "KERNEL32: Calling handle"
|
---|
| 27 | db "r at %p code=%lx flags=%"
|
---|
| 28 | db "lx",0ah,0h
|
---|
| 29 | @CBE9 db "KERNEL32: Handler return"
|
---|
| 30 | db "ed %lx",0ah,0h
|
---|
| 31 | CONST32_RO ends
|
---|
| 32 | DATA32 ends
|
---|
| 33 |
|
---|
[620] | 34 | CODE32 SEGMENT DWORD PUBLIC USE32 'CODE'
|
---|
[21916] | 35 |
|
---|
| 36 |
|
---|
[3275] | 37 | public _RaiseException@16
|
---|
[21916] | 38 | extrn _OS2RaiseException : near
|
---|
[620] | 39 |
|
---|
[3275] | 40 | _RaiseException@16 proc near
|
---|
[21916] | 41 |
|
---|
| 42 | ; _OS2RaiseException is _cdecl
|
---|
| 43 |
|
---|
[620] | 44 | push ebp
|
---|
[21916] | 45 | mov ebp, esp
|
---|
[620] | 46 | push eax
|
---|
[21916] | 47 |
|
---|
| 48 | mov eax, 0
|
---|
| 49 | mov eax, ss
|
---|
[620] | 50 | push eax
|
---|
[21916] | 51 | mov eax, gs
|
---|
[620] | 52 | push eax
|
---|
| 53 | mov eax, fs
|
---|
| 54 | push eax
|
---|
[21916] | 55 | mov eax, es
|
---|
[620] | 56 | push eax
|
---|
[21916] | 57 | mov eax, ds
|
---|
[620] | 58 | push eax
|
---|
[21916] | 59 | mov eax, cs
|
---|
| 60 | push cs
|
---|
| 61 | push esi
|
---|
| 62 | push edi
|
---|
| 63 | push edx
|
---|
| 64 | push ecx
|
---|
| 65 | push ebx
|
---|
| 66 | push dword ptr [ebp-4] ; original eax
|
---|
| 67 | pushfd
|
---|
| 68 | push dword ptr [ebp] ; original ebp
|
---|
| 69 | push ebp
|
---|
| 70 | add dword ptr [esp], 4 ; original esp
|
---|
| 71 | push dword ptr [ebp + 4] ; original eip (return address)
|
---|
[620] | 72 |
|
---|
[21916] | 73 | push dword ptr [ebp + 20] ; arg 4 (DWORD *lpArguments)
|
---|
| 74 | push dword ptr [ebp + 16] ; arg 3 (DWORD cArguments)
|
---|
| 75 | push dword ptr [ebp + 12] ; arg 2 (DWORD dwExceptionFlags)
|
---|
| 76 | push dword ptr [ebp + 8] ; arg 1 (DWORD dwExceptionCode)
|
---|
| 77 |
|
---|
| 78 | call _OS2RaiseException
|
---|
| 79 |
|
---|
| 80 | add esp, 20 * 4
|
---|
| 81 |
|
---|
| 82 | pop eax
|
---|
| 83 | pop ebp
|
---|
| 84 |
|
---|
[4106] | 85 | ret 16 ;__stdcall
|
---|
[21916] | 86 |
|
---|
[3275] | 87 | _RaiseException@16 endp
|
---|
[620] | 88 |
|
---|
[21916] | 89 |
|
---|
[3275] | 90 | public _RtlUnwind@16
|
---|
[21916] | 91 | extrn _OS2RtlUnwind : near
|
---|
[620] | 92 |
|
---|
[3275] | 93 | _RtlUnwind@16 proc near
|
---|
[21916] | 94 |
|
---|
| 95 | ; OS2RtlUnwind is _cdecl
|
---|
| 96 |
|
---|
[620] | 97 | push ebp
|
---|
[21916] | 98 | mov ebp, esp
|
---|
[620] | 99 | push eax
|
---|
[21916] | 100 |
|
---|
| 101 | mov eax, 0
|
---|
| 102 | mov eax, ss
|
---|
[620] | 103 | push eax
|
---|
[21916] | 104 | mov eax, gs
|
---|
[620] | 105 | push eax
|
---|
| 106 | mov eax, fs
|
---|
| 107 | push eax
|
---|
[21916] | 108 | mov eax, es
|
---|
[620] | 109 | push eax
|
---|
[21916] | 110 | mov eax, ds
|
---|
[620] | 111 | push eax
|
---|
[21916] | 112 | mov eax, cs
|
---|
| 113 | push cs
|
---|
| 114 | push esi
|
---|
| 115 | push edi
|
---|
| 116 | push edx
|
---|
| 117 | push ecx
|
---|
| 118 | push ebx
|
---|
| 119 | push dword ptr [ebp-4] ; original eax
|
---|
| 120 | pushfd
|
---|
| 121 | push dword ptr [ebp] ; original ebp
|
---|
| 122 | push ebp
|
---|
| 123 | add dword ptr [esp], 4 ; original esp
|
---|
| 124 | push dword ptr [ebp + 4] ; original eip (return address)
|
---|
[620] | 125 |
|
---|
[21916] | 126 | push dword ptr [ebp + 20] ; arg 4 (DWORD returnEax)
|
---|
| 127 | push dword ptr [ebp + 16] ; arg 3 (PWINEXCEPTION_RECORD pRecord)
|
---|
| 128 | push dword ptr [ebp + 12] ; arg 2 (LPVOID unusedEip)
|
---|
| 129 | push dword ptr [ebp + 8] ; arg 1 (PWINEXCEPTION_FRAME pEndFrame)
|
---|
| 130 |
|
---|
| 131 | call _OS2RtlUnwind
|
---|
| 132 |
|
---|
| 133 | add esp, 20 * 4
|
---|
| 134 |
|
---|
| 135 | pop eax
|
---|
| 136 | pop ebp
|
---|
| 137 |
|
---|
[4106] | 138 | ret 16 ;__stdcall
|
---|
[21916] | 139 |
|
---|
[3275] | 140 | _RtlUnwind@16 endp
|
---|
[620] | 141 |
|
---|
| 142 |
|
---|
[10409] | 143 | PUBLIC OS2ExceptionHandler
|
---|
| 144 | EXTRN OS2ExceptionHandler2ndLevel:NEAR
|
---|
| 145 |
|
---|
| 146 | OS2ExceptionHandler proc near
|
---|
| 147 | ;Clear the direction flag (as specified by the _System calling convention)
|
---|
| 148 | ;(OS/2 doesn't bother checking before calling our exception handler)
|
---|
| 149 | cld
|
---|
| 150 | jmp OS2ExceptionHandler2ndLevel
|
---|
| 151 | OS2ExceptionHandler endp
|
---|
| 152 |
|
---|
[21999] | 153 |
|
---|
| 154 | PUBLIC OSLibDispatchException
|
---|
| 155 | EXTRN OSLibDispatchExceptionWin32:NEAR
|
---|
| 156 | EXTRN ___seh_handler_filter:NEAR
|
---|
| 157 |
|
---|
| 158 | ; BOOL APIENTRY OSLibDispatchException(PEXCEPTIONREPORTRECORD pReportRec,
|
---|
| 159 | ; PEXCEPTIONREGISTRATIONRECORD pRegistrationRec,
|
---|
| 160 | ; PCONTEXTRECORD pContextRec, PVOID p,
|
---|
| 161 | ; BOOL fSEH);
|
---|
| 162 | OSLibDispatchException proc near
|
---|
| 163 | cmp dword ptr [esp + 20], 0 ; fSEH == FALSE?
|
---|
| 164 | jz OSLibDispatchExceptionWin32
|
---|
| 165 | jmp ___seh_handler_filter
|
---|
| 166 | OSLibDispatchException endp
|
---|
| 167 |
|
---|
| 168 |
|
---|
[21916] | 169 | PUBLIC _QueryExceptionChain
|
---|
[620] | 170 |
|
---|
[21916] | 171 | _QueryExceptionChain proc near
|
---|
[620] | 172 | mov eax, fs:[0]
|
---|
| 173 | ret
|
---|
[21916] | 174 | _QueryExceptionChain endp
|
---|
[620] | 175 |
|
---|
| 176 | PUBLIC GetExceptionRecord
|
---|
| 177 | GetExceptionRecord proc near
|
---|
| 178 | push ebp
|
---|
| 179 | mov ebp, esp
|
---|
| 180 | push fs
|
---|
| 181 | push ebx
|
---|
| 182 |
|
---|
| 183 | mov eax, [ebp+8]
|
---|
| 184 | mov fs, eax
|
---|
| 185 | mov ebx, [ebp+12]
|
---|
| 186 | mov eax, fs:[ebx]
|
---|
| 187 |
|
---|
| 188 | pop ebx
|
---|
| 189 | pop fs
|
---|
| 190 | pop ebp
|
---|
| 191 | ret
|
---|
| 192 | GetExceptionRecord endp
|
---|
| 193 |
|
---|
| 194 | PUBLIC ChangeTIBStack
|
---|
| 195 | ChangeTIBStack proc near
|
---|
| 196 | ; xor eax, eax
|
---|
| 197 | push ebx
|
---|
| 198 | mov eax, fs:[4]
|
---|
| 199 | mov ebx, fs:[8]
|
---|
| 200 | add ebx, 8
|
---|
| 201 | mov fs:[4], ebx
|
---|
| 202 | mov fs:[8], eax
|
---|
| 203 | pop ebx
|
---|
| 204 | ret
|
---|
| 205 | ChangeTIBStack endp
|
---|
| 206 |
|
---|
| 207 | PUBLIC _SetExceptionChain
|
---|
| 208 |
|
---|
| 209 | _SetExceptionChain proc near
|
---|
| 210 | mov eax, dword ptr [esp+4]
|
---|
| 211 | mov fs:[0], eax
|
---|
| 212 | ret
|
---|
| 213 | _SetExceptionChain endp
|
---|
| 214 |
|
---|
| 215 |
|
---|
[9913] | 216 | ;;ULONG CDECL AsmCallThreadHandler(BOOL fAlignStack, ULONG handler, LPVOID parameter);
|
---|
[5354] | 217 | PUBLIC _AsmCallThreadHandler
|
---|
| 218 | _AsmCallThreadHandler proc near
|
---|
| 219 | push ebp
|
---|
| 220 | mov ebp, esp
|
---|
| 221 |
|
---|
[9913] | 222 | ;first check if we have 128kb stack or more; if not, then skip the stack alignment code
|
---|
| 223 | mov eax, [ebp+8]
|
---|
| 224 | cmp eax, 0
|
---|
| 225 | je @goodthreadstack
|
---|
| 226 |
|
---|
[9754] | 227 | ;We're asking for problems if our stack start near a 64kb boundary
|
---|
[9780] | 228 | ;Some OS/2 thunking procedures can choke if there's not enough stack left
|
---|
[9754] | 229 | mov eax, esp
|
---|
| 230 | and eax, 0FFFFh
|
---|
| 231 | cmp eax, 0E000h
|
---|
| 232 | jge @goodthreadstack
|
---|
| 233 |
|
---|
[9780] | 234 | ;set ESP to the top of the next 64kb block and touch each
|
---|
| 235 | ;page to make sure the guard page exception handler commits
|
---|
| 236 | ;those pages
|
---|
| 237 | mov edx, esp
|
---|
| 238 | sub edx, eax
|
---|
| 239 |
|
---|
| 240 | and esp, 0FFFFF000h
|
---|
| 241 | dec esp
|
---|
| 242 |
|
---|
| 243 | @touchthreadstackpages:
|
---|
| 244 | mov al, byte ptr [esp]
|
---|
| 245 |
|
---|
| 246 | sub esp, 1000h
|
---|
| 247 |
|
---|
| 248 | cmp esp, edx
|
---|
| 249 | jg @touchthreadstackpages
|
---|
| 250 |
|
---|
| 251 | mov esp, edx
|
---|
| 252 | sub esp, 16
|
---|
| 253 |
|
---|
[9822] | 254 | ;also touch this page
|
---|
| 255 | mov eax, dword ptr [esp]
|
---|
| 256 |
|
---|
[9754] | 257 | @goodthreadstack:
|
---|
| 258 |
|
---|
[10409] | 259 | mov eax, esp
|
---|
| 260 | sub eax, 16
|
---|
| 261 | and eax, 0FFFFFFF0h
|
---|
| 262 | ;now we make sure the stack is aligned at 16 bytes when the entrypoint is called
|
---|
| 263 | ;(8+4+4(return address) = 16)
|
---|
| 264 | add eax, 8
|
---|
| 265 | mov esp, eax
|
---|
| 266 |
|
---|
[9913] | 267 | push dword ptr [ebp+16]
|
---|
| 268 | mov eax, dword ptr [ebp+12]
|
---|
[5354] | 269 | call eax
|
---|
| 270 |
|
---|
| 271 | mov esp, ebp
|
---|
| 272 | pop ebp
|
---|
| 273 | ret
|
---|
| 274 | _AsmCallThreadHandler endp
|
---|
| 275 |
|
---|
[6133] | 276 | PUBLIC _CallEntryPoint
|
---|
| 277 | _CallEntryPoint proc near
|
---|
| 278 | push ebp
|
---|
| 279 | mov ebp, esp
|
---|
| 280 |
|
---|
[9441] | 281 | ;We're asking for problems if our stack start near a 64kb boundary
|
---|
[9780] | 282 | ;Some OS/2 thunking procedures can choke if there's not enough stack left
|
---|
[6133] | 283 | mov eax, esp
|
---|
[9441] | 284 | and eax, 0FFFFh
|
---|
| 285 | cmp eax, 0E000h
|
---|
[9780] | 286 | jge @goodmainstack
|
---|
[9441] | 287 |
|
---|
[9780] | 288 | ;set ESP to the top of the next 64kb block and touch each
|
---|
| 289 | ;page to make sure the guard page exception handler commits
|
---|
| 290 | ;those pages
|
---|
| 291 | mov edx, esp
|
---|
| 292 | sub edx, eax
|
---|
[9441] | 293 |
|
---|
[9780] | 294 | and esp, 0FFFFF000h
|
---|
| 295 | dec esp
|
---|
| 296 |
|
---|
| 297 | @touchmainstackpages:
|
---|
| 298 | mov al, byte ptr [esp]
|
---|
| 299 |
|
---|
| 300 | sub esp, 1000h
|
---|
| 301 |
|
---|
| 302 | cmp esp, edx
|
---|
| 303 | jg @touchmainstackpages
|
---|
| 304 |
|
---|
| 305 | mov esp, edx
|
---|
| 306 | sub esp, 16
|
---|
| 307 |
|
---|
[9822] | 308 | ;also touch this page
|
---|
| 309 | mov eax, dword ptr [esp]
|
---|
| 310 |
|
---|
[9780] | 311 | @goodmainstack:
|
---|
| 312 |
|
---|
[9441] | 313 | mov eax, esp
|
---|
[6133] | 314 | sub eax, 16
|
---|
| 315 | and eax, 0FFFFFFF0h
|
---|
[10409] | 316 | ;now we make sure the stack is aligned at 16 bytes when the entrypoint is called
|
---|
| 317 | ;(8+4+4(return address) = 16)
|
---|
| 318 | add eax, 8
|
---|
[6133] | 319 | mov esp, eax
|
---|
| 320 |
|
---|
| 321 | push dword ptr [ebp+12]
|
---|
| 322 | mov eax, dword ptr [ebp+8]
|
---|
| 323 | call eax
|
---|
| 324 |
|
---|
| 325 | mov esp, ebp
|
---|
| 326 | pop ebp
|
---|
| 327 | ret
|
---|
| 328 | _CallEntryPoint endp
|
---|
| 329 |
|
---|
[21916] | 330 | ifndef __EMX__
|
---|
[6133] | 331 |
|
---|
[5557] | 332 | EXTRN WriteLog:PROC
|
---|
| 333 | EXTRN _GetThreadTEB@0:PROC
|
---|
| 334 | IFDEF DEBUG
|
---|
[21916] | 335 | EXTRN _DbgEnabledKERNEL32:DWORD
|
---|
[5557] | 336 | ENDIF
|
---|
| 337 |
|
---|
[21916] | 338 | ; 129 static inline WINEXCEPTION_FRAME * EXC_push_frame( WINEXCEPTION_FRAME *frame )
|
---|
| 339 | align 04h
|
---|
| 340 |
|
---|
| 341 | EXC_push_frame proc
|
---|
[5557] | 342 | push ebp
|
---|
| 343 | mov ebp,esp
|
---|
| 344 | sub esp,04h
|
---|
| 345 | mov [ebp+08h],eax; frame
|
---|
| 346 |
|
---|
| 347 | ; 132 TEB *teb = GetThreadTEB();
|
---|
| 348 | call _GetThreadTEB@0
|
---|
| 349 | mov [ebp-04h],eax; teb
|
---|
| 350 |
|
---|
| 351 | ; 133 frame->Prev = (PWINEXCEPTION_FRAME)teb->except;
|
---|
| 352 | mov ecx,[ebp-04h]; teb
|
---|
| 353 | mov ecx,[ecx]
|
---|
| 354 | mov eax,[ebp+08h]; frame
|
---|
| 355 | mov [eax],ecx
|
---|
| 356 |
|
---|
| 357 | ; 134 teb->except = frame;
|
---|
| 358 | mov eax,[ebp-04h]; teb
|
---|
| 359 | mov ecx,[ebp+08h]; frame
|
---|
| 360 | mov [eax],ecx
|
---|
| 361 |
|
---|
| 362 | ; 135 return frame->Prev;
|
---|
| 363 | mov eax,[ebp+08h]; frame
|
---|
| 364 | mov eax,[eax]
|
---|
| 365 | leave
|
---|
| 366 | ret
|
---|
[21916] | 367 | EXC_push_frame endp
|
---|
[5557] | 368 |
|
---|
| 369 | ; 138 static inline WINEXCEPTION_FRAME * EXC_pop_frame( WINEXCEPTION_FRAME *frame )
|
---|
| 370 | align 04h
|
---|
| 371 |
|
---|
[21916] | 372 | EXC_pop_frame proc
|
---|
[5557] | 373 | push ebp
|
---|
| 374 | mov ebp,esp
|
---|
| 375 | sub esp,04h
|
---|
| 376 | mov [ebp+08h],eax; frame
|
---|
| 377 |
|
---|
| 378 | ; 141 TEB *teb = GetThreadTEB();
|
---|
| 379 | call _GetThreadTEB@0
|
---|
| 380 | mov [ebp-04h],eax; teb
|
---|
| 381 |
|
---|
| 382 | ; 142 teb->except = frame->Prev;
|
---|
| 383 | mov ecx,[ebp+08h]; frame
|
---|
| 384 | mov ecx,[ecx]
|
---|
| 385 | mov eax,[ebp-04h]; teb
|
---|
| 386 | mov [eax],ecx
|
---|
| 387 |
|
---|
| 388 | ; 143 return frame->Prev;
|
---|
| 389 | mov eax,[ebp+08h]; frame
|
---|
| 390 | mov eax,[eax]
|
---|
| 391 | leave
|
---|
| 392 | ret
|
---|
[21916] | 393 | EXC_pop_frame endp
|
---|
[5557] | 394 |
|
---|
[21916] | 395 | ; 281 static extern "C" DWORD EXC_CallHandler( WINEXCEPTION_RECORD *record, WINEXCEPTION_FRAME *frame,
|
---|
[5557] | 396 | align 04h
|
---|
[21916] | 397 | PUBLIC _EXC_CallHandler
|
---|
[5557] | 398 |
|
---|
[21916] | 399 | _EXC_CallHandler proc
|
---|
[5557] | 400 | push ebp
|
---|
| 401 | mov ebp,esp
|
---|
| 402 | sub esp,010h
|
---|
| 403 | sub esp,04h
|
---|
| 404 | mov [ebp+08h],eax; record
|
---|
| 405 | mov [ebp+0ch],edx; frame
|
---|
| 406 | mov [ebp+010h],ecx; context
|
---|
| 407 |
|
---|
| 408 | ; 296 newframe.frame.Handler = nested_handler;
|
---|
| 409 | mov eax,[ebp+01ch]; nested_handler
|
---|
| 410 | mov [ebp-08h],eax; newframe
|
---|
| 411 |
|
---|
| 412 | ; 297 newframe.prevFrame = frame;
|
---|
| 413 | mov eax,[ebp+0ch]; frame
|
---|
| 414 | mov [ebp-04h],eax; newframe
|
---|
| 415 |
|
---|
| 416 | ; 298 EXC_push_frame( &newframe.frame );
|
---|
| 417 | lea eax,[ebp-0ch]; newframe
|
---|
[21916] | 418 | call EXC_push_frame
|
---|
[5557] | 419 |
|
---|
| 420 | ; 299 dprintf(("KERNEL32: Calling handler at %p code=%lx flags=%lx\n",
|
---|
| 421 | IFDEF DEBUG
|
---|
[21916] | 422 | cmp word ptr _DbgEnabledKERNEL32+020h,01h
|
---|
[5557] | 423 | jne @BLBL20
|
---|
| 424 | mov eax,[ebp+08h]; record
|
---|
| 425 | push dword ptr [eax+04h]
|
---|
| 426 | mov eax,[ebp+08h]; record
|
---|
| 427 | push dword ptr [eax]
|
---|
| 428 | push dword ptr [ebp+018h]; handler
|
---|
| 429 | push offset FLAT:@CBE8
|
---|
| 430 | call WriteLog
|
---|
| 431 | add esp,010h
|
---|
| 432 | ENDIF
|
---|
| 433 |
|
---|
| 434 | ; 300 handler, record->ExceptionCode, record->ExceptionFlags));
|
---|
| 435 | @BLBL20:
|
---|
| 436 |
|
---|
| 437 | ; 301 ret = handler( record, frame, context, dispatcher );
|
---|
| 438 | push dword ptr [ebp+014h]; dispatcher
|
---|
| 439 | push dword ptr [ebp+010h]; context
|
---|
| 440 | push dword ptr [ebp+0ch]; frame
|
---|
| 441 | push dword ptr [ebp+08h]; record
|
---|
| 442 | call dword ptr [ebp+018h]; handler
|
---|
| 443 | mov [ebp-010h],eax; ret
|
---|
| 444 |
|
---|
| 445 | IFDEF DEBUG
|
---|
| 446 | ; 302 dprintf(("KERNEL32: Handler returned %lx\n", ret));
|
---|
[21916] | 447 | cmp word ptr _DbgEnabledKERNEL32+020h,01h
|
---|
[5557] | 448 | jne @BLBL21
|
---|
| 449 | push dword ptr [ebp-010h]; ret
|
---|
| 450 | push offset FLAT:@CBE9
|
---|
| 451 | call WriteLog
|
---|
| 452 | add esp,08h
|
---|
| 453 | @BLBL21:
|
---|
| 454 | ENDIF
|
---|
| 455 |
|
---|
| 456 | ; 303 EXC_pop_frame( &newframe.frame );
|
---|
| 457 | lea eax,[ebp-0ch]; newframe
|
---|
[21916] | 458 | call EXC_pop_frame
|
---|
[5557] | 459 |
|
---|
| 460 | ; 304 return ret;
|
---|
| 461 | mov eax,[ebp-010h]; ret
|
---|
| 462 | add esp,04h
|
---|
| 463 | leave
|
---|
| 464 | ret
|
---|
[21916] | 465 | _EXC_CallHandler endp
|
---|
[5557] | 466 |
|
---|
[21916] | 467 | endif ; ifndef __EMX__
|
---|
| 468 |
|
---|
[620] | 469 | CODE32 ENDS
|
---|
| 470 |
|
---|
| 471 | END
|
---|