Chapter 10 -- Pentium Architecture
It is time to stop programming in SASM, and get to the real stuff:
Pentium assembly language.
Notes ahead of time:
-- The assembly language details presented are not specific to just
the Pentium architecture. They are applicable to the 486 and
to the Pentium II and the Pentium Pro. Many details also work
for the earlier Intel architectures.
-- I'm only presenting a subset of the Pentium instruction set.
The real instruction set is REALLY large, and contains many
instructions that no one really uses anymore. We don't cover
those "obsolete" instructions. We also don't cover the
instructions that only the operating system would use.
About the Pentium Architecture
------------------------------
-- It is not a load/store architecture.
-- The instruction set is huge! We go over only a fraction of
the instruction set. The text only presents a fraction.
-- There are lots of restrictions on how instructions/operands are
put together, but there is also an amazing amount of flexibility.
Registers
---------
The Intel architectures as a set just do not have enough registers
to satisfy most assembly language programmers. Still, the processors
have been around for a LONG time, and they have a sufficient number
of registers to do whatever is necessary.
For our (mostly) general purpose use, we get
32-bit 16-bit 8-bit 8-bit
(high part of 16) (low part of 16)
EAX AX AH AL
EBX BX BH BL
ECX CX CH CL
EDX DX DH DL
and
EBP BP
ESI SI
EDI DI
ESP SP
There are a few more, but we won't use or discuss them. They
are only used for memory accessability in the segmented memory
model.
Using the registers:
As an operand, just use the name (upper case and lower case both
work interchangeably).
EBP is a frame pointer (see Chapter 11).
ESP is a stack pointer (see Chapter 11).
Oddities:
This is the only architecture that I know of where the programmer
can designate part of a register as an operand. On ALL other
machines, the whole register is designated and used.
ONE MORE REGISTER:
Many bits used for controlling the action of the processor and
setting state are in the register called EFLAGS. This register
contains the condition codes:
OF Overflow flag
SF Sign flag
ZF Zero flag
PF Parity flag
CF Carry flag
The settings of these flags are checked in conditional control
instructions. Many instructions set one or more of the flags.
(Note that we only utilized SF and ZF in SASM.)
There are many other bits in the EFLAGS register: TO BE DISCUSSED
LATER.
The use of the EFLAGS register is implied (rather than explicit)
in instructions.
Accessing Memory
----------------
There are 2 memory models supported in the Pentium architecture.
(Actually it is the 486 and more recent models that support 2 models.)
In both models, memory is accessed using an address. It is the
way that addresses are formed (within the processor) that differs
in the 2 models.
FLAT MEMORY MODEL
-- The memory model that we use. AND, the memory model that every
other manufactures' processors also use.
--
SEGMENTED MEMORY MODEL
-- Different parts of a program are assumed to be in their own,
set-aside portions of memory. These portions are called
segments.
-- An address is formed from 2 pieces: a segment location and
an offset within a segment.
Note that each of these pieces can be shorter (contain fewer
bits) than a whole address. This is much of the reason that
Intel chose this form of memory model for its earliest
single-chip processors.
-- There are segments for:
code
data
stack
other
-- Which segment something is in can be implied by the memory
access involved. An instruction fetch will always be looking
in the code segment. A push instruction (we'll talk about this
with chapter 11) always accesses the stack segment. Etc.
Addressing Modes
----------------
Some would say that the Intel architectures only support 1 addressing
mode. It looks (something like) this:
effective address = base reg + (index reg x scaling factor) + displacement
where
base reg is EAX, EBX, ECX, EDX or ESP or EBP
index reg is EDI or ESI
scaling factor is 1, 2, 4, or 8
The syntax of using this (very general) addressing mode will
vary from system to system. It depends on the preprocessor
and the syntax accepted by the assembler.
For our implementation, an operand within an instruction that
uses this addressing mode could look like
[EAX][EDI*2 + 80]
The effective address calculated with be the contents of
register EDI multiplied times 2 added to the constant 80,
added to the contents of register EAX.
There are extremely few times where a high-level language
compiler can utilize such a complex addressing mode. It is
much more likely that simplified versions of this mode
will be used.
SOME ADDRESSING MODES
-- register mode --
The operand is in a register. The effective address is the
register (wierd).
Example instruction:
mov eax, ecx
Both operands use register mode. The contents of register ecx
is copied to register eax.
-- immediate mode --
The operand is in the instruction. The effective address is within
the instruction.
Example instruction:
mov eax, 26
The second operand uses immediate mode. Within the instruction
is the operand. It is copied to register eax.
-- register direct mode --
The effective address is in a register.
Example instruction:
mov eax, [esp]
The second operand uses register direct mode. The contents of
register esp is the effective address. The contents of memory
at the effective address are copied into register eax.
-- direct mode --
The effective address is in the instruction.
Example instruction:
mov eax, var_name
The second operand uses direct mode. The instruction contains
the effective address. The contents of memory
at the effective address are copied into register eax.
-- base displacement mode --
The effective address is the sum of a constant and the contents
of a register.
Example instruction:
mov eax, [esp + 4]
The second operand uses base displacement mode. The instruction
contains a constant. That constant is added to the contents
of register esp to form an effective address. The contents
of memory at the effective address are copied into register eax.
-- base-indexed mode -- (Intel's name)
The effective address is the sum of the contents of two registers.
Example instruction:
mov eax, [esp][esi]
The contents of registers esp and esi are added to form an
effective address. The contents of memory at the effective
address are copied into register eax.
Note that there are restrictions on the combinations of registers
that can be used in this addressing mode.
-- PC relative mode --
The effective address is the sum of the contents of the PC and
a constant contained within the instruction.
Example instruction:
jmp a_label
The contents of the program counter is added to an offset that
is within the machine code for the instruction. The resulting
sum is placed back into the program counter. Note that from the
assembly language it is not clear that a PC relative addressing
mode is used. It is the assembler that generates the offset
to place in the instruction.
Instruction Set
----------------
Generalities:
-- Many (most?) of the instructions have exactly 2 operands.
If there are 2 operands, then one of them will be required
to use register mode, and the other will have no restrictions
on its addressing mode.
-- There are most often ways of specifying the same instruction
for 8-, 16-, or 32-bit oeprands. I left out the 16-bit ones
to reduce presentation of the instruction set. Note that
on a 32-bit machine, with newly written code, the 16-bit form
will never be used.
Meanings of the operand specifications:
reg - register mode operand, 32-bit register
reg8 - register mode operand, 8-bit register
r/m - general addressing mode, 32-bit
r/m8 - general addressing mode, 8-bit
immed - 32-bit immediate is in the instruction
immed8 - 8-bit immediate is in the instruction
m - symbol (label) in the instruction is the effective address
Data Movement
-------------
mov reg, r/m ; copy data
r/m, reg
reg, immed
r/m, immed
movsx reg, r/m8 ; sign extend and copy data
movzx reg, r/m8 ; zero extend and copy data
lea reg, m ; get effective address
(A newer instruction, so its format is much restricted
over the other ones.)
EXAMPLES:
mov EAX, 23 ; places 32-bit 2's complement immediate 23
; into register EAX
movsx ECX, AL ; sign extends the 8-bit quantity in register
; AL to 32 bits, and places it in ECX
mov [esp], -1 ; places value -1 into memory, address given
; by contents of esp
lea EBX, loop_top ; put the address assigned (by the assembler)
; to label loop_top into register EBX
Integer Arithmetic
------------------
add reg, r/m ; two's complement addition
r/m, reg
reg, immed
r/m, immed
inc reg ; add 1 to operand
r/m
sub reg, r/m ; two's complement subtraction
r/m, reg
reg, immed
r/m, immed
dec reg ; subtract 1 from operand
r/m
neg r/m ; get additive inverse of operand
mul eax, r/m ; unsigned multiplication
; edx||eax <- eax * r/m
imul r/m ; 2's comp. multiplication
; edx||eax <- eax * r/m
reg, r/m ; reg <- reg * r/m
reg, immed ; reg <- reg * immed
div r/m ; unsigned division
; does edx||eax / r/m
; eax <- quotient
; edx <- remainder
idiv r/m ; 2's complement division
; does edx||eax / r/m
; eax <- quotient
; edx <- remainder
cmp reg, r/m ; sets EFLAGS based on
r/m, immed ; second operand - first operand
r/m8, immed8
r/m, immed8 ; sign extends immed8 before subtract
EXAMPLES:
neg [eax + 4] ; takes doubleword at address eax+4
; and finds its additive inverse, then places
; the additive inverse back at that address
; the instruction should probably be
; neg dword ptr [eax + 4]
inc ecx ; adds one to contents of register ecx, and
; result goes back to ecx
Logical
-------
not r/m ; logical not
and reg, r/m ; logical and
reg8, r/m8
r/m, reg
r/m8, reg8
r/m, immed
r/m8, immed8
or reg, r/m ; logical or
reg8, r/m8
r/m, reg
r/m8, reg8
r/m, immed
r/m8, immed8
xor reg, r/m ; logical exclusive or
reg8, r/m8
r/m, reg
r/m8, reg8
r/m, immed
r/m8, immed8
test r/m, reg ; logical and to set EFLAGS
r/m8, reg8
r/m, immed
r/m8, immed8
EXAMPLES:
and edx, 00330000h ; logical and of contents of register
; edx (bitwise) with 0x00330000,
; result goes back to edx
Floating Point Arithmetic
-------------------------
Since the newer architectures have room for floating point
hardware on chip, Intel defined a simple-to-implement
extension to the architecture to do floating point arithmetic.
In their usual zeal, they have included MANY instructions to
do floating point operations.
The mechanism is simple. A set of 8 registers are organized
and maintained (by hardware) as a stack of floating point
values. ST refers to the stack top. ST(1) refers to the
register within the stack that is next to ST. ST and ST(0)
are synonyms.
There are separate instructions to test and compare the values
of floating point variables.
finit ; initialize the FPU
fld m32 ; load floating point value
m64
ST(i)
fldz ; load floating point value 0.0
fst m32 ; store floating point value
m64
ST(i)
fstp m32 ; store floating point value
m64 ; and pop ST
ST(i)
fadd m32 ; floating point addition
m64
ST, ST(i)
ST(i), ST
faddp ST(i), ST ; floating point addition
; and pop ST
ETC. (see p.201-202)
I/O
---
The only instructions which actually allow the reading and
writing of I/O devices are priviledged. The OS must handle
these things. But, in writing programs that do something
useful, we need input and output. Therefore, there are some
simple macros defined to help us do I/O.
These are used just like instructions.
put_ch r/m ; print character in the least significant
; byte of 32-bit operand
get_ch r/m ; character will be in AL
put_str m ; print null terminated string given
; by label m
Control Instructions
--------------------
These are the same control instructions that all started with
the character 'b' in SASM.
jmp m ; unconditional jump
jg m ; jump if greater than 0
jge m ; jump if greater than or equal to 0
jl m ; jump if less than 0
jle m ; jump if less than or equal to 0
ETC. (see p. 205)