Linux_kernel汇编指令05

一、温故知新

        1、跳转指令

b{cond} <target_label>

                相当于C语言中的goto

                <target_label>是跳转地址,±32M

                {cond}是条件码,先决条件

                根据CPSR寄存器的NZCV位来决定是跳转还是不跳转

bl

                l:带链接状态,将PC寄存器的值保存到LR寄存器中

                BL跳转的范围是±32M

bx

                ARM有两种工作状态,ARM与Thumb

                x可以进行状态的切换

        2、数据传输指令

mov 数据传输指令

                mov{cond}{S} <Rd>, <OP2>

                        {cond}条件码,是先决条件

                        {S}决定是否影响CPSR寄存器的NZCV位

                        <Rd>一定是通用寄存器

                        <OP2>有三种表现形式:立即数\寄存器\寄存器移位之后的值

mvn 数据取反传输指令

                mvn{cond}{S} <Rd>, <OP2>

                        {cond}条件码,是先决条件

                        {S}决定是否影响CPSR寄存器的NZCV位

                        <Rd>一定是通用寄存器

                        <OP2>有三种表现形式:立即数\寄存器\寄存器移位之后的值

        3、数据处理指令

                1)移位操作

        LSL逻辑左移,空位补0

        LSR逻辑右移,空位补0

        ASR算术右移,最高位补符号位

        ROR循环右移,被移出的位位将重新插入最高位

        RRX带扩展的循环右移,新的最高位由CPSR寄存器的C位补充,拿最低位更新C位

                2)算术运算指令

 add加法指令

                add{cond}{S} <Rd>, <Rn>, <OP2>

                        {cond}条件码,是先决条件

                        {S}决定是否影响CPSR寄存器的NZCV位

                        <Rd>目标寄存器

                        <Rn>操作寄存器

                        <OP2>有三种表现形式:立即数\寄存器\寄存器移位之后的值

adc带进位的加法指令

                adc{cond}{S} <Rd>, <Rn>, <OP2>

                        {cond}条件码,是先决条件

                        {S}决定是否影响CPSR寄存器的NZCV位

                        <Rd>目标寄存器

                        <Rn>操作寄存器

                        <OP2>有三种表现形式:立即数\寄存器\寄存器移位之后的值

                        adc r0, r1, r2        @r0 = r1 + r2 + CPSR.C位

sub减法指令

                sub{cond}{S} <Rd>, <Rn>, <OP2>

                        {cond}条件码,是先决条件

                        {S}决定是否影响CPSR寄存器的NZCV位

                        <Rd>目标寄存器

                        <Rn>操作寄存器

                        <OP2>有三种表现形式:立即数\寄存器\寄存器移位之后的值

sbc带借位的减法指令

                sbc{cond}{S} <Rd>, <Rn>, <OP2>

                        {cond}条件码,是先决条件

                        {S}决定是否影响CPSR寄存器的NZCV位

                        <Rd>目标寄存器

                        <Rn>操作寄存器

                        <OP2>有三种表现形式:立即数\寄存器\寄存器移位之后的值

                        sbc r0, r1, r2        @r0 = r1 - r2 - NOT(CPSR.C位)

rsb逆向减法指令

                rsb{cond}{S} <Rd>, <Rn>, <OP2>

                        {cond}条件码,是先决条件

                        {S}决定是否影响CPSR寄存器的NZCV位

                        <Rd>目标寄存器

                        <Rn>操作寄存器

                        <OP2>有三种表现形式:立即数\寄存器\寄存器移位之后的值

                        rsb r0, #0x08, r1        @语法错误

        4、位运算指令

                and        &

                orr          |

                eor         ^

                bic        清除

        5、比较测试指令 

                cmp        比较指令(内部其实做了一个相减的操作)

                tst           位测试指令

                teq          相等测试指令

注意:比较测试指令即使不加S,默认也会影响CPSR寄存器的NZCV位

二、ARM汇编-加载存储指令 

         图示过程

        1、单寄存器加载指令

                ldr指令用于从存储器(内存)中加载数据到寄存器中

                ldr{cond} Rd, addr        @用于将一个字(32bit)从内存中加载到寄存器中

                        {cond}条件码

                        Rd寄存器

                        addr地址

