##IA32 Registers:
-
Eight registers(first six are general purpose):
- eax(ax/ah/al)
- ecx
- edx
- ebx
- esi/si
- edi/di
- esp/sp (Stack pointer)
- ebp/bp (Frame pointer)
-
The lower order bits can be accessed without altering higher bits.
Build code with level 1 optimization:
gcc -O1 -S code.c
gcc -O1 -o code.c
gcc -O1 prog code.o main.c
Check binary file::
objdump -d main.o
$Imm
: Immediate(liteal) valueEa
: registerR[Ea]
Imm
: Absolute memoery address valueM[Imm]
(Ea)
: Indirect memoery addressM[R[Ea]]
Imm(Eb)
: Base+displacementM[Imm+R[Eb]]
(Eb,ei)
: Indexed.M[R[Eb]+R[Ei]]
Imm(Eb,Ei)
: IndextedM[Imm+R[Eb]+R[Ei]]
(,Ei,s)
: Scale indexed:M[R[Ei]*s]
Imm( ,Ei,s)
: Scaled indexed:M[Imm+R[Ei]*s]
(Eb,Ei,s)
: Scaled Indexed:M[R[Eb]+R[Ei]*s]
Imm(Eb,Ei,s)
: Scaled indexed:M[Imm+R[Eb]+R[Ei]*s]
Note: scaling factor s
must be either 1,2,4,8
MOV
can only move from immediate value(literal) to register/memory, register to register/memory, and memory to register. If need to move between memory, needs two steps: load value from memory to register, then write register value to destination.
-
MOV S,D
: move value from S to D- movb
- movw
- movl
-
MOVS S,D
: sign-extended move (byte to word, byte to dw, word to dw)- movsbw
- movsbl
- movswl
-
MOVZ S,D
: zero-extended move (byte to word, byte to dw, word to dw)- movzbw
- movzbl
- mvzwl
-
PUSH S
: reduceESP
by 4 (points to next word in memory), then moveS
into memoery where stack pointerESP
points to, Equivalent:subl $4, %esp #R[%esp] <- R[%esp] - 4 movl S, (%esp) #M[R[%esp]] <- S
-
POP D
: Pop double word whichESP
points to, put it to D, then moveESP
. Equivalent:movl (%esp), D #M[R[%esp]] -> D addl $4, %esp #R[%esp] <- R[%esp] + 4
Load effective address (leal): it's a variant of movl
. First operand is a form of a memoery reference. but does not use it to reference memory, but just copy the value (of the expression) to the second operand. Compilers often find clever uses of leal that have nothing to do with effective address computations. The destination operand must be a register.
## if %edx saves value of x, then
leal 7(%edx, %edx, 4), %eax # saves 5x+7 into %eax. (first operand is a scaled indexed memery expression)
INC D
: incrementDEC D
: decrementNEG D
: negateNOT D
: complementADD S,D
: add, and destination isD
SUB S,D
: subtract:D <- D-S
IMUL S,D
: multiplyD <- D*S
XOR S,D
OR S,D
AND S,D
SAL k,D
: left shiftD <- D<<k
SHL k,D
: left shift (same as SAL)SAR k,D
: arithmetic right shiftD <- D >>(A) k
SHR k,D
: logical right shiftD <- D >>(L) k
imull S
: signed full multiply. MultiplyS
andR[%eax]
and saves results inR[%edx]:R[%eax]
mull S
: unsigned full multiplycltd
: ConvertR[%eax]
into quad word(64bit), store intoR[%edx]:R[%eax]
idivl S
: signed divideR[%edx] <- R[%edx]:R[%eax] mod S
|R[%eax] <- R[%edx]:R[%eax] / S
divl S
: unsigned divide
CF
: Carry Flag: the most recent operation generated a carry out of the most significant bit. used to detect overflow for unsigned operationsZF
: Zero Flag: the most recent operation yielded zeroSF
: Sign Flag: The most recent operation yielded a negative valueOF
: Overflow Flag: The most recent operation caused a two's-complement overflow - either negative or positive
For example, we perform ADD
for C assignments t = a + b
.
CF: (unsgiend) t < (unsigned) a #Unsigned overflow
ZF: (t==0) #Zero
SF: (t<0) #Negative
OF: (a<0 == b<0) && (t<0 != a<0) #signed overflow (a,b同号, t, a异号)
The leal
instruction doesn't alter any codes, since it's intended for address operation.
- For logical operations such as
XOR
, carry and overflow flags are set to 0. - For shift operations, carry flag is set to the last bit shifted out, while over flow flag is 0
Inc
andDec
set overflow and zero flags, but leave carry flag unchanged
CMP
and TEST
CMP
acts like sub
, but doesn't update destination, just set flags.
TEST
acts like AND
, but doesn't update destination, jsut set flags.
Rather than directly read them, there are three common ways to acess codes:
- set a single byte to 0 or 1 depending on some combination of the condietion codes
- We can conditionally jump to some other part of the program
- we can conditionally transfer data
For the first case, we uset SET
instructions. the descriptions apply to the case where a comparison instruction has been executed, setting the condition codes.
Note that SET
only sets one byte.(%al,%bl,etc.), we need to clear high-order 24 bits. like this setl %al ; movzbl %al, %eax
sete D
/setz D
: Equal/zeroD <- ZF
setne D
/setnz D
: not equal/not zeroD <- ~ZF
sets D
: negativeD<-SF
setns D
: non negativesetg D
/setnle D
: greater(signed >) :D <- ~(SF^OF)&~ZF
setge D
/setnl D
: greater or equal (signed >=):D <- ~(SF^OF)
setl D
/setnge D
: Lesssetle D
/setng D
: Less or equal(signed <=)D <- (SF^OF)|ZF
seta D
/setnbe D
: Above (unsigned >)D <- ~CF & ~ZF
setae D
/setnb
: Above or equal (unsigned >=)D <- ~CF
setb D
/setnae D
: BelowD <- CF
setbe D
/setna D
: Below or equalD <- CF|ZF
jump instructions jumps to _label_s in assembly code. some instructions jumps unconditionally, some depends on flags.
Conditional jumps either jump, or continue executing.
Direct jump: target is encoded as part of the instruction, like a label.
indirect jump: target is read from a register or a memory location. written using "*" followed by an operand specificier:
jmp *%eax #uses the value in register %eax as the jump target
jmp *(%eax) #reads jump target from memory which is addressed using value in %eax
Jump encodings: Most commonly are PC relative. They encode differences between the address of the target instruction, and the address of the instruction immediately following the jump. Or use absolute address, which is 4 bytes.
jmp Label
: jump to labeljmp *Operand
: jump to address specified byOperand
je Label
/jz
: equal/zerojne Label
/jnz
: not equal/not zerojs
: negativejns
non negativejg
/jnle
: greaterjge
/jnl
: greater or equaljl
/jnge
: lessjle
/jng
: less or equalja
/jnbe
: abovejae
/jnb
: above or equaljb
/jnae
: belowjbe
/jna
: below or equal
###Conditional move instructions
Conditional data movement insteaad of control, which is better suited for pipelining and usually better performance
cmovge S, D
cmovnz S, D
- ...
For control branching, processor needs branch prediction during pipelining to process future instructions, when the prediction misses, it can incur a serious penalty. While for conditional move(data branching), pipeline is always full and the flow of control does not depend on data.
However, if the branches are expensive to calculate, using data branching may not be good because both branches(then-expr and else-expr) needs to be calculated.
A jump table is an array where entry i is the address of a code segment implementing the action of the program should be taken when the switch index equals i.
jmp *.L8(, %eax, 4) # example of switch. where L8 is a lable,
#and it is followed by actual labels that we jumps to. %eax stores
#the index. the actual jump destination is the value stored at (4*R[%eax] + L8)