看懂PowerPC汇编之指令集架构
看懂PowerPC汇编,需要如下3⽅⾯的知识:
1.PowerPC指令集架构即Power ISA,可以从获得,包括寄存器定义,数据模型,寻址⽅式和指令定义以及指令助记符;
2.PowerPC ABI即应⽤程序⼆进制接⼝,即寄存器的使⽤规范和栈调⽤结构;
3.PowerPC Pseudo-ops,即.text, .align n等汇编语⾔中常⽤的伪操作符。
PowerPC ISA分为3个级别即“Book”,分别对应于⽤户指令集体系结构,虚拟环境体系结构和操作环境体系结构。其中Book III分化出了服务器版本Book III-S(经典PowerPC架构)和嵌⼊式版本Book III-E(专门为嵌⼊式优化的版本)。
1.寄存器定义:
PowerPC处理器寄存器分为2⼤类-专⽤寄存器和⾮专⽤寄存器。其中,⾮专⽤寄存器包括32个通⽤⽬的寄存器(GPR),32个浮点寄存器(FPR),条件寄存器(CR),浮点状态和控制寄存器(FPSCR);专⽤寄存器主要包括连接寄存器(LR),计数寄存器(CTR),机器状态寄存器(MSR)
以及时间基准寄存器(TBL/TBU)等等。PPC4xx系列处理器还有DCR寄存器,需要⽤专门的指令访问。这⾥有两点需要注意:
1. PowerPC处理器可以运⾏于两个级别,即⽤户模式和特权模式。⽤户模式下,仅有GPR,FPR,CR,FPSCR,LR,CTR,XER以及TBL/TBU可以访问。从Power ISA
2.05开始,DCR寄存器也可以在通过⽤户模式DCR访问指令进⾏访问。
2.PowerPC处理器没有专⽤的栈指针寄存器和PC指针寄存器,也就是说硬件不负责维护调⽤栈。
2.数据模型:
PowerPC⽀持如下数据格式:byte, halfword, word, doubleword,quadword, 同时默认⽀持big-endian字节序,即MSB(最⾼有效字节,例如0x12345678中0x12即MSB)保存在低地址。little-endian字节序可以通过修改设置⽀持。
注意:PowerPC习惯, msb(最⾼有效位)为bit0,lsb为bit31.
3.寻址⽅式
PowerPC没有专门的IO操作指令,所有地址访问⼀视同仁,并且只⽀持地址和寄存器之间的访问。因此寻址⽅式⾮常简单,可以概括为2类6种:
3.1 Load/store/算术/逻辑/cache指令:
a)寄存器间接寻址模式,通常写作RA或者RB;
b)寄存器间接⽴即数索引寻址模式,即(基址寄存器+⽴即数偏移)寻址模式,通常写作d(RA);
c)寄存器间接索引寻址模式(基址寄存器 + 偏移寄存器)寻址模式,通常写作RA,RB。
注意:对于三种模式,若寄存器为GPR0,则其内容被忽略,并以0代替其内容。
3.2 跳转指令:
a)⽴即数寻址模式;
b)链接寄存器(LR)模式,即⽬的地址被保存在LR中;
c)计数寄存器(CTR)模式,即⽬的地址保存在CTR中。
注意:实际上还有⼀些特殊的跳转指令rfi/rfci/rfmci,其⽬的地址保存在SRR0/CSRR0/MCSRR0中。
4.指令定义和指令助记符:
PowerPC指令的长度都是4字节,但是种类繁多,⽽且有些指令极其复杂。因此,通常情况下,PowerPC汇编编程中采⽤指令和助记符混⽤的⽅式。 助记符主要⽤来简化内存访问、算术运算、逻辑运算等常⽤指令,例如⽤bne target代替bc 4,2,target表⽰不为零则跳转。下⾯仅以⼀些常见的汇编代码⽚段来做⼀些简单的归纳,具体信息请参考相应的处理器core⽤户⼿册或者Power ISA。注意,cache和MMU指令会跟其实现⼀起介绍,此处不再赘述。
4.1 读取⼀个word(0x12345678)到⽬的寄存器
lis RA,0x12345678@h /* ⾼16位(0x1234)偏移16位后变成0x12340000放进RA */
ori RB, RA, 0x12345678@l /* RA与低16位(0x5678)相或后构成完整数据放进RA */
注意:PowerPC指令中, i后缀表⽰⽴即数,s后缀表⽰左移16位。例如addi、addis、ori、oris等。这段代码也可以⽤来读取某个变量的值,只需要把⽴即数替换成变量名。
2.从某个地址(0x56789abc)读取数据
lis RA,0x56789abc@ha /* 调整后的⾼16位(0x5679)偏移16位后变成(0x56790000)放进RA */
lwz RB, 0x56789abc@l (RA) /* RA加上低16位(0xffff9abc) 构成完整数据地址,然后将其内容放进RB */
注意:
@l,@h和@ha:⽤于算术运算的操作数(包括addi的操作数)时,@l获取的是符号扩展的低16位数据(0xffff9abc) ,因此⾼16位必须进⾏根据bit15进⾏调整,⽽不能简单的使⽤@h来获取。
load/store指令的通常格式为(l/st)(w/h/b)(z/br)(u/x) RA,… . 其中l代表读取数据到RA中;st代表将RA的内容写⼊内存;w/h/b 分别代表针对word、halfword/byte进⾏操作;z仅⽤于读取数据,代表字或者半字读到寄存器中后将其⾼位清零(注意:对word的读取⽆意义,但必须加);br代表读取后或者存⼊前对数据进⾏字节序反转;u代表从某个内存地址读取数据后,同时更新保存内存地址的寄存器;x代表使⽤寄存器间接索引寻址模式(基址寄存器 + 偏移寄存器)寻址模式(默认使⽤寄存器间接⽴即数索引寻址模式) 这段代码也可以⽤来访问数组或者结构中的某个成员,或者指针指向的地址块中的数据,只需把⽴即数换成相应的数组名、结构名或者指针即可。
3.⼊栈/出栈操作
⼊栈:
stwu 1, –16(1) /* 原始栈指针GPR1保存在新栈顶(原始栈指针减去16)*/
mflr 0 /* LR暂存在GPR1 */
stw 0, 20(1) /* 保存LR到调⽤者的栈中 */
出栈:
lwz 0, 20(1) /* LR出栈 */
mtlr 0 /* 恢复LR */
addi r1, r1, 16 /* 销毁栈 */
注意:栈定义会在ABI部分详细解释,此处不再赘述。
4.循环
li 0, 10 /* 循环次数暂存⼊GPR0 */
mtctr 0 /* 更新计数寄存器 CTR*/
label:
… /* 需要重复执⾏的指令 */
bdnz label /* 递减计数器,不等于0则跳转到标号处重复执⾏ */
注意:
label类似于C语⾔中的标号,因此在同⼀段代码中,不能重复。因此,习惯中使⽤数字标号来代替。数字标号作为跳转指令的⽬的地址时,通常在其后⼀个b表⽰向最近的低地址数字标号跳转,加f表⽰向最近的⾼地址数字标号跳转。例如beq 1f或者blt 2b。注意,标号,不管是数字形式还是字母形式,都可以⽤作⼀个代表标号所对应⾏的地址的变量使⽤。例如,可以⽤lis RA, 1f@ha; lwz RB, 1f@l(RA)可以⽤来获取标号1f处的指令内容。
跳转指令分为条件跳转和⽆条件跳转两种:
⽆条件跳转主要有b(跳转到相对地址)\ba(跳转到绝对地址)\blr(跳转到连接寄存器)\bctr(跳转到计数寄存器)4种;(注意,rfi、rfci、rfmci等异常返回指令也可以看做是特殊的⽆条件跳转。)
条件跳转指令分为两种:需要配合⽐较指令/算术指令/逻辑运算指令使⽤的beq(相等或者为0则跳转)
/bne(不等或者⾮0则跳转)/blt(⼩于则跳转)/bgt(⼤于则跳转)/ble(⼩于等于则跳转)/bge(⼤于等于则跳转)/bnl(不⼩于则跳转)/bng(不⼩于则跳转)等和需要配合计数寄存器CTR使⽤的bdz(CTR递减到0则跳转)/bdnz(CTR没有递减到0则跳转)等。
此外条件跳转指令还可以增加后缀a表⽰跳转到绝对地址;所有跳转指令增加后缀l表⽰同时更新连接寄存器(LR),⽤于⼦程序调⽤。
配合条件跳转指令使⽤的⽐较指令主要是cmp(l)w(i),其中l表⽰逻辑⽐较既⽆符号数⽐较,w表⽰⽐较2个word,i表⽰寄存器内容跟⽴即数进⾏⽐较;
配合条件跳转指令使⽤的算术指令必须加上后缀“.”⽤以表⽰更新条件寄存器CR,主要有add(寄存器内容相加)/addi(寄存器内容跟⽴即数相加)/addis(⽴即数左移16位后跟寄存器内容相加)和subi(寄存器内容减去⽴即数)/subis(寄存器内容减去左移16位后的⽴即数)/subf(从RB(第三个参数)中减去RA(第⼆个参数)的内容放⼊RT(第⼀个参数));
配合条件跳转指令使⽤的逻辑指令也必须加上后缀“.”⽤以表⽰更新条件寄存器CR,主要包括and(i)(s)/or(i)(s)。
CTR等专⽤寄存器必须通过专⽤命令mfspr rD,SPR和mtspr SPR,rS或者
mfctr/mtctr/mflr/mtlr/mfspr/mtspr/mftbl/mftbu/mttbl/mttbu鞥助记符进⾏操作。此外,DCR寄存器必须通过
mfdcr/mtdcr/mfdcrx/mtdcrx/mfdcrux/mtdcrux等进⾏操作。注意,后⾯4条DCR指令仅在Power ISA 2.05及更⾼版本⽀持。
5.强⼤的位操作指令
PowerPC有3条强⼤的位操作指令,⼏乎能实现你能想象的所有位操作。
a)rlwinm(.) rA,rS,SH,MB,ME 寄存器RS的内容循环左移⽴即数SH位,然后跟⽴即数MB和ME形成的MASK相与后放进RA
b)rlwnm(.) rA,rS,RB,MB,ME 类似于上⼀条指令,只是把左移的位数放到了寄存器RB中
c)rlwimi(.) rA,rS,SH,MB,ME 寄存器RS的内容循环左移⽴即数SH位,然后跟⽴即数MB和ME形成的MASK相与,再把RA的内容跟⽴即数MB和ME形成的MASK的补码相与,即清掉RA中MASK对应的位,最后把处理后的RS和RA的内容相或,放⼊RA中
汇编语言跳转指令注意:MASK形成的规则是,如果MB⼩于等于ME,则MB到ME之间的位全部置1,包括这两位,形成MASK;否则,MB到ME之间的位清0,其他位包括这两位置1,形成MASK。
下⾯给出⼏个例⼦:
a)从⽴即数0x12345678(RS)中抽取bit 20-23,并左移16位,从⽽得到0x06000000.
rlwinm rA, rS, 16, 4, 7
具体过程如下:0x12345678循环左移16位得到0x56781234,然后与MASK0x0f00 0000 (MASK[4,7])相与。
* 该指令可以⽤来抽取C语⾔代码或者寄存器中的位域。
b)清除⽴即数0x12345678(RS)的bit 28 - 31,并右移24位,从⽽得到0x0012 3456
rlwinm rA, rS, 24, 8, 31
具体过程如下:0x12345678循环左移24位得到0x78123456,然后与MASK0x00ff ffff (MASK[8,31])相与。
* 该指令可以进⾏除数或者乘数为2的倍数的乘法/除法操作。
c)清除⽴即数0x12345678(RS)的bit 6,从⽽得到0x10345678
rlwinm rA, rS, 0, 7, 5
具体过程如下:0x12345678循环左移0位,仍是0x56781234,然后与MASK0xfdff ffff (MASK[7,5])相与。
* 该指令可以⽤来清除C语⾔代码或者寄存器中的位域。
d)抽取0x87654321(RS)的bit 24-31,⽤以对⽴即数0x12345678(RA)的bit 8-15进⾏先清除后置位的操作,从⽽得到
0x12215678.
rlwimi rA, rS, 16, 8, 15
具体过程如下:0x87654321(RS)循环左移16位得到0x43218765,然后与MASK0x00ff 0000 (MASK[8,15])相与得到0x0021 0000;再把0x12345678(RA)与MASK0x00ff 0000 (MASK[8,15])的补码0xff00 ffff相与,得到0x1200 5678; 最后0x0021 0000跟0x1200 5678相与,得到0x12215678。
* 该指令可以⽤来清除C语⾔代码或者寄存器中的某个位域,然后对该位域进⾏赋值的操作。
结语:
PowerPC位操作指令 如斯强⼤和美妙,可以说是PowerPC汇编中的神器,因此⼏乎出处可见他们的⾝影。谨以此作为PowerPC指令集架构的总结,希望能够引起⼤家对PPC汇编的兴趣。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论