加载多少个字节可以根据ldr后面的符号来指定
ldrb用于将一个无符号单字节(8bit)从内存中加载到寄存器中
ldrh用于将一个无符号半字(16bit)从内存中加载到寄存器中
ldrsb用于将一个有符号单字节(8bit)从内存中加载到寄存器中
ldrsh用于将一个有符号半字(16bit)从内存中加载到寄存器中
ldrt用于将一个字(32bit)从内存中加载到寄存器中,并保证加载过程不中断
ldrbt用于将一个无符号单字节(8bit)从内存中加载到寄存器中,并保证加载过程不中断
ldrd用于将一个双字(64bit)从内存中加载到寄存器中

        2、单寄存器字/无符号字节加载地址模式

                地址模式 = 基地址 + 偏移地址

                        基地址 = 任意的通用寄存器

                        偏移地址 = 立即数\寄存器\寄存器移位 

        3、ldr示例

[ ]是把内容取出来
ldr r0, [r1]将存储器地址为r1的字数据读到寄存器r0
ldr r0, [r1, #0x8]将存储器地址为r1 + 0x8的字数据读到寄存器r0
ldr r0, [r1, #-0x20]将存储器地址为r1 - 0x20的字数据读到寄存器r0
ldr r0, [r1, r2]将存储器地址为r1 + r2的字数据读到寄存器r0
ldr r0, [r1, -r2]将存储器地址为r1 - r2的字数据读到寄存器r0
ldr r0, [r1, r2, lsl #3]将存储器地址为r1 + r2 * 8的字数据读到寄存器r0
ldr r0, [r1, #0x8]!将存储器地址为r1 + 0x8的字数据读取到r0,并且将r1 + 0x8的值存入到r1
ldr r0, [r1, r2]!将存储器地址为r1 + r2的字数据读到寄存器r0,并且将r1 + r2的值存入到r1
ldr r0, [r1, r2, lsl #2]将存储器地址为r1 + r2 * 4的字数据读到寄存器r0,并且将r1 + r2 * 4的值存入到r1
注意:加“!”表示要更新地址
ldr r0, [r1, #2]将存储器地址为r1 + 2的字数据读到寄存器r0
ldr r0, [r1], #2将存储器地址为r1的字数据读到寄存器r0,并将r1 + 2的值存入到r1
ldr r0, [r1], r2将存储器地址为r1的字数据读到寄存器r0,并将r1 + r2的值存入到r1
ldr r0, [r1], r2, lsl #3将存储器地址为r1的字数据读到寄存器r0,并将r1 + r2 * 8的值存入到r1
注意:先索引(前变址),后索引(后变址)

        4、ldr和mov的区别

                ldr指令用于从内存中加载数据到寄存器

                ldr指令的应用场景

                        【1】从内存中加载变量或者常量到寄存器中

                        【2】加载数组元素到寄存器中

                        【3】进行数据的读取和赋值操作

                mov指令用于在寄存器之间传递数据,或将立即数存储到寄存器中

                mov指令的应用场景

                        【1】在寄存器之间传递数据

                        【2】将立即数加载到寄存器中

                        【3】进行数据的赋值操作

        5、单寄存器存储指令

                str指令用于将寄存器中的数据写入到内存中

                str{cond} Rd, addr        @从寄存器中将一个32bit的字数据传送到存储器中

                        {cond}条件码

                        Rd寄存器

                        addr地址            

strb把寄存器中低8bit数据写入到存储器中
strh把寄存器中低16bit数据写入到存储器中
strt把寄存器中低8bit数据写入到存储器中,并且不会被中断打断

        6、单寄存器字/无符号字节存储地址模式 

                地址模式 = 基地址 + 偏移地址

                        基地址 = 任意的通用寄存器

                        偏移地址 = 立即数\寄存器\寄存器移位 

        7、str示例

str r0, [r1]将r0寄存器中的数据写入到地址值为r1的存储器中
str r0, [r1, #0x08]将r0寄存器中的数据写入到地址值为r1 + 0x08的存储器中
str r0, [r1, r2]将r0寄存器中的数据写入到地址值为r1 + r2的存储器中
str r0, [r1, r2, lsl #3]将r0寄存器中的数据写入到地址值为r1 + r2 * 8的存储器中
str r0, [r1, #0x08]!

将r0寄存器中的数据写入到地址值为r1 + 0x08的存储器中,

并将r1 + 0x08的值存入到r1

str r0, [r1, r2]!

将r0寄存器中的数据写入到地址值为r1 + r2的存储器中,

并将r1 + r2的值存入到r1

str r0, [r1, r2, lsl #3]!

将r0寄存器中的数据写入到地址值为r1 + r2 * 8的存储器中,

并将r1 + r2 * 8的值存入到r1

str r0, [r1], #0x08

将r0寄存器中的数据写入到地址值为r1的存储器中,

并将r1 + 0x08的值存入到r1

str r0, [r1], r2

将r0寄存器中的数据写入到地址值为r1的存储器中,

并将r1 + r2的值存入到r1

三、栈操作指令 

        栈是一种数据结构:FILO(first in last out)

        1、ATPCS

                ATPCS(ARM-Thumb Produces Call Standard),是ARM程序和Thumb程序中调用的基本规则,目的是为了使单独编译的C语言程序和汇编程序之间能够相互调用(内嵌汇编)

        2、ATPCS中各寄存器的名称

                【1】R0~R3        可以记作A1~A4,用于函数间传递参数

                【2】R4~R11      可以记作V1~V8,用于存储函数的局部变量

                        【a】R7        在Thumb工作状态下记作wr(work register)

                        【b】R9        可以记作sb(static base)

                                可以在与位置无关的代码中保存内存的静态地址,在Uboot中R9用来保存.global data的起始地址

                        【c】R10        可以记作sl(stack limit[栈限制])

                                用来检测stack是否overflow,可以把stack的最低端写入sl寄存器中,这样处理后,如果sp指向的地址低于sl寄存器里面的值时,就会触发栈溢出的错误。

                        【d】R11        可以记作fp(frame pointer[帧指针])

                                在函数的调用过程中,通常使用栈帧结构,也就是sp指针总是指向程序的顶端,同时设置fp来保存当前函数在栈上的基地址

-------------------------------------------------------------------------

补充:

        在多进程并发程序中,每一个进程都有自己的栈

        在同一进程中调用函数和被调用函数使用的是同一个栈,我们该如何进行区分?

        我们可以使用桟帧(stack frame)来区分,桟帧就是一个函数所使用的stack的一部分,所有函数的桟帧穿起来就是一个完整的栈,桟帧的两个边界分别是由fp和sp来限定

-------------------------------------------------------------------------

                【3】R12        可以记作ip(内部程序调用暂存器)

                                在子程序中R13(sp)不能作其他的用途,寄存器R13在进入子程序和退出子程序时的值必须相等

                【4】R13        可以记作sp(stack pointer[栈指针])

                【5】R14        可以记作lr(link register[链接寄存器])

                                用于保存调用函数的返回地址

                【6】R15        可以记作pc(program counter[程序计数器])

                                不能作为其他的用途来使用

        3、数据栈的使用规则

                对于ARM来说,支持4中栈,分别是:

                【1】FD        满递减栈

                【2】FA         满递增栈

                【3】ED        空递减栈

                【4】EA        空递增栈

---------------------------------------------------------

F:Full                满栈SP指向最后一个数据

E:Empty           空栈SP指向与最后一个数据相邻的下一个可写单元

D:Descend       递减,代表栈的增长方向

A:Ascend          递增,代表栈的增长方向 

满栈:栈顶本身有数据(SP寄存器指向位置本来有数据)

空栈:栈顶本身没有数据(SP寄存器指向位置本来没有数据)

注意:我们的S5P6818的内核ARM-Cortex-A53的栈所使用的结构就是fd满递增栈

---------------------------------------------------------

        4、指令

                ldr:从存储器加载数据到寄存器

                str:从寄存器存储数据到存储器

                ldm:(load much)多数据加载,将地址上的值加载到寄存器上(相当于出栈) 

                stm:(store much)多数据存储,将寄存器上的值存储到地址上(相当于入栈)

                1)执行格式

                        ldm{cond} mode Rn{!}, register{^}

                        stm{cond} mode Rn{!}, register{^}

                                Rn基址寄存器,存储传送数据的起始地址(Rn不能是R15)

                                !表示最后的地址写回到Rn中

                                register可以包含多个寄存器,用“,”隔开

                                如:{r1, r2, r3, r6-r9}        寄存器由小到大顺序排列

                                ^不允许在用户模式(user)和系统模式(system)下运行

                2)stm示例(入栈操作)

 注意:在ARM的指令系统中,

对于递减的栈,

入栈操作的顺序是从右到左依次入栈

对于递增的栈,

入栈操作的顺序是从左到右依次入栈

                3)ldm示例(出栈操作) 

注意:在ARM的指令系统中,

对于递减的栈,

出栈操作的顺序是从左到右依次出栈

对于递增的栈,

出栈操作的顺序是从右到左依次出栈

                4)反汇编代码

arm-cortex_a9-linux-gnueabi-gcc xxx.c -o xxx

arm-cortex_a9-linux-gnueabi-objdump -S xxx > xxx.s

注意:

xxx:文件名

objdump:反汇编器

         

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值