Introduction
We all know that computers execute machine code which is a sequence of bytes encoding the low-level operations that manipulate data, manage memory, read and write data on storage device and communicate over networks. Machine-level code, also called assembly code, is generated by compiler depend on different operating system. But as abstraction is an important notation in Computer Science, many high-level programming languages enable developers to neglect the assembly code layer for distinct standards in different platforms to improve developing efficiency and put more emphasis on practical tech schema.
However, in some specific conditions like compiler optimization should take assembly layer into consideration because more effective organization of assembly code will achieve better performance which will influence the higher level architecture a lot. Plus, in reverse engineering decompile from machine code need to understand assembly code.
So what consists of assembly code? Since assembly code is a kind of programming language, employing different forms of abstraction and hiding details of implementation thorough the use of simpler, abstract model is two important properties for assembly code. The basic component of assembly code is instruction, instruction defines operation and processor state so that assembly code is equivalent to the composition of instruction set architecture which defines the processor state, the format of instructions and their effect on processor state.
A program can be viewed as a sequence of instruction and processor executes them one by one. But programs executed concurrently is one of the most critical characteristics in modern operating system. Multi-core architecture can ensure that in the same time there are several processors are running simultaneously. But for one core, how to improve the performance of concurrency? In most modern CPU architecture, sequential pipeline becomes a necessary component. The basic idea of pipeline is that instruction sequence execution can be split into several stages and processor can simultaneously execute different stages for different program to increase throughout of the system, that is, the number of *”customer”* served per unit time.
Generally, processing instruction involves a number of operations. We can organize them in a particular sequence of stages. Although instructions differ greatly in their actions, they are all executed in a uniform sequence. Let’s see the processing stages briefly:
Fetch -> Decode -> Execute -> Memory ->Write Back -> PC update
In general, Compiler -> Linker -> Instruction Set Architecture -> Assembly code -> Sequential stages -> Pipeline is the progress of source code executed in operating system. Compile is not our main point and linking will be introduced in another note.
In this note, we will introduce these concepts:
- IA32 Instruction Set Architecture (ISA);
- Y86 Processor: Sequential and Pipeline implementation on the foundation of IA32;
IA32 ISA
Example
A simple example of IA32 program is as follows:
Two basic elements: instructions with particular actions and their objective integer registers
Several kinds of instructions
We will list some instructions of IA32
instruction | Effect | Description |
---|---|---|
popl | Pop double word | Move with zero extension |
pushl | Push Double word | Move with zero extension |
movl | move double word | Move |
addl | ||
ret | return |
some registers will be listed as well. Register is
Register | definition |
---|---|
%ebp | frame pointer, 32-bit |
%eax | 32-bit |
%edx | 32-bit |
%ecx | 32-bit |
%esi | 32-bit |
%edi | 32-bit |
%ah | 8-bit |
%al | 8-bit |
%esp | stack pointer, 32-bit |
%dh | 8-bit |
%dl | 8-bit |
%bh | 8-bit |
%bl | 8-bit |
%ch | 8-bit |
%cl | 8-bit |