美文网首页程序员ARM硬件架构
ARM汇编之内存处理一网打尽

ARM汇编之内存处理一网打尽

作者: 赵国开 | 来源:发表于2018-07-24 20:07 被阅读9次

RISC架构可以认为是加载/存储的架构,因为所有存储在外部数据都需要通过指令加载到处理器进行处理。

加载/存储的指令很多,常用的如下:

加载 存储 长度和类型
LDR STR 32位的字(默认)
LDRB STRB 8位的无符号字节
LDRH STRH 16位无符号的半字
LDRSB 8位的有符号字节
LDRSH 16位的有符号半字
LDM STM 多个字的处理

  • 加载/存储的单指令处理的格式如下:
    LDR|STR{<size>}{<cond>} <Rd>, <addressing_mode>
    LDR表示从内存中加载数据并写到通用寄存器,STR表示从通用寄存器读取数据并把它存储到内存中。其中size是可选的如上表中的B/SB/H/SH等,addressing_mode表示寻址模式就是前面的文章《ARM汇编之内存寻址模式》介绍的,总共3种。
    下面这种格式不加!是偏移寻址模式,加!是前变址寻址模式
    LDR|STR{<size>}{<cond>} <Rd>, [<Rn>, <offset>]{!}
    下面这种格式是后变址寻址模式
    LDR|STR{<size>}{<cond>} <Rd>, [<Rn>], <offset>
    例子:
AREA load_store, CODE, READONLY

ARM

ENTRY

start

MOV R1,#0x40000000
MOV R2,#2

