在阅读linux/unix内核
源代码的时候,必须先掌握
汇编,大家都知道,
内核代码用的
编译器是
gcc,而gcc采用的是AT&T的汇编格式,与MS的intel有些区别。
BSD爱好者乐园)fo$]N'f7Z
v Z-GD一 AT&T的基本语法
W/l4w&Mf*P&e!M,~ nBSD爱好者乐园SS)r0z6pW语法上主要有以下几个不同.BSD爱好者乐园?S w2}D^ r'w7w
KD5DE2K'YM
|"MxS.Ih★ 寄存器命名原则
x&nDeK.dm#o"RHw K
z{AT&T: %eax Intel: eax
'N9xz"G8H,D3h$Rd/H a/zPU8YqjV★ 源/目的操作数顺序
]z f-{(k{^-]7{5Mx1lAT&T: movl %eax,%ebx Intel: mov ebx,eax
7|U0c^0X5D,Y"Ct9CR)p★ 常数/立即数的格式
*z#|U4UF1I
@s8t;J
b U
DAT&T: movl $_value,%ebx Intel: mov eax,_valueBSD爱好者乐园
Y6aac0Xc
BSD爱好者乐园Yi/_V$xC l3@0G:\把_value的地址放入eax寄存器BSD爱好者乐园z6SD a4p)K$_
,NU$F
l
E|N
QAT&T: movl $0xd00d,%ebx Intel: mov ebx,0xd00d
`r7W \qM+{%oqN]`'NRs n★ 操作数长度标识
6gcW0L)p
_vBSD爱好者乐园%n
N(Y_"^KLlAT&T: movw %ax,%bx Intel: mov bx,ax
x2T0e:JU_[u1n{BSD爱好者乐园m)hU1i#~★寻址方式
~O0`Du5dcJ_:n QBSD爱好者乐园I
VX4{#B(| R*\j1dC,HAT&T: immed32(basepointer,indexpointer,indexscale)
]5Vk[7ur+Ce%~Te:Z3}+q1s-EIntel: [basepointer + indexpointer*indexscale + imm32)BSD爱好者乐园p3r'Ru(ssu
BSD爱好者乐园RFt&_"TLinux工作于保护模式下,用的是32位线性地址,所以在计算地址时
/u![8pI2G kYBSD爱好者乐园-v'?4iP&h}u'`%R不用考虑segment:offset的问题.上式中的地址应为:BSD爱好者乐园}/WNY1@ P,bL
BSD爱好者乐园jZx$RqHiimm32 + basepointer + indexpointer*indexscale
l6eH5_+Mdw"o_nsxBSD爱好者乐园
t t6q6u |下面是一些例子:
4DB4R)`2{3v]JyBSD爱好者乐园KGQJI@★直接寻址
(]:gG%qy)m#A
D(HhRN7v6T$lb'Ml)YAT&T: _booga ; _booga是一个全局的C变量BSD爱好者乐园E%z,NxK)Y3F"Sc
_
BSD爱好者乐园0}0WH#_U$\5n)b注意加上$是表示地址引用,不加是表示值引用.BSD爱好者乐园,b@ie$U1Iu1FbNit
[
c7E
B @2W注:对于局部变量,可以通过堆栈指针引用.
)[)OOl4FX7{x5kpK$p RIntel: [_booga]
Imr M9JyBSD爱好者乐园,b_$o0b+G?★寄存器间接寻址
"q(RKKbP6|;u\;B3[G3SUE$OXAT&T: (%eax)
R+}2j;q0}Ub-j9U(I4y"@fI.HtbeIntel: [eax]BSD爱好者乐园Y:m,p-lvc{`)GAw
uQ2r$z)uS/t7A★变址寻址BSD爱好者乐园U{M2O`R }U
BSD爱好者乐园Dah#Oc7TT.s$MAT&T: _variable(%eax)BSD爱好者乐园5yUIYCe
/G_&gJ JR4OIntel: [eax + _variable]
`(`)Q6{5XJ4N[6UblD2_AT&T: _array(,%eax,4)
H6_
v"_-Uz-T1V Pu$q+Bc6j uIntel: [eax*4 + _array]
v-QlN0p^G#EBSD爱好者乐园Y6j~
Q,fK7M q;WkAT&T: _array(%ebx,%eax,8)
8?$bJ'wQMBSD爱好者乐园0xZ3lA;]
V"KIntel: [ebx + eax*8 + _array]BSD爱好者乐园Geh&[&om~"k
@$b)Y0C/vU.SBSD爱好者乐园hF!z.nTJf2H9`Py二 基本的行内汇编BSD爱好者乐园`9Vr7U\(a#G'}+S8G
BSD爱好者乐园9P,NQq3GZ基本的行内汇编很简单,一般是按照下面的格式
g_9t9E1R8J5G[X.Ag(eI'aasm("statements");
9v\%]M3C3O&q3c(O\!J!iaW例如:asm("nop"); asm("cli");
P'j:TI#]#nZofX&B?6j@?\,tasm 和 __asm__是完全一样的.BSD爱好者乐园U-f*U3f/AO.E
!C b$bs0T)H如果有多行汇编,则每一行都要加上 "\n\t"BSD爱好者乐园*A
v @^aDXw7MY!i
BSD爱好者乐园]jA;\ l1nKq例如:
`!nqud$y ^
q7?VM,T\dC.Eh:i
|asm( "pushl %eax\n\t"BSD爱好者乐园L(wGY S
l{z
BSD爱好者乐园(@DsP%T#x4z)x}K"movl $0,%eax\n\t"BSD爱好者乐园?X5V9C@I
f ka
4w$K1D![6^Rj~"popl %eax");
*q)c]e1|JBSD爱好者乐园BS/UpQw4_N
~`实际上gcc在处理汇编时,是要把asm(...)的内容"打印"到汇编
mqh}aPa?9udBSD爱好者乐园 H9w'\4vMuz
R文件中,所以格式控制字符是必要的.BSD爱好者乐园&|tucZ3@r
BSD爱好者乐园!u|
Iqe]f再例如:BSD爱好者乐园pIbI,Nx{
!PW#il?
}asm("movl %eax,%ebx");
p1a CRgNPfx |
k)Rm{asm("xorl %ebx,%edx");BSD爱好者乐园1M){!` o1Hm['e H)G
w
BSD爱好者乐园?xjPIasm("movl $0,_booga);
_J2[Dx RbC3Y/Je}@在上面的例子中,由于我们在行内汇编中改变了edx和ebx的值,但是BSD爱好者乐园
t^v/m2^5E0|
bw/~&ds%})UN由于gcc的特殊的处理方法,即先形成汇编文件,再交给GAS去汇编,BSD爱好者乐园
}V h
W
INl4HL
BSD爱好者乐园Kb2}!Kz(d*jZ所以GAS并不知道我们已经改变了edx和ebx的值,如果程序的上下文BSD爱好者乐园`8D
Wo \
Dj
9fK jy7h需要edx或ebx作暂存,这样就会引起严重的后果.对于变量_booga也
Q[UU0Uc&n:z&G4]Qh存在一样的问题.为了解决这个问题,就要用到扩展的行内汇编语法.
([KBc!tQ
Aw:^9gQzmBSD爱好者乐园&E_-Rv6uf,xn[三 扩展的行内汇编
n[9^m6E$M6w!dfd I8t%Y扩展的行内汇编类似于Watcom.BSD爱好者乐园_
D\+Cm5T7QJ
]
BSD爱好者乐园_CXY t,Q基本的格式是:BSD爱好者乐园G8K
}bxsD-v~,N
BSD爱好者乐园4S Vn/H7BE:v"fQasm ( "statements" : output_regs : input_regs : clobbered_regs);
5U
_:ic @'QXBSD爱好者乐园 j
ncbcclobbered_regs指的是被改变的寄存器.
yU'j-RU\|yA6C4k8G;V^tp下面是一个例子(为方便起见,我使用全局变量):
ar5CQC
mm(m4fK~n!aC`,@int count=1;
#dU
Z(x"]/vH4h!HJOJ/Rint value=1;BSD爱好者乐园ow-U$xF,Mm
k!a6qO$J2qZP-[int buf[10];
h7[NlN5M'`Np5fZ3svoid main()
WS)t P,|1bx |)HkBSD爱好者乐园*ZT2N[1L{BSD爱好者乐园MlQ%eRQBYm
;Zd6j^e`*bvasm(BSD爱好者乐园:i:r0Sg4rfC
BSD爱好者乐园`Y[^4G&O5s$N|"cld \n\t"BSD爱好者乐园!A\O{hB
l0p[!J{jK4dZP"rep \n\t"
:M8G HF]3aBSD爱好者乐园,kD"{1C@e#~r
S"stosl"BSD爱好者乐园:k+v7lS)p:n"v`'c
V!e8['t3L&CZ-C;P*^t:
)?;r+Vp
AAn3sBSD爱好者乐园,xo
qxpg9A: "c" (count), "a" (value) , "D" (buf[0])
y"N4D;BOXgBSD爱好者乐园SNOg8g4@sAs: "%ecx","%edi" );
9QPlOK~x5Td mQZ c/lB:@i0W%V}
/Yty#_J!Y!vkp'SDb)|V0b'@]d2X得到的主要汇编代码为:
/}KM%}0V sU+b,mThBSD爱好者乐园1Bo{(hJn6p3kOmovl count,%ecx
Tc r}2y6y&f3fBSD爱好者乐园O4@Zez5?!A ctmovl value,%eaxBSD爱好者乐园+s+jscN D1hE(e9z
BSD爱好者乐园
}a}(i S'Y!c p(Dmovl buf,%ediBSD爱好者乐园-q7xsOStW
BSD爱好者乐园.I? CGC^+w k#APPBSD爱好者乐园
~-y8S8s"gE
BSD爱好者乐园2Eta/?$pl1S+V8Lp.m2Ccld
2jE8v)i4nBSD爱好者乐园7]"]4T.V x%b7aQ
Orep
0p oZ2D1KAx
tBSD爱好者乐园lU;@7M#aL1~bstoslBSD爱好者乐园+@0O;|~5v R$Ct
BSD爱好者乐园)E4UX@&];I;m.j#NO_APPBSD爱好者乐园+B/]LXwll;zt3l~4D
BSD爱好者乐园"d"iR)Z2F.@bKP3tcld,rep,stos就不用多解释了.
OYp
m0wJ-R/P)~QO3CaH1u4B1q这几条语句的功能是向buf中写上count个value值.BSD爱好者乐园p!X"?;Q VM$hP
l5vPKM2X冒号后的语句指明输入,输出和被改变的寄存器.BSD爱好者乐园` v@'ydX)aLh
3j"Y@Di'ZweZ通过冒号以后的语句,编译器就知道你的指令需要和改变哪些寄存器,
)w%B)a`!b]}BSD爱好者乐园'N"b0o.mJN.S m{从而可以优化寄存器的分配.
x
mF+? KHVrJBSD爱好者乐园"l
g,GP1Y其中符号"c"(count)指示要把count的值放入ecx寄存器BSD爱好者乐园Mt
Yk*AK3ZVfB6L_
BSD爱好者乐园'E~Ga3}uP+k类似的还有:
f"?S_AxBSD爱好者乐园$x^$c
eR&?Ua eax
6UY3F"}
^vfM1I8zd?b ebxBSD爱好者乐园t,g,|%F| l
*j&z
sL jO \c ecx
v1l;Y!Z
V9d$j{YkIRw
m8k7mxd edxBSD爱好者乐园u
y"pf4?@
7y3yL(HF |'P WX.BS esiBSD爱好者乐园$^8Ci
J@ \2a*w(S7O
BSD爱好者乐园 [ ZsYNW;lD edi
Z*`cTrBSD爱好者乐园el`GwY
G3\"W+AI 常数值,(0 - 31)BSD爱好者乐园JGN*Xo6`[
BSD爱好者乐园0W6|8sy]#Hq,r 动态分配的寄存器
]N#R1lyR
n%R/L qf#`&d