I have programmed with several languages. This semester, I am teaching students x86 assembler. The 8086 was the start of the x86 family for Intel. The University of Virgia has a great introduction to x86 codding.
Introduction
For all programs, jumps and calls have some similarities, but they are not the same. In most programming languages, code execution goes from one statement to the next statement. Sometimes a user might want to switch the execution of the program to a different location. The new location is usually labeled through either a function or a label.
Functions
Functions are separate code that has an entry point at the start and a ret (return) at the end. It can be called from other functions in your code. Since I have several examples of Fibonacci sequence generators in other languages, I will use a simple function that adds together two numbers and returns the result in the EAX register. All x86 assembler functions start with PROC and end with ENDP.
; Next Fibonacci Number Calculator
; Add two numbers on the stack and return their sum in registeer EAX
; For all routines, the last item to be pushed on the stack is the return address, save it to a register
; then save any other expected parameters in registers, then restore the return address to the stack.
fibonacci PROC near
_fibonacci:
pop edx ; Save the return address
pop eax ; Save second number in register EAX
pop ebx ; Save first number in EBX
push edx ; Restore return address
add eax, ebx ; Add them together and store in EAX
ret ; And return with result in EAX
fibonacci ENDP
Calling a Function
Calling a function is simple, the instruction call followed by the name of the function. When the function finishes, it returns control to the instruction immediately after the call. A calll might look like:
_fibLoop:
push number2 ; Second parameter.
push number1 ; First parameter.
call fibonacci
mov ebx, number1 ; Move the previous high number into EBX
mov number1, eax ; Move the new high number into number1
mov number2, ebx ; Store the second number for recursion
In assembler, and thus in all programming languages, parameters are put on the stack in the reverse order. On the return from fibonacci, the next statement to be executed is “mov ebx,” which directly follows the “call fibonacci” statement.
Jumps
Programs usually progress from one statement to the next. The exceptions are function calls and jumps. Jumps just change the execution from one statement in the program to another statement within the program. The two statements do not need to follow each other. Only jump to a label. Never jump to a function, as when it tries to return somewhere, it does not know where that new location is located.
The tail end of the _fibloop in the sample above would look like:
cmp eax, maxNumber ; This will exit loop when EAX = 0x63D = 1597
jg _fibRecurse ; It will drop through one more than printed.
push eax
call writeInt
jmp _fibLoop
_fibRecurse:
push ebx
The first line is a comparison the max number I specified for the loop. If the number is greater than the maximum number, the program jumps to _fibRecurse. If the number is less than the maximum number, the program continues and then jumps back to _fibLoop.
Conclusion
Jumps and calls are not the same. Their start is each a location to which the process can transfer control. Labels can be accessed by jumps. They just continue to process one instruction after the next until something changes the program counter.
Functions are called by a statement. Functions have a “ret” statement at the end. When that statement is reached, the program returns to the statement immediately following the call. If you jump to a function, the return address has not been pushed onto the stack. Therefore, there is no guarantee where the program would go when the top item on the stack is popped.
Calls return to the statement following the call. Jumps just change which code is being executed. Choose wisely on what you want to happen.
Great article. Very clear