LDR R3,[R1,R2,LSL #2];偏移寻址模式
;LDR R3,[R1,R2,LSL#2]!;前变址寻址模式
;LDR R3,[R1],R2,LSL#2;后变址寻址模式

STR R2,[R1]
STR R2,[R1,#4]!
MOV R2,#0XFF
STR R2,[R1],#8

stop

MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SVC #0x123456 ; A32 semihosting (formerly SWI)

END
  • 加载/存储多个寄存器的指令

LDM的语法格式如下:
LDM{addr_mode}{cond} Rn{!}, reglist{^}
其中<addr_mode>告诉汇编指令寻址的模式有下面四种:
IA,在每次传输完之后递增地址(默认模式,可省略) 。
IB,在每次传输完之前递增地址 (仅A32支持)。
DA,在每次传输完之后递减地址 (仅A32支持)。
DB,在每次传输完之前递减地址。

cond是可选的,表示条件码。
Rn是基址寄存器。
感叹号!是可选的,如果有表示最后的地址要写回Rn寄存器。
reglist是用来加载数据的寄存器列表(包含一个或多个寄存器,多个的话可用逗号进行分隔,如果是多个连续的寄存器也可用一个范围表示,比如R0-R4),reglist需要用花括号括起来,对A32来说寄存器从R0到R15都可用,但T32只有部分寄存器可用。
reglist之后的^是可选的,仅A32支持,他不能用在用户模式或者系统模式( User mode/System mode),他是为如下场景设计的:

  • 当reglist中包含PC寄存器时,不仅将数据加载到寄存器列表中指定的寄存器,同时也顺便把SPSR复制到CPSR,这发生在异常模式下中断处理程序还回时。
  • 否则数据将被传输进/出用户模式的寄存器,而不是当前模式的寄存器

备注:因为有多个寄存器,那么怎么考虑寄存器列表里面的寄存器和内存之间的映射,拿存储来说,是最低序号的寄存器存储到最低内存地址中,最高序号的寄存器存储到最高的内存地址中,加载也是按这种方式进行映射的,这个是跟寄存器列表中寄存器的存放顺序没有关系的。

STM的语法格式如下:
STM{addr_mode}{cond} Rn{!}, reglist{^}

STM和LDM所带选项基本一样,释义也基本一样,对LDM来说Rn存储的是内存中的基地址,只是STM要从该地址往内存中写数据,而LDM是从该地址从内存中读数据。reglist之后的^对STM来说,同样也不能在用户模式或者系统模式,只是出现该符号时数据将被传输进/出用户模式的寄存器,而不是当前模式的寄存器。

例子1:

AREA load_store, CODE, READONLY
ARM

ENTRY

start

MOV R9,#0x40000000
ADD R10,R9,#32
LDMIA R9, {R5, R0, R3};低地址的数据先加载到r0,在加载到r3,最后加载到r5,
                      ;加载顺序跟放置在列表中的位置无关,只跟寄存器的编号有关
LDMDB R10!,{R0-R1};最终地址会被写回R10

stop

MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SVC #0x123456 ; A32 semihosting (formerly SWI)

END

例子2:

AREA load_store, CODE, READONLY

ARM

ENTRY

start

MOV R9,#0x40000000
ADD R10,R9,#32
MOV R2,#2
MOV R1,#1
STMIA R9,{R2,R1};注意最低地址存储R1,在接着存储R2,存储顺序跟放置在列表中的位置无关

STMIB R9,{R1,R2}
STMDA R10,{R2,R1}
STMDB R10!,{R1,R2}

stop

MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SVC #0x123456 ; A32 semihosting (formerly SWI)

END
  • PUSH和POP

主要是针对栈的操作,PUSH其实就是 STMDB sp!,POP其实就是 LDMIA sp!
语法格式如下:
PUSH{<cond>} <reglist>
POP{<cond>} <reglist>
其中reglist可以参照前面的LDM/STMD的说明

例子:

AREA push_pop, CODE, READONLY

ARM

ENTRY

start

mov sp,#0x40000010
push {r1,r0}
pop {r3,r4}

stop

MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SVC #0x123456 ; A32 semihosting (formerly SWI)

END
  • 使用 LDM和STM来实现栈

使用栈时需要注意两点:

  • 栈的增长方向,向上增长(ascending)或者向下增长(Descending)
  • 栈指针的位置,指向空的位置(empty,栈中下一个空的位置),或者满的位置(Full,最后一个栈成员的位置)

因此就可以组合出四种栈:
FD(Full Descending stack)
FA(Full Ascending stack)
ED(Empty Descending stack)
EA(Empty Ascending stack)
当然这四种操作和LDM/STM中的addr_mode是等价的可以互相替换的,编程时如果你觉得基于这种栈方式的操作更容易理解,可以用这种助记符来进行编写程序,汇编器会自动帮你把这些转换为基于addr_mode的合适指令。
下面是一张等价图

image.png

如果你是基于FD的栈来进行开发,如果没用FD助记符,那么入栈是你需要使用STMDB,而出栈是需要使用LDMIA,如果使用FD的话入栈STMFD,出栈LDMFD就行了剩下的交个汇编器去解释,这种就很容易记忆了。下面是四种栈入栈/出栈的指令及等效的addr_mode模式下的原始指令


image.png

例子:

AREA push_pop, CODE, READONLY

ARM

ENTRY

start

mov sp,#0x40000010
stmfd sp!,{r0,r1};入栈
ldmfd sp!,{r2,r3};出栈

stop

MOV r0, #0x18 ; angel_SWIreason_ReportException
LDR r1, =0x20026 ; ADP_Stopped_ApplicationExit
SVC #0x123456 ; A32 semihosting (formerly SWI)

END

参考文献

【1】DUI0801I_armasm_user_guide

相关文章

  • ARM汇编之内存处理一网打尽

    RISC架构可以认为是加载/存储的架构,因为所有存储在外部数据都需要通过指令加载到处理器进行处理。 加载/存储的指...

  • ARM寄存器

    汇编: 分析和修改汇编指令: 用户模式(usr): ARM处理器:

  • ARM64汇编入门 - 汇编基础

    ARM64汇编入门 - 汇编基础ARM64汇编入门 - 汇编基础

  • 2018-07-13

    Androguard 安装 使用 ARM汇编 汇编指令 伪指令 伪操作 .arch 框架.fpu 协处理器类型 $...

  • 汇编分析&编译器优化

    汇编的种类 8086汇编(8086处理器是16bit的CPU) Win32汇编 Win64汇编 ARM汇编(嵌入式...

  • 逆向 - arm64汇编 - 第一天

    1. 汇编语言种类 8086汇编(8086处理器是16bit的CPU)Win32汇编Win64汇编ARM汇编(嵌入...

  • ARM汇编语言入门

    一 ARM汇编介绍 1.1 处理器arm VS. intel ARM与Intel有诸多不同,最主要的区别是指令集。...

  • iOS逆向学习(arm64汇编入门)

    iOS汇编 iOS汇编语音有很多钟。常见的有8086汇编、arm汇编、x86汇编等等。 arm汇编 iOS的架构从...

  • ARM汇编指令

    关于arm64汇编指令,如下图 汇编指令可以汇总如下:(后续会更新) 关于内存读写指令 注意:读/写 数据是都是往...

  • 代码还原的技术 ARM汇编入门教程(一) Hello World

    一、目标 为什么要学ARM汇编? 不为什么。 学了ARM汇编有用吗? 没啥用 学完ARM汇编能找到工作吗? 目前流...

网友评论

    本文标题:ARM汇编之内存处理一网打尽

    本文链接:https://www.haomeiwen.com/subject/reiymftx.html