Hello !
Some years ago, in DOS, i learned something about C++ (not deeply) to translate
some procedures to asm and i was able to put it to work.
Now, i am reading some documentation (in PlatformSDK) and i found this:
switch( uMsg ) {
case WM_PAINT:
...
case WM_COMMAND:
...
case WM_DESTROY:
...
default:
return( DefWindowProc( hWnd, msg, wParam, lParam ));
}
( it is about processing messages ).
and
case WM_PAINT:
hDC = BeginPaint( hWnd, &ps );
TextOut( hDC, 10, 10, "Hello, World!", 13 );
EndPaint( hWnd, &ps );
break;
and this:
case WM_COMMAND:
switch( wParam ) {
case IDM_ABOUT:
...
break;
}
Whats my doubt ? It is about break. What does it do between cases ?
Can we put it there when we are thinking the processor needs "to take a coffee"
or it is tired and needs to stop ?
Seriously, what is the equivalent in asm ?
Rui
break is used to stop the rest of the switch block from executing if the previous condition is true.
Quote from: RuiLoureiro on September 01, 2008, 11:57:57 AM
Seriously, what is the equivalent in asm ?
Well, try it and see. :8) Seriously, that is the best answer, try the SWITCH and CASE macros in MASM32. Make a little test app, and load it into OllyDbg and press F7 and F8 repeatedly. :U
Rui,
The asm equivalent to the C/C++ break statement would be an unconditional jump out of the switch block. If the jump were not taken, then the next case statement would be evaluated, for example:
switch(i)
{
case 1:
// case statements for i == 1
break;
case 2:
case 3:
case 4:
// case statements for i == 2 || i == 3 || i == 4
break;
default:
// case statements for i == any other value
}
The MASM32 switch/case macros (authored by Greg Falen) effectively include a break statement at the end of each case block (similar to a BASIC Select Case, in case you are familiar with that). The macros actually generate .IF/.ELSEIF/.ELSE/.ENDIF statements, so the jumps are generated by MASM, but the end effect is the same.
As an example of what the compiler produces, for this source:
#include <windows.h>
int main(void)
{
int i;
switch(i) // line 5
{
case 1:
break; // line 8
case 2:
case 3:
case 4:
break; // line 12
default:
i=1; // this necessary for the source to compile line
}
return 0; // line 16
}
The Visual C++ Toolkit 2003 compiler produces this asm code:
; Line 5
mov eax, DWORD PTR _i$[ebp]
mov DWORD PTR tv64[ebp], eax
cmp DWORD PTR tv64[ebp], 1
je SHORT $L74000
cmp DWORD PTR tv64[ebp], 1
jle SHORT $L74002
cmp DWORD PTR tv64[ebp], 4
jle SHORT $L74001
jmp SHORT $L74002
$L74000:
; Line 8
jmp SHORT $L73997
$L74001:
; Line 12
jmp SHORT $L73997
$L74002:
; Line 14
mov DWORD PTR _i$[ebp], 1
$L73997:
; Line 16
Hi
Thanks Neil, Mark & MichaelW
Mark, Finally, i tried with OllyDbg. It was exactly what i expected except
the use of the EAX register. The next case begins with a jump to the end
and then it compares.
first experience with OllyDbg
; this the prog:
; ««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
.586 ; create 32 bit code
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
include \masm32\macros\macros.asm
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
.data
hInstance dd ?
.code
start:
invoke GetModuleHandle, 0
mov hInstance, eax
mov ebx, 0AAAAAAAAh
switch ebx
case 0BBBBBBBBh
mov eax, 1
case 0AAAAAAAAh
mov eax, 2
default
mov eax, 0
endsw
;
mov esi, 0FFFFFFF0h
invoke ExitProcess, 0
end start
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««
OLLYdbg
my note: »»» are my comments
; This is the result:
00401000 >/$ 6A 00 PUSH 0 ; /pModule = NULL
00401002 |. E8 3F000000 CALL <JMP.&kernel32.GetModuleHandleA> ; \GetModuleHandleA
00401007 |. A3 00304000 MOV DWORD PTR DS:[403000],EAX
0040100C |. BB AAAAAAAA MOV EBX,AAAAAAAA
00401011 |. 8BC3 MOV EAX,EBX
»»» case BBBBBBBBh
00401013 |. 3D BBBBBBBB CMP EAX,BBBBBBBB
00401018 |. 75 07 JNZ SHORT Test1.00401021
0040101A |. B8 01000000 MOV EAX,1
0040101F |. EB 13 JMP SHORT Test1.00401034 »»» jump to endsw
»»» case AAAAAAAAh
00401021 |> 3D AAAAAAAA CMP EAX,AAAAAAAA
00401026 |. 75 07 JNZ SHORT Test1.0040102F
00401028 |. B8 02000000 MOV EAX,2
0040102D |. EB 05 JMP SHORT Test1.00401034 »»» jump to endw
0040102F |> B8 00000000 MOV EAX,0
»»» endsw
00401034 |> BE F0FFFFFF MOV ESI,-10
00401039 |. 6A 00 PUSH 0 ; /ExitCode = 0
0040103B \. E8 00000000 CALL <JMP.&kernel32.ExitProcess> ; \ExitProcess
00401040 .-FF25 04204000 JMP DWORD PTR DS:[<&kernel32.ExitProcess>; kernel32.ExitProcess
00401046 $-FF25 00204000 JMP DWORD PTR DS:[<&kernel32.GetModuleHa>; kernel32.GetModuleHandleA
.....................................................................................................................
MichaelW,
«The asm equivalent to the C/C++ break statement would be an unconditional jump out
of the switch block. If the jump were not taken, then the next case statement
would be evaluated».
In C++ do we need to put a break btw cases ? Isnt it implied ? If we dont
put a break then the next case statement will be evaluated ?
Could you compile this (correct it if need)
and show the asm code using Visual C++ Toolkit 2003
#include <windows.h>
int main(void)
{
int i;
int m;
switch(i)
{
case 1:
m= 10;
break;
case 2:
m= 20;
default:
m=30;
i=1; // this necessary for the source to compile line
}
return 0;
}
Thanks
Rui
Quote from: RuiLoureiro on September 02, 2008, 03:04:50 PM
In C++ do we need to put a break btw cases ? Isnt it implied ? If we dont
put a break then the next case statement will be evaluated ?
Exactly. C++ has the "fall through" behaviour, which can be nasty if you have
mov eax, 1
switch eax
case 1
mov eax, 2
case 2
mov eax, 123
endsw
The
C++ construct would give you 123 because it "falls through" to case 2, compares it to eax (=2, equal) and assigns 123. For my taste, this behaviour is counterintuitive.
The
MASM switch gives back 2 in eax, same as in all
BASIC dialects known to me.
Rui, compiled as posted, with all of the generated code included:
; Listing generated by Microsoft (R) Optimizing Compiler Version 13.10.3077
TITLE switch.c
.386P
include listing.inc
if @Version gt 510
.model FLAT
else
_TEXT SEGMENT PARA USE32 PUBLIC 'CODE'
_TEXT ENDS
_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
_DATA ENDS
CONST SEGMENT DWORD USE32 PUBLIC 'CONST'
CONST ENDS
_BSS SEGMENT DWORD USE32 PUBLIC 'BSS'
_BSS ENDS
$$SYMBOLS SEGMENT BYTE USE32 'DEBSYM'
$$SYMBOLS ENDS
_TLS SEGMENT DWORD USE32 PUBLIC 'TLS'
_TLS ENDS
FLAT GROUP _DATA, CONST, _BSS
ASSUME CS: FLAT, DS: FLAT, SS: FLAT
endif
INCLUDELIB LIBC
INCLUDELIB OLDNAMES
PUBLIC _main
; Function compile flags: /Odt
_TEXT SEGMENT
tv64 = -12 ; size = 4
_m$ = -8 ; size = 4
_i$ = -4 ; size = 4
_main PROC NEAR
; File c:\program files\microsoft visual c++ toolkit 2003\my\switch.c
; Line 3
push ebp
mov ebp, esp
sub esp, 12 ; 0000000cH
; Line 6
mov eax, DWORD PTR _i$[ebp]
mov DWORD PTR tv64[ebp], eax
cmp DWORD PTR tv64[ebp], 1
je SHORT $L74001
cmp DWORD PTR tv64[ebp], 2
je SHORT $L74002
jmp SHORT $L74003
$L74001:
; Line 9
mov DWORD PTR _m$[ebp], 10 ; 0000000aH
; Line 10
jmp SHORT $L73998
$L74002:
; Line 12
mov DWORD PTR _m$[ebp], 20 ; 00000014H
$L74003:
; Line 14
mov DWORD PTR _m$[ebp], 30 ; 0000001eH
; Line 15
mov DWORD PTR _i$[ebp], 1
$L73998:
; Line 17
xor eax, eax
; Line 18
mov esp, ebp
pop ebp
ret 0
_main ENDP
_TEXT ENDS
END
Thanks jj & MichaelW
I used SELECT/CASE and switch/case (Dbase ?) many years ago but i dont remember
to use break. So that switch/case in C++ is not linear. It was out of my
memory.
Now, it is explaind why i found this
case WM_PAINT:
hDC = BeginPaint( hWnd, &ps );
TextOut( hDC, 10, 10, "Hello, World!", 13 );
EndPaint( hWnd, &ps );
break;
Thank you Michael for your code
Rui
Hello !
I decided to come here again
because in the following example (see above) it seems that we need to have EAX=2
after case 1 (btw case 1 and case 2). It doesnt compare. It goes on until the end.
«...it "falls through" to case 2, compares it to eax (=2, equal) and assigns 123»
mov eax, 1
switch eax
case 1
mov eax, 2
case 2
mov eax, 123
endsw
; This is the code MichaelW posted (cleaned and commented by me):
mov eax, DWORD PTR _i$[ebp]
mov DWORD PTR tv64[ebp], eax
cmp DWORD PTR tv64[ebp], 1
je SHORT $L74001
cmp DWORD PTR tv64[ebp], 2
je SHORT $L74002
jmp SHORT $L74003
; »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
; here is where we process the case 1 (means when i=1)
; »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
$L74001:
mov DWORD PTR _m$[ebp], 10
jmp SHORT $L73998 <--- here is our "break"
; »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
; here is where we process the case 2 (means when i=2)
; »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
$L74002:
mov DWORD PTR _m$[ebp], 20
<--- here, there isnt "jmp SHORT $L73998[/b]"
so when i=2 then it continues to down
and goes to the default case
; »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
; here is where we process default (means when i isnt 1 or 2)
; »»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»
$L74003:
mov DWORD PTR _m$[ebp], 30
mov DWORD PTR _i$[ebp], 1
$L73998:
xor eax, eax
Thanks, again jj & MichaelW !
Rui