320 likes | 331 Views
Learn about converting control structures from high-level C to assembly code, covering if/else, while, do/while, for loops, and CALL/RET instructions. Understand how to pass parameters and handle local variables efficiently.
E N D
CS 301 Fall 2001 – Chapter 7 Slides by Prof. Hartman, following “IBM PC Assembly Language Programming” by Peter Abel
Address types • Short – Same segment, one byte offset, -128 to +127 • Near – Same segment, two byte (80286 and earlier) or four byte (80386 and later) offset. • Far – Different segment
Branching Instructions • JMP can jump to Short, Near, or Far addresses • Jxx can jump to Short or Near (80386+) addresses • LOOP can jump to Short addresses • CALL can jump to Near or Far addresses
Short Jumps • If the label is before the jump (jumping back) NASM will automatically choose a Short jump if possible. • If the label is after the jump (jumping forward) NASM will always use a Near jump, unless you specify jmp short label
NASM labels • Labels beginning with a period are “local” labels – they are associated with the most recent non-local label.
Converting high-level control structures – if/else if ( condition ) { // body of then_block } else { // body of else_block } In C is roughly equivalent to the following assembly code. Note the use of local labels. ; code to set flags based on condition jxx .else_block ; select xx to branch if false ; code for body of then_block jmp .endif .else_block: ; code for body of else_block .endif:
Converting high-level control structures – while while ( condition ) { // body of loop } In C is roughly equivalent to the following assembly code. Note the use of local labels. .while: ; code to set flags based on condition jxx .endwhile ; select xx so that branches if false ; body of loop jmp .while .endwhile:
Converting high-level control structures – do/while do { // body of loop } while ( condition ) In C is roughly equivalent to the following assembly code. Note the use of local labels. .do: ; code for body of loop ; code to set flags based on condition jxx .do ; select xx so branches if true
Converting high-level control structures – for • Should put here a slide converting for loop
LOOP instruction • LOOP label • Decrements ecx (or cx in 16-bit mode) and branches to label unless ecx is then zero. • LOOPE/LOOPZ label • Adds condition that ZF=1. • LOOPNE/LOOPNZ label • Adds condition that ZF=0.
Converting high-level control structures – for (again!) • And should put here a slide using LOOP to convert a for loop.
CALL and RET • CALL proc_name • Pushes IP, sets IP to offset of proc_name (and clears processor’s prefetch instruction queue) • RET [n] • Pops IP (and clears processor’s prefetch instruction queue) • Possibly “pops” n arguments from the stack
Passing parameters • Can pass parameters by reference (address) or value. • Can pass parameters in registers or on stack. • Examples using registers: regpassing.asm
Passing parameters on the stack 1 • Push parameters on the stack before the CALL instruction • Procedure doesn’t pop them off, it accesses them directly on the stack: • Avoids having to pop off return address then put it back on • Allows using the parameter multiple times • Need to use indirect addressing • Examples using stack: stackpassing.asm
Indirect Addressing • Can add registers and/or constants and/or a location and get at what is located in the result • MOV eax,[data] • MOV eax,[ebx] • MOV eax,[data+ebx] • MOV eax,[ebx+2] • MOV eax,[ebx*8+esp+4]
Passing parameters on the stack 2 • CALL places return address on stack, so parameters are at [esp+4] (last parameter pushed), [esp+8] (next to last), etc. • What if the subroutine pushes something? Now esp has changed, so parameters are at [esp+8] (last parameter), etc. Yuck! • Solution is to set ebp to esp when entering. Then esp may change, but ebp won’t.
Passing parameters on the stack 3 • But what if the routine that called us was using ebp? We’ll have to save it first, and restore it when we’re done. push ebp mov ebp,esp … pop ebp • Parameters are now at [ebp+8] (last parameter pushed), [ebp+12], etc.
C Calling Convention • Parameters are pushed onto stack in reverse order. • Caller is responsible for removing parameters from stack • Subroutine maintains ebx, esi, edi, ebp, cs, ds, ss, es. (and could change eax, ecx, edx) • Return values are passed via eax (extended to 32 bits) or ST0 (floating point).
Local Variables • Corresponding to C’s “auto” (automatic), the default of any C/C++ variable. • Allow reentrant code. • Stored on the stack. To make space, subtract storage amount from esp. To restore, just put ebp back into esp. • Example: factorial.asm
More Local Variables Examples • local1.asm • local2.asm
Prologue and Epilogue • So the start (prologue) of most subroutines looks like push ebp mov ebp,esp sub esp,n ;where n is immediate, how much space • And the end (epilogue) looks like mov esp,ebp pop ebp • Local storage is from [ebp-1] to [ebp-n]. Typically n is a multiple of 4 and you would use [ebp-4], [ebp-8], … • Parameters are located at [ebp+8] (last parameter pushed), [ebp+12], and so on.
ENTER and LEAVE • ENTER takes two immediate mode parameters. First is number of bytes of local storage, second is (for C programs) always 0. (The second parameter is nesting level, for languages like Pascal that can have nested procedures.) • ENTER n,0 replaces prologue. • LEAVE (no parameters) replaces epilogue.
The Way It’s Done • So the start (prologue) of most subroutines looks like enter n,0 ;n=how much local storage space (in bytes) • And the end (epilogue) looks like leave • Local storage is from [ebp-1] to [ebp-n]. Typically n is a multiple of 4 and you would use [ebp-4], [ebp-8], … • Parameters are located at [ebp+8] (last parameter pushed), [ebp+12], and so on.
Boolean Operations • AND, OR, XOR, TEST, NOT • Useful to set, clear, or test bits • AND/OR/XOR reg/mem, reg/mem/imm • Affect CF, OF, PF, SF, and ZF. AF undefined. • NOT reg/mem • Reverses 1’s and 0’s (one’s complement)
Boolean Operations – AND • AND reg/mem, reg/mem/imm • Affects CF(0), OF(0), PF, SF, and ZF. AF undefined. • To clear some bits, AND with a binary value with 0s where you wish to clear and 1s elsewhere.
Boolean Operations – OR • OR reg/mem, reg/mem/imm • Affects CF(0), OF(0), PF, SF, and ZF. AF undefined. • To set some bits, OR with a binary value with 1s where you wish to set and 0s elsewhere.
Boolean Operations – XOR • XOR reg/mem, reg/mem/imm • Affects CF(0), OF(0), PF, SF, and ZF. AF undefined. • To flip some bits, XOR with a binary value with 1s where you wish to flip and 0s elsewhere. • XOR reg,reg • The shortest way to set a register to 0
Boolean Operations – TEST • TEST reg/mem, reg/mem/imm • Affects CF(0), OF(0), PF, SF, and ZF. AF undefined. • Just like AND but doesn’t put the result in the destination (sets flags only)
Boolean Operations – NOT • NOT reg/mem • Affects no flags • Reverses 1’s and 0’s (one’s complement)
Shifting And Rotating Bits • SHR/SAR/SHRD – Shifting right • SHL/SAL/SHLD – Shifting left • ROR/RCR – Rotating right • ROL/RCL – Rotating left • op reg/mem, CL/imm • opD reg/mem, reg/mem/imm, CL/imm • Flags – all affect CF, OF, PF, SF, ZF. AF undefined.
C (and C++) Bitwise Operations • & is AND (note & is not &&) • | is OR (again, | is different from ||) • ~ is NOT • ^ is XOR • << is SAL/SHL • >> is SAR/SHR (depending on whether type is signed or not)
Examples – Counting Bits • We’ll talk about four methods: • Rotate through all bits, counting for each 1 we find. • Add the 1’s up: bitcount.c • Use a table lookup: bitcount2.c • Clear one 1 per iteration of a loop, count how many times: bitcount3.c