As I recall, the was a 16 bit processor, which used double registers to enable 32 bit memory addressing. Intel was far from being a leader in the field in those days.
The call instruction first pushes the current code location onto the hardware supported stack in memory see the push instruction for detailsand then performs an unconditional jump to the code location indicated by the label operand. Unlike the simple jump instructions, the call instruction saves the location to return to when the subroutine completes.
The ret instruction implements a subroutine return mechanism. This instruction first pops a code location off the hardware supported in-memory stack see the pop instruction for details.
It then performs an unconditional jump to the retrieved code location. Syntax ret Calling Convention To allow separate programmers to share code and develop libraries for use by many programs, and to simplify the use of subroutines in general, programmers typically adopt a common calling convention.
The calling convention is a protocol about how to call and return from routines. For example, given a set of calling convention rules, a programmer need not examine the definition of a subroutine to determine how parameters should be passed to that subroutine.
Furthermore, given a set of calling convention rules, high-level language compilers can be made to follow the rules, thus allowing hand-coded assembly language routines and high-level language routines to call one another.
In practice, many calling conventions are possible. We will use the widely used C language calling convention. The C calling convention is based heavily on the use of the hardware-supported stack. It is based on the push, pop, call, and ret instructions. Subroutine parameters are passed on the stack.
Registers are saved on the stack, and local variables used by subroutines are placed in memory on the stack.
The vast majority of high-level procedural languages implemented on most processors have used similar calling conventions. The calling convention is broken into two sets of rules. The first set of rules is employed by the caller of the subroutine, and the second set of rules is observed by the writer of the subroutine the callee.
It should be emphasized that mistakes in the observance of these rules quickly result in fatal program errors since the stack will be left in an inconsistent state; thus meticulous care should be used when implementing the call convention in your own subroutines.
The image above depicts the contents of the stack during the execution of a subroutine with three parameters and three local variables. The cells depicted in the stack are bit wide memory locations, thus the memory addresses of the cells are 4 bytes apart.
The first parameter resides at an offset of 8 bytes from the base pointer. Above the parameters on the stack and below the base pointerthe call instruction placed the return address, thus leading to an extra 4 bytes of offset from the base pointer to the first parameter.
When the ret instruction is used to return from the subroutine, it will jump to the return address stored on the stack. Caller Rules To make a subrouting call, the caller should: Before calling a subroutine, the caller should save the contents of certain registers that are designated caller-saved.
Since the called subroutine is allowed to modify these registers, if the caller relies on their values after the subroutine returns, the caller must push the values in these registers onto the stack so they can be restore after the subroutine returns. To pass parameters to the subroutine, push them onto the stack before the call.
The parameters should be pushed in inverted order i. Since the stack grows down, the first parameter will be stored at the lowest address this inversion of parameters was historically used to allow functions to be passed a variable number of parameters. To call the subroutine, use the call instruction.Assembly language programmers and compiler writers should take great care in producing efficient code.
This requires a fairly deep understanding of the x86 architecture, especially the behavior of the cache(s), pipelines and alignment bias. This guide describes the basics of bit x86 assembly language programming, covering a small but useful subset of the available instructions and assembler directives.
There are several different assembly languages for generating x86 machine code. Writing assembly language is something best left for the experts. Similarly “in Budapest” would be Budapesten – the en suffix means “in.” x86 assembly language code reminds me of Hungarian.
You don’t use mov or an 8 byte or 64 bit value.
Most x86 code these days works with 64 bit or 32 bit values, so you’ll most often see. In subtlety they do mean different things (well, amd64 means something different from x86_64 (the former being a vendor specific architecture, and the latter the subset of two vendors architectures), but x86_64 === x64), but for anyone except programmers writing in assembly or machine code it really doesn't make a different.
For years, PC programmers used x86 assembly to write performance-critical code. However, bit PCs are being replaced with bit ones, and the underlying assembly code has changed.
This white paper is an introduction to x64 assembly. There is a bit register named eflags which is implicitly read or written in many instructions. In other words, its value plays a role in the instruction execution, but the register is .