GAS中每個操作都是有一個字符的后綴,表明操作數的大小。
C聲明
|
GAS后綴
|
大小(字節)
|
char
|
b
|
1
|
short
|
w
|
2
|
(unsigned)
int / long / char*
|
l
|
4
|
float
|
s
|
4
|
double
|
l
|
8
|
long
double
|
t
|
10/12
|
注意:GAL使用后綴“l”同時表示4字節整數和8字節雙精度浮點數,這不會產生歧義因為浮點數使用的是完全不同的指令和寄存器。
操作數格式:
格式
|
操作數值
|
名稱
|
樣例(GAS = C語言)
|
$Imm
|
Imm
|
立即數尋址
|
$1
= 1
|
Ea
|
R[Ea]
|
寄存器尋址
|
%eax = eax
|
Imm
|
M[Imm]
|
絕對尋址
|
0x104
= *0x104
|
(Ea)
|
M[R[Ea]]
|
間接尋址
|
(%eax)= *eax
|
Imm(Ea)
|
M[Imm+R[Ea]]
|
(基址+偏移量)尋址
|
4(%eax)
= *(4+eax)
|
(Ea,Eb)
|
M[R[Ea]+R[Eb]]
|
變址
|
(%eax,%ebx)
= *(eax+ebx)
|
Imm(Ea,Eb)
|
M[Imm+R[Ea]+R[Eb]]
|
尋址
|
9(%eax,%ebx)=
*(9+eax+ebx)
|
(,Ea,s)
|
M[R[Ea]*s]
|
伸縮化變址尋址
|
(,%eax,4)=
*(eax*4)
|
Imm(,Ea,s)
|
M[Imm+R[Ea]*s]
|
伸縮化變址尋址
|
0xfc(,%eax,4)=
*(0xfc+eax*4)
|
(Ea,Eb,s)
|
M(R[Ea]+R[Eb]*s)
|
伸縮化變址尋址
|
(%eax,%ebx,4)
= *(eax+ebx*4)
|
Imm(Ea,Eb,s)
|
M(Imm+R[Ea]+R[Eb]*s)
|
伸縮化變址尋址
|
8(%eax,%ebx,4)
= *(8+eax+ebx*4)
|
注:M[xx]表示在存儲器中xx地址的值,R[xx]表示寄存器xx的值,這種表示方法將寄存器、內存都看出一個大數組的形式。
數據傳送指令:
指令
|
效果
|
描述
|
movl S,D
|
D <-- S
|
傳雙字
|
movw S,D
|
D <-- S
|
傳字
|
movb S,D
|
D <-- S
|
傳字節
|
movsbl S,D
|
D <-- 符號擴展S
|
符號位填充(字節->雙字)
|
movzbl S,D
|
D <-- 零擴展S
|
零填充(字節->雙字)
|
pushl S
|
R[%esp] <-- R[%esp] – 4;
M[R[%esp]] <-- S
|
壓棧
|
popl D
|
D <-- M[R[%esp]];
R[%esp] <-- R[%esp] + 4;
|
出棧
|
注:均假設棧往低地址擴展。
算數和邏輯操作地址:
指令
|
效果
|
描述
|
leal S,D
|
D = &S
|
movl地版,S地址入D,D僅能是寄存器
|
incl D
|
D++
|
加1
|
decl D
|
D--
|
減1
|
negl D
|
D = -D
|
取負
|
notl D
|
D = ~D
|
取反
|
addl S,D
|
D = D + S
|
加
|
subl S,D
|
D = D – S
|
減
|
imull S,D
|
D = D*S
|
乘
|
xorl S,D
|
D = D ^ S
|
異或
|
orl S,D
|
D = D | S
|
或
|
andl S,D
|
D = D & S
|
與
|
sall k,D
|
D = D << k
|
左移
|
shll k,D
|
D = D << k
|
左移(同sall)
|
sarl k,D
|
D = D >> k
|
算數右移
|
shrl k,D
|
D = D >> k
|
邏輯右移
|
特殊算術操作:
指令
|
效果
|
描述
|
imull S
|
R[%edx]:R[%eax] = S * R[%eax]
|
無符號64位乘
|
mull S
|
R[%edx]:R[%eax] = S * R[%eax]
|
有符號64位乘
|
cltd S
|
R[%edx]:R[%eax] = 符號位擴展R[%eax]
|
轉換為4字節
|
idivl S
|
R[%edx] = R[%edx]:R[%eax] % S;
R[%eax] = R[%edx]:R[%eax] / S;
|
有符號除法,保存余數和商
|
divl S
|
R[%edx] = R[%edx]:R[%eax] % S;
R[%eax] = R[%edx]:R[%eax] / S;
|
無符號除法,保存余數和商
|
注:64位數通常存儲為,高32位放在edx,低32位放在eax。
條件碼:
條件碼寄存器描述了最近的算數或邏輯操作的屬性。
CF:進位標志,最高位產生了進位,可用于檢查無符號數溢出。
OF:溢出標志,二進制補碼溢出——正溢出或負溢出。
ZF:零標志,結果為0。
SF:符號標志,操作結果為負。
比較指令:
指令
|
基于
|
描述
|
cmpb S2,S1
|
S1 – S2
|
比較字節,差關系
|
testb S2,S1
|
S1 & S2
|
測試字節,與關系
|
cmpw S2,S1
|
S1 – S2
|
比較字,差關系
|
testw S2,S1
|
S1 & S2
|
測試字,與關系
|
cmpl S2,S1
|
S1 – S2
|
比較雙字,差關系
|
testl S2,S1
|
S1 & S2
|
測試雙字,與關系
|
訪問條件碼指令:
指令
|
同義名
|
效果
|
設置條件
|
sete D
|
setz
|
D = ZF
|
相等/零
|
setne D
|
setnz
|
D = ~ZF
|
不等/非零
|
sets D
|
|
D = SF
|
負數
|
setns D
|
|
D = ~SF
|
非負數
|
setg D
|
setnle
|
D = ~(SF ^OF) & ZF
|
大于(有符號>)
|
setge D
|
setnl
|
D = ~(SF ^OF)
|
小于等于(有符號>=)
|
setl D
|
setnge
|
D = SF ^ OF
|
小于(有符號<)
|
setle D
|
setng
|
D = (SF ^ OF) | ZF
|
小于等于(有符號<=)
|
seta D
|
setnbe
|
D = ~CF & ~ZF
|
超過(無符號>)
|
setae D
|
setnb
|
D = ~CF
|
超過或等于(無符號>=)
|
setb D
|
setnae
|
D = CF
|
低于(無符號<)
|
setbe D
|
setna
|
D = CF | ZF
|
低于或等于(無符號<=)
|
跳轉指令:
指令
|
同義名
|
跳轉條件
|
描述
|
jmp
Label
|
|
1
|
直接跳轉
|
jmp
*Operand
|
|
1
|
間接跳轉
|
je
Label
|
jz
|
ZF
|
等于/零
|
jne
Label
|
jnz
|
~ZF
|
不等/非零
|
js
Label
|
|
SF
|
負數
|
jnz
Label
|
|
~SF
|
非負數
|
jg
Label
|
jnle
|
~(SF^OF) & ~ZF
|
大于(有符號>)
|
jge
Label
|
jnl
|
~(SF ^ OF)
|
大于等于(有符號>=)
|
jl
Label
|
jnge
|
SF ^ OF
|
小于(有符號<)
|
jle
Label
|
jng
|
(SF ^ OF) | ZF
|
小于等于(有符號<=)
|
ja
Label
|
jnbe
|
~CF & ~ZF
|
超過(無符號>)
|
jae
Label
|
jnb
|
~CF
|
超過或等于(無符號>=)
|
jb
Label
|
jnae
|
CF
|
低于(無符號<)
|
jbe
Label
|
jna
|
CF | ZF
|
低于或等于(無符號<=)
|
轉移控制指令:(函數調用):
指令
|
描述
|
call
Label
|
過程調用,返回地址入棧,跳轉到調用過程起始處,返回地址是call后面那條指令的地址
|
call
*Operand
|
leave
|
為返回準備好棧,為ret準備好棧,主要是彈出函數內的棧使用及%ebp
|
用GCC在C中潛入匯編代碼:
asm( code-string [:output-list [ :
input-list [ :overwrite-list]]]);
注意,后面的參數(如overwrite-list)如果為空則不要相應的“:”,而如果前面參數(如output-list)為空則需要用“:”占位。
如:
asm ("..."
: //output需要占位
: "r" (src) //后面的Overwrites不能寫,我測試的結果是寫了編譯不過
};
如:
Int ok_umul(unsigned x,unsigned y,unsigned
*dest)
{
int
result;
asm(“movl %2 , %%eax; mull %3; movl %%eax,%0;\
setae %dl; movzbl
%%dl,%1”
: “=r” (*dest)
, “=r” (result) //output
: “r” (x) , “r”
(y) //inputs
: “%ebx” , “%edx” //Overwrites
);
return result;
}
我們用%0--%n表示輸入的參數,從前往后統一編號(如上例中*dest表示%0,reset是%1,x是%2,y是%3),”r”表示整數寄存器,”=”表示對其進行了賦值。%eax要寫成%%eax,這是c語言字符串的規則,別忘了code-string就是一個c語言的字符串。