Program Flow – Jumps and Calls @ P. Klimo 5/11/04 Program Flow – Jumps and Calls 1. Unconditional JUMPS : Program Flow Chart with Unconditional Jumps JUMPS: Type Mnemonic Operand Advantages Disadvantages Re-locatable Code Relative JUMPR Displacement Very Fast Small jump range Yes Intra-Segment JUMP Offset Faster execution Current Segment Yes Inter-Segment JUMPF Segment : Offset Can jump anywhere Slower execution No Relative Addressing: The jump address is specified by relative (positive or negative) address offset which is added to the current content of the program counter to give the destination address. As the current content of program counter is the address of the instruction following the current jump instruction, the relative offset is calculated as follows: Relative Offset = Destination Address – Next Instruction Address Positive offset signifies forward jump and negative offset means backward jump. 1 Program Flow – Jumps and Calls @ P. Klimo 5/11/04 Example of Absolute Jump: Using DEBUG, load the value 0FFFFh into CS and 0 into IP. Then dump memory at FFFF:0000: You will see that the “start up” memory location FFFF0 contains bytes such as FFFF:0000 EA 5B E0 00 F0 Here EA is the opcode for the absolute (inter-segment) jump JMPF. The next two bytes represent the segment offset 00E0 and the last two bytes the code segment F000: JMPF F000:00E0 In MASM there is only one mnemonic for jump. The Inter-Segment jump is flagged out by the assembler directive FAR as shown in this extract: EXTERN label_1 : FAR label_2 ; defines a label with property FAR i.e. carries ;absolute (segment : offset) address. ; the specifier EXTERN informs assembler that ; the label is defined in another file (module). JUMP label_2 ……… JUMP label_1 ; translates to a near jump ; translates to a far jump at Example of Relative Jump: Assume you see bytes at memory 300 0100: EB 02 01 D8 A3 00 02 D8 … In 8086 machine code 0100: 0102: 0104: ; ; ; ; ; ; jmp 02 add AX, BX mov [0200], AX In MASM . org 0200 addr dw ( ?) org 0100 jmp here add AX,BX here mov addr, AX Note: The jump offset is calculated as starting from the instruction following the relative jump instruction. This address is 00302 (the JMP is two bytes long ,i.e opcode and a one byte operand ). The relative displacement is calculated: Offset = 0304 – 0302 = 2 The length of relative jump is limited by the size of the operand Example: 8086 CPU branch instructions have an 8 bit operand. 8 bit relative address allows max jumps across 27 memory locations (i.e 127 forward and 128 backwards) 2 Program Flow – Jumps and Calls 2. @ P. Klimo 5/11/04 Conditional Jumps (Branches) Flow Diagram: CONDITIONAL JUMPS (BRANCHES): The execution of the branch depends on the current condition of the flags in the flag register: ZF CF SF OF PF zero flag carry flag sign flag overflow flag parity flag The seven ‘survival’ kit branch 8086 instructions are: JZ JNZ General: Jump if result was Zero jump if result was Not Zero JA JB For unsigned numbers: Jump if result was Above zero CF = ZF = 0 Jump if result Below zero CF =1 JG JL For signed numbers: Jump if result Greater than zero ZF=0 and SF=OF Jump if result Less than zero SF OF 3 ZF set (ZF=1) ZF not set (ZF=0) Program Flow – Jumps and Calls @ P. Klimo 5/11/04 ALL Branch instructions in 8086 use RELATIVE Addressing: Example of Assembly Listing. Var_I My_loop: DB 0Ah MOV AX, Var_I DEC AX BNZ My_loop MOV BX, AX ; Define the variable ; Copy the variable’s value into AX ; Decrement AX ; Branch if Not Zero to the label My_loop Note : When the BNZ instruction ( Branch on Not Zero) starts executing, the CPU checks the Zero flag in Flags Register. If this is not set, i.e. the result of the previous instruction (DEC AX ) was not zero, the program counter is set to point to the address location defined by the label My_loop. If the zero flag has been set then the program counter is pointed towards the instruction following the BNZ instruction. Thus the final instruction MOV BX, AX always copies a zero into BX. The above listing does not change the value of the variable Var_I. Problem: Revise the above listing so that the value of the variable is decremented by each loop until it becomes zero. (Hint: Decrement the variable in memory location directly by using instruction DEC Var_I. ). Question: Which of the two differently coded loops will run faster and why ? 3. Subroutines (Procedures): Example : The following example converts the ASCII upper case letter codes to the lower case ones. The algorithm is based on the fact that the lower case letters a, b, c …z have ASCII codes which are 20h more than their upper case equivalents A, B, C … Z. Letter : DB ‘A’ Convert: MOV AL, Letter ADD AL, 20h MOV Letter, AL ; define a byte in memory and initiate it to the ASCII ; code for letter A. ; Convert from upper to lower case ; and replace in memory location with ‘a’ Repeated use of this extract would require to repeat entering the same machine code into memory thus eventually exhausting all the available program memory!!! Instead, we can place one copy of the conversion routine into a memory segment starting say at a certain location Convert and each time we want to run it from the calling program we execute the CALL instruction which will set the PC to the routine and after running it, returns to the calling program at the place it “ took off”: 4 Program Flow – Jumps and Calls @ P. Klimo 5/11/04 Observe that: There is only one copy of machine code for each subroutine irrespective of how many times the subroutine is called. This saves program memory. CALL instruction has to save the value of the Program Counter before it branches to the subroutine. Before returning to the calling program the subroutine code has to include a special Return from Subroutine instruction ( RET) which will restore the value of the PC to the value which it held before the jump to the subroutine was taken. 5 Program Flow – Jumps and Calls @ P. Klimo 5/11/04 Question: Where does the CALL instruction save the value of the PC ?? Answer: On the Memory Stack. Question: What is a Stack ? Answer : Stack is a one dimensional data storage structure characterised by the Last in First Out (LIFO) behaviour. Example of LIFO is a stack of plates in a cafeteria. We can add plates or take away plates to or from the TOP f the STACK. MEMORY Stack. 6 Program Flow – Jumps and Calls @ P. Klimo 5/11/04 There is always one current memory location identified as The TOP of the Stack. This is pointed to by the Stack Pointer (SP) register. There are two operation associated with a Stack: 1. PUSH AX increments the SP and copies the AX data at the newly created location at the top of the stack. 2. POP AX copies the data from the top of the stack into AX and then decrements the SP to create a new top of the stack. NOTE: Data locations above the current top of the stack do not hold valid data. If stack growth or shrinks beyond the memory space reserved for stack any PUSH operations will overwrite the adjacent memory and may cause the program to crash. Example: The previous Convert program written as a subroutine: Letter : DB ‘A’ Main: CALL Convert MOV BL, Letter; … … MOV Letter, ‘B’ CALL Convert … … END Convert: ; Define a byte in memory and initiate it to the ASCII ; code for letter A. ; First call for the subroutine. When the subroutine returns ; the converted letter will be in memory location Letter. ; Do something else with the converted letter ; Do another letter ; Second call for the subroutine MOV AL, Letter ADD AL, 20h MOV Letter, AL RET ; First instruction of the subroutine takes the letter ; from the memory location Letter. ; Converts it from the upper to the lower case ; and replaces the memory location Letter with the ; newly converted letter. ; Return from subroutine What does CALL do?: (a) (b) Pushes the current value of IP onto stack Loads IP (and CS) with address of subroutine What does RET do?: (a) Pops the current top of stack into IP (and CS) 7 Program Flow – Jumps and Calls @ P. Klimo 5/11/04 As with JUMP, there are two types of CALL 8086 instruction: 1. Near CALL (mnemonic CALL and corresponding RET) which has a maximum range equal to the Intra-Segment JUMP instruction. The operand is only the segment offset of the procedure. This type of subroutine is re-locatable. 2. Far CALL (mnemonic CALLF and corresponding RETF) which has an unlimited range, similar to the Inter-Segment JUMP instruction. The operand is in the form segment:offset and the program containing Far Call is not re-locatable. Note: In MASM the same instruction CALL is used for both the Far and the Near types of procedures. As with the JUMP, MASM needs the directive syntax below to distinguish between the two. <label> <label> PROCEDURE ….. ENDP FAR ; or NEAR The subroutine may reside in another part of the program memory (e.g. forming a part of a library of subroutines assembled in a different module(s), called object files) It is the responsibility of the Linker program to identify all subroutines referred to in different modules (object files) and link their addresses to form one executable file which can be run by the CPU. An executable program is created by firstly assembling all modules into object files and then linking all the object files to obtain one executable file. 8 Program Flow – Jumps and Calls Example: @ P. Klimo 5/11/04 Subroutine and Branches in 8088/86 The Intra-Segment and Inter-Segment Mechanism. Consider the following program extract: 010B 010D 0110 0110 0113 8B E8 F4 F7 8B C1 01 00 E3 D0 MOV AX,CX CALL A_SUB HLT MUL BX MOV DX, AX . . RET A_SUB: 0124 C3 Trace the effect of CALL and RET on the contents of IP, SP and the stack. Before After CALL 0001 IP SP 01E1 01E2 01E3 01E4 010D 01E4 0111 01E2 ?? ?? ?? ?? ?? 10 01 ?? RET IP SP 01E1 01E2 01E3 01E4 0125 01E2 0110 01E4 ?? 10 01 ?? ?? 10 01 ?? 9 Program Flow – Jumps and Calls @ P. Klimo 5/11/04 Commentary: By the time these instructions come to be executed the assembler will have replaced the label A_SUB with one of two things: 1. If the subroutine with the first instruction labelled A_SUB is stored within 0FFFF locations of the CALL instruction, then the label A_SUB will be replaced by a 16 bit signed number. This number specifies what will need to be added to the contents of the IP (PC) register after execution of CALL has begun in order for CS:IP to point to the instruction labelled A_SUB. Thus in the above case the label in CALL A_SUB will be replaced by 0001. But this is not the only effect of CALL. It also pushes the 16 bit address offset of the instruction which follows CALL onto the stack. The execution of the RET instruction simply pops this value back to the IP. This type of CALL and RET is known as intra-segment instructions. 2. If the first instruction the subroutine is more than 0FFFF locations apart, the inter-segment form of CALL (CALLF) and RET (RETF) must be used. Now the assembler replaces the A_SUB label with a 4 byte number defining the absolute address of the first instruction (two bytes for CS and two bytes for IP). Similarly, the CALL instruction updates the values of the CS and IP accordingly and places on stack a four byte number representing the absolute address of the instruction following the CALL. When the RET instruction executes it pops these four bytes of the address to the CS and the IP. 10 Program Flow – Jumps and Calls @ P. Klimo 5/11/04 Exercise: Re-Entrant Subroutine Re-entrant subroutine is the one that calls itself. What will be the content of the memory locations 5030h to 5040h after the following program extract? Assume initially the content of SP is 5040h. Memory Dump 4000: B0 02 4002: FF 16 10 40 4006: CD 20 start MOV AL,2 CALL alpha stop INT 20h ........ ; Subroutine alpha alpha MOV BL,56h 4010: B3 56 4012: FF C8 DEC AL 4014: 74 04 JZ fini 4016: FF 16 10 40 401A: C3 CALL alpha fini 11 RET