Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Down to the Metal: Managed Code Under the Hood (Part II) : Page 2

In this part of the series, you'll dig deeper into MSIL and learn to write conditional code, loops, and how to handle errors.


advertisement
The Sample Application
Let's assume you want an application to behave as follows: If a user enters a value less than zero, you want to perform action A; if the value is equal to zero you want action B; for values larger than zero but smaller than ten you want to loop action C, and for all other values you want action D. This sample will show you how to use branching (conditional) statements and how to build a basic loop.

Conditional Statements
Conditional statements are useful when you need to execute code based on the value of an item. They are similar to if/else combinations in most high-level languages. Here's an example:

ldstr "Enter some integer: " call void [mscorlib]System.Console::Write(string) call string [mscorlib]System.Console::ReadLine() call int32 [mscorlib]System.Int32::Parse(string) dup brzero ZeroLabel dup ldc.i4.0 blt.s LessThanZeroLabel br.s BiggerThanZeroLabel ZeroLabel: ldstr "You entered 0" call void [mscorlib]System.Console::WriteLine(string) pop ret LessThanZeroLabel: ldstr "You entered " call void [mscorlib]System.Console::Write(string) call void [mscorlib]System.Console::WriteLine(int32) ret BiggerThanZeroLabel: Dup ldc.i4.s 9 ble.s LoopPoint ldstr "Numbers higher than nine don't cause a loop." call void [mscorlib]System.Console::WriteLine(string) pop ret

In the preceding code snippet you'll find two new elements: labels and branch operands. Labels are used as targets for jumps. You can also use a relative value that specifies the jump offset—how many bytes of intermediate bytecode you want to skip forward or back from the current position. To get that value, you would have to sum the size of all opcodes and operands from your starting point to your endpoint to find the jump offset. Obviously it's much easier and more convenient to use labels and let the ILAsm compiler calculate the offsets needed for the jump.

The branch statements all begin with "b" followed by some abbreviation that tells you what kind of jump it is. The code shown always uses a short version that has ".s" at the end, because you can be sure that the calculated offset won't be far away. The short version uses only one byte for the offset, while the long version requires four bytes. To help keep the assembly size down, try to use the short version whenever possible.

All branch statements work the same way; they take the topmost values from the stack (if they need to compare something), check for the comparison they are enforcing and then continue code execution at the specified label when the expression evaluates to true or at the next line if it doesn't.

Table 1 shows a list of all branch operands:

Table 1. IL Branch Operands

Statement



Offset
size

Items
popped
off the stack

Description

br

int32

-

Branch <int32> bytes from the current position

br.s

int8

-

 

brfalse
brnull
brzero

int32

int32

Branch if the top item on the stack 0

brfalse.s

int8

int32

Note that there is no brnull.sor brzero.s

brtrue
brinst

int32

int32

Branch if the value on the stack is nonzero (or a valid address of an object instance)

brtrue.s
brinst.s

int8

int32

 

beq

int32

*,*

Branch if equal

bge

int32

*,*

Branch if greater or equal

bgt

int32

*,*

Branch if greater

ble

int32

*,*

Branch if lower or equal

blt

int32

*,*

Branch if lower

bne.un

int32

*,*

Branch if not equal (unsigned compare)

bge.un

int32

*,*

Branch if greater or equal (unsigned compare)

bgt.un

int32

*,*

Branch if greater (unsigned compare)

ble.un

int32

*,*

Branch if lower or equal (unsigned compare)

blt.un

int32

*,*

Branch if lower (unsigned compare)

beq.s

int8

*,*

 

bge.s

int8

*,*

 

bgt.s

int8

*,*

 

ble.s

int8

*,*

 

blt.s

int8

*,*

 

bne.un.s

int8

*,*

 

bge.un.s

int8

*,*

 

bgt.un.s

int8

*,*

 

ble.un.s

int8

*,*

 

blt.un.s

int8

*,*

 


The pop opcode still needs explaining. This one is simple; it discards the topmost item of the evaluation stack.

The ret statement simply returns control to the caller when the code reaches a point where no other code or condition remains to be evaluated.

Take a look at the accompanying code download, which includes stack transition diagrams that function as code comments for easier traceability.



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap
Thanks for your registration, follow us on our social networks to keep up-to-date