Lecture 03: Cortex M3存储系统访问 Refer to Chapter 5 in the reference book “ARM Cortex-M3权威指南”
内容 Cortex-M3存储器的分类 ARM的存储结构及存储方式 存储器操作数及变量 操作数的寻址方式 Cortex-M3存储器访问指令 栈操作
Cortex-M3存储器的分类 在系统中的地位 存储介质 信息存取方式 主存储器 辅助存储器 主存储器 辅助存储器 存储介质 磁存储器 半导体集成电路存储器 光存储器 激光光盘存储器 信息存取方式 随机存取存储器(RAM) 只读存储器(ROM)
ARM存储结构及存储方式 ARM支持以下6种数据类型: 8位有符号和无符号字节(Byte)。 16位有符号和无符号半字(Halfword) 它们必须以两字节的边界对齐(半字对齐)。 32位有符号和无符号字(word) 它们必须以4字节的边界对齐(字对齐)。 字对齐:字单元地址的低两位 A1A0=0b00。即地址末位为0x0, 0x4, 0x8, 0xc。 半字对齐:半字单元地址的最低位 A0=0b0 (地址末位为0x0,0x2,0x4,0x6,0x8,0xa,0xc,0xe)。
ARM存储结构及存储方式 一个字由四个字节组成,如果要说明一个字存储的地址,则是指这个字存储的最低的地址单元的地址,即一个字存储地址是A,则实际它占用的存储单元地址是A,A+1,A+2,A+3四个单元,一个半字(2个字节)占用的地址是A,A+1两个单元,若是一个字节,占用的地址是A的一个单元。 例如,地址0x10000000(8位十六进制数)中存放的是一个字节的数据,0x10000000、0x10000001、0x10000002、0x10000003四个存储单元中存放的是一个字数据。
ARM存储结构及存储方式
字对齐 ARM的每个地址是对应于一个存储字节而不是一个存储字,但ARM可以访问存储字,访问存储字时,其地址应该是字对齐的。 字对齐,就是字的地址可以被4整除。也就是说,若第1个字在存储空间中是在第0个地址对应的单元(32位),那么,第2个字则应在第4个地址对应的单元,第3个字应在第8个地址对应的单元,依此类推。一个字(32位二进制数)是由4个字节组成,假如某个字其地址是A(A能被4整除),那么,该字的4个字节对应的地址是A、A+1、A+2、A+3。
字对齐 分析:假设存储器从地址0(0x00000000)开始存放字数据,一个字数据占四个存储单元,即0(0x00000000)、1(0x00000001)、2(0x00000002)、3(0x00000003)四个单元,那么第二个字数据放在地址4(0x00000004)开始的单元里,第三个数据则放在地址8开始的单元里,依此类推。
字对齐 即使存储了其他类型(半字或者字节)的数据,没有用到四个字节,那么下一个数据也必须按字对齐的原则,存放在能被4整除的地址单元里。 例如:一个字(32位)数据存放在4(0x00000004)、5(0x00000005)、6(0x00000006)、7(0x00000007)四个存储单元中,下面一个存储单元即8(0x00000008)存放了一个字节(8位)的数据,如果接着要存放一个字(32位)数据,则这个字数据不能存储在9(0x00000009)开始的存储单元中,而是必须存放在c(0x0000000C)、d(0x0000000D)、e(0x0000000E)、f(0x0000000F)这四个地址单元中,这样才符合地址对齐的规定。
ARM存储结构 对于指令,ARM指令系统分为32位ARM指令集和16位的Thumb指令集,在存储时分别以32位和16位的两种不同长度存储。
ARM存储结构 ARM存储器以8位为一个单元存储数据(一个字节),每个存储单元分配一个存储地址。 ARM将存储器看作是从零地址开始的字节的线性组合。作为32位的微处理器,ARM体系结构所支持的最大寻址空间为4GB(232字节)。 从零字节到三字节放置第一个存储的字数据,从第四个字节到第七个字节放置第二个存储的字数据,依次排列。 32位的字数据要使用4个地址单元,16位半数据要使用2个地址单元。 就存在一个所存储的字或半字数据的排列顺序问题。ARM体系结构可以用两种方法存储字数据,称为大端格式和小端格式 。
ARM存储结构 数据存储格式 大端格式:字数据的高字节存储在低地址中,低字节存储在高地 址中。 小端格式:字数据的高字节存储在高地址中,低字节存储在低地址中。 例:0x12345678字数据的大、小端存储方式 低位地址 高位地址 大端格式 低位地址 高位地址 小端格式
存储器存储方式 存储器以字节为基本存储单元。 每个存储单元都有唯一的地址与之相对 应。 每个字节的二进制码占用一个存储单元 。 0xfe 0xdc 0xba 0x98 0x76 0x54 0x32 0x10 0x20001000 0x20001001 0x20001002 0x20001003 0x20001004 0x20001005 0x20001006 0x20001007 0x98ba 0x10325476 存储器以字节为基本存储单元。 每个存储单元都有唯一的地址与之相对 应。 每个字节的二进制码占用一个存储单元 。 每个双字节的二进制码占用两个连续的 存储单元。 低字节保存在低地址,高字节保存 在高地址。 每个四字节的二进制码占用四个连续的 存储单元。
存储器存储方式 存储器每个存储单元都有唯一地址 每个数据的地址都采用低地址来标识 0xfe地址为0x20001000 0xdc 0xba 0x98 0x76 0x54 0x32 0x10 0x20001000 0x20001001 0x20001002 0x20001003 0x20001004 0x20001005 0x20001006 0x20001007 0x98ba 0x10325476 存储器每个存储单元都有唯一地址 每个数据的地址都采用低地址来标识 0xfe地址为0x20001000 0xdc地址为0x20001001 0x98ba地址为0x20001002 0x10325476地址为0x20001004
内容 Cortex-M3存储器的分类 ARM的存储结构及存储方式 存储器操作数及变量 操作数的寻址方式 Cortex-M3存储器访问指令 栈操作
存储器操作数 存储器操作数都按一定规律在存储器中排列,为了便于描述,通常采用不同字符组合来标识。 存储在存储空间的数据通常称为存储变量或简称变量。 变量声明 {变量名} 类型 值1,值2, … 变量名 实质是所变量所在存储空间的地址。 主要用于对存储空间的标识,方便编程。 变量类型 字符型(char) DCB 半字型(short) DCW 字型(long) DCD
变量定义 以字节定义 x1 DCB 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 以半字定义 x2 DCW 0xdcfe, 0x98ba, 0x5476, 0x1032 以字定义 x3 DCD 0x98badcfe, 0x10325476 混合定义 x4 DCB 0xfe, 0xdc DCW 0x98ba DCD 0x10325476
变量定义对照 x DCB 1,2,3 y DCW 1,2,3 z DCD 1,2,3 x DCB 1 char x[]={1}; 在C语言中定义一个变量“char x=1;”,这样应用起来方便。但在汇编来看,所有值都放在存储器中,只有地址。汇编中使用的是&x。
long x[]={0x98badcfe, 0x10325476, x}; 变量定义 x DCD 0x98badcfe, 0x10325476 DCD x 0x20001000 0xfe 0x20001001 0xdc 0x20001002 0xba 0x20001003 0x98 0x20001004 0x76 0x20001005 0x54 0x20001006 0x32 x DCD 0x98badcfe, 0x10325476 DCD 0x20001000 0x20001007 0x10 0x20001008 0x00 0x10 0x20 0x20001009 0x2000100a 0x2000100b long x[]={0x98badcfe, 0x10325476, x};
变量定义 char x[4]; long y[]={4}; 批量字节空间分配 变量名 SPACE n ; for KEIL 常用于大数量的存储空间分配 x SPACE 4 y DCD 4 :分配四个字节(1个字)空间 :分配四个字节(1个字)空间,并将值4保 存在其中。 char x[4]; long y[]={4};
内容 Cortex-M3存储器的分类 ARM的存储结构及存储方式 存储器操作数及变量 操作数的寻址方式 Cortex-M3存储器访问指令 栈操作
操作数的寻址方式 立即数寻址 MOV Rd, #imm (Rd) = imm 立即数 imm 0-0xffff 奇偶字节均相等 MOVW Rd, #imm Rd的高16位清零 imm MOVT Rd, #imm (Rd) = imm<<16 Rd的低16位不受任何影响 其它立即数如何送至寄存器?
操作数的寻址方式 直接寻址 [addr] 首地址为addr的存储空间 读取数值按操作类型确定 [0x20001000] 字符型:0xfe 半字型:0xdcfe 字型:0x98badcfe [0x20001003] 字符型:0x98 半字型:0x7698 字型:0x32547698 0xfe 0x20001000 0xdc 0x20001001 0xba 0x20001002 0x98 0x20001003 0x76 0x20001004 0x54 0x20001005 0x32 0x20001006 0x10 0x20001007
操作数的寻址方式 相对寻址 相对寻址 [Rn, offset] Rn的值(Rn)为基址 地址=基址+偏移量 偏移量为立即数 [Rn, #imm] Addr=(Rn)+imm -0xfffimm 0xfff 偏移量为寄存器值 [Rn, Rm] Addr=(Rn)+(Rm) 偏移量为寄存器值的移位结果 [Rn, Rm, LSL #n] Addr=(Rn)+(Rm)<<n n=1、2、3 0xfe 0x20001000 0xdc 0x20001001 0xba 0x20001002 0x98 0x20001003 0x76 0x20001004 0x54 0x20001005 0x32 0x20001006 0x10 0x20001007
内容 Cortex-M3存储器的分类 ARM的存储结构及存储方式 存储器操作数及变量 操作数的寻址方式 Cortex-M3存储器访问指令 栈操作
Cortex-M3存储器访问指令 常用的存储器访问指令 实例 描述 LDRB Rd, [Rn, #offset] LDRH Rd, [Rn, #offset] 从存储器位置Rn+offset处读取半字 LDR Rd, [Rn, #offset] 从存储器位置Rn+offset处读取字 LDRD Rd1, Rd2, [Rn, #offset] 从存储器位置Rn+offset处读取双字 STRB Rd, [Rn, #offset] 往存储器位置Rn+offset处存储字节 STRH Rd, [Rn, #offset] 往存储器位置Rn+offset处存储半字 STR Rd, [Rn, #offset] 往存储器位置Rn+offset处存储字 STRD Rd1, Rd2, [Rn, #offset] 往存储器位置Rn+offset处存储双字
a=*(long*)(((char*)x)+m); Cortex-M3存储器访问指令 存储器只能与寄存器交换数据 读出 LDR Rd, [Rn, offset]; 读一个字 LDRH Rd, [Rn, offset]; 读一个半字 LDRB Rd, [Rn, offset]; 读一个字节 LDRD RdL, RdH, [Rn, offset]; 读一个双字 a=*(long*)(((char*)x)+m); a=*(short*)(((char*)x)+m); a=*(((char*)x)+m); a=*(long long*)(((char*)x)+m);
*(long*)(((char*)x)+m)=a; Cortex-M3存储器访问指令 存储器只能与寄存器交换数据 写入 STR Rd, [Rn, offset]; 写一个字 STRH Rd, [Rn, offset]; 写一个半字 STRB Rd, [Rn, offset]; 写一个字节 STRD RdL, RdH, [Rn, offset]; 写一个双字 *(long*)(((char*)x)+m)=a; *(short*)(((char*)x)+m)=a; *(((char*)x)+m)=a; *(long long*)(((char*)x)+m)=a;
Cortex-M3存储器访问指令 存储器的读写 x (Rn) i(Rm) j (Rd) long x[5]; j=x[i]; short x[5]; j=x[i]; char x[5]; j=x[i]; long x[5]; x[i]=j; short x[5]; x[i]=j; char x[5]; x[i]=j; LDR Rd, [Rn, Rm, LSL #2] LDRH Rd, [Rn, Rm, LSL #1] LDRB Rd, [Rn, Rm] STR Rd, [Rn, Rm, LSL #2] STRH Rd, [Rn, Rm, LSL #1] STRB Rd, [Rn, Rm]
Cortex-M3存储器访问指令 存储器寻址 LDR R2, [R0,#4] Addr=0x20001000+4=0x20001004 LDRH R2, [R0, R1] Addr=0x20001000+1=0x20001001 R2=0xbadc LDRB R2, [R0, R1, LSL #2] Addr=0x20001000+(1<<2)=0x20001004 R2=0x76 R0 0x1 R1 0xfe 0x20001000 0xdc 0x20001001 0xba 0x20001002 0x98 0x20001003 0x76 0x20001004 0x54 0x20001005 0x32 0x20001006 0x10 0x20001007
练习题 存储器中存有0x80、0x2030、0x456789三个数,将这三个数分别读取至R2、R3、R4中。 LDRB R2, [R0, #0] 0x67 0x89 LDRH R3, [R0, #2] 0x67 0x45 LDR R2, [R0, #6] 0x00 0x01 0x00
练习题 如何将超过16位的立即数赋给寄存器呢??? 这三个数可以组成一个32位数0x78563412,将该值保存在R1中,直接采用 将数值0x12、0x34、0x56、0x78按顺序保存在地址为0x20001010、0x20001011、0x20001012、0x20001013这四个存储单元中。 假定R0当前值为0x20001000 程序 MOV R1, #0x12 STRB R1, [R0, #0x10] MOV R1, #0x34 STRB R1, [R0, #0x11] MOV R1, #0x56 STRB R1, [R0, #0x12] MOV R1, #0x78 STRB R1, [R0, #0x13] 如何将超过16位的立即数赋给寄存器呢??? 这三个数可以组成一个32位数0x78563412,将该值保存在R1中,直接采用 STR R1, [R0, #0x10] 即可。
练习思考 如何将超过16位的任一立即数(如0x78563412 )赋给寄存器呢? 先将0x78563412作为数据定义出来,再采用LDR将其读入R1。 x DCD 0x78563412 LDR R1, x 假定x标识的存储单元地址为0x00001008 ,汇编指令实质是以PC 作为基址的相对寻址。 LDR R1, [PC, #offset] offset在编译连接过程中自动生成,无需人为计算,但仅当offset在规定的范围内才无错。 假定当前PC为0x00001000 LDR R1, [PC, #8]
Cortex-M3存储器访问指令 立即数offset在编译连接过程中自动生成,无需人为计算。 使用LDR伪指令进行立即数赋值 LDR R0, =imm imm满足MOV要求的 等同于 MOV R0, #imm imm满足MOVW要求的 等同于 MOVW R0, #imm imm不满足MOV或MOVW要求的 分为两部分,即以PC作为基址的相对寻址指令和立即数的存储(与指令同在相同的代码区)。 LDR R0, [PC, #offset] ⁞ DCW immL DCW immH 立即数offset在编译连接过程中自动生成,无需人为计算。
Cortex-M3存储器访问指令 “.W”表明指令为32位Thumb-2指令,否则位16位Thumb指令 前序存储器访问指令 实例 描述 LDR.W Rd, [Rn, #offset]! 多种数据大小的前序加载指令 (字、字节、半字、双字) LDRB.W Rd, [Rn, #offset]! LDRH.W Rd, [Rn, #offset]! LDRD.W Rd1, Rd2, [Rn, #offset]! LDRSB.W Rd, [Rn, #offset]! 带有符号展开、多种数据大小的前序加载指令(字节、半字) LDRSH.W Rd, [Rn, #offset]! STR.W Rd, [Rn, #offset]! 多种数据大小的前序存储指令 STRB.W Rd, [Rn, #offset]! STRH.W Rd, [Rn, #offset]! STRD.W Rd1, Rd2, [Rn, #offset]! “!”表明基址寄存器Rn会更新,这样指令包含两部分工作,访问存储器+地址修正。-255offset255 Sign extension LDR.W R0, [R1, #offset]! ;读取存储器[R1+offset],R1更新为R1+offset
Cortex-M3存储器访问指令 后序存储器访问指令 实例 描述 LDR.W Rd, [Rn], #offset 多种数据大小的后序加载指令 (字、字节、半字、双字) LDRB.W Rd, [Rn], #offset LDRH.W Rd, [Rn], #offset LDRD.W Rd1, Rd2, [Rn], #offset LDRSB.W Rd, [Rn], #offset 带有符号展开、多种数据大小的后序加载指令(字节、半字) LDRSH.W Rd, [Rn], #offset STR.W Rd, [Rn], #offset 多种数据大小的后序存储指令 STRB.W Rd, [Rn], #offset STRH.W Rd, [Rn], #offset STRD.W Rd1, Rd2, [Rn], #offset LDR.W R0, [R1], #offset ;读取存储器[R1],R1更新为R1+offset
Cortex-M3存储器访问指令 前序存储器访问 从地址0x20001000开始将后续的三个字分别读到的R1,R2和R3中。 0x20000ffc 从地址0x20001000开始将后续的三个字分别读到的R1,R2和R3中。 LDR R1, [R0, #4]! LDR R2, [R0, #4]! LDR R3, [R0, #4] 0x20001000 0xfe 0xdc R0 0x20000ffc 0xba 0x98 0x76 R0 0x20001000 R1 0x98badcfe 0x54 0x32 0x10 R0 0x20001004 R2 0x10325476 0x01 0x23 0x45 R0 0x20001004 R3 0x67452301 0x67
Cortex-M3存储器访问指令 后序存储器访问 从地址0x20001000开始将后续的三个字分别读到的R1,R2和R3中。 LDR R1, [R0], #4 LDR R2, [R0], #4 LDR R3, [R0] 0x20001000 0xfe 0xdc R0 0x20001000 0xba 0x98 0x76 R0 0x20001004 R1 0x98badcfe 0x54 0x32 0x10 R0 0x20001008 R2 0x10325476 0x01 0x23 R0 0x20001008 R3 0x67452301 0x45 0x67
练习题 将数值0x12、0x34、0x56、0x78按顺序保存在地址为0x20001010、0x20001013、0x20001016、0x20001019这四个存储单元中。 程序 LDR R0, =0x20001010 MOV R1, #0x12 STRB R1, [R0, #0x0] MOV R1, #0x34 STRB R1, [R0, #0x3] MOV R1, #0x56 STRB R1, [R0, #0x6] MOV R1, #0x78 STRB R1, [R0, #0x9]
练习题 将数值0x12、0x34、0x56、0x78按顺序保存在地址为0x20001010、0x20001013、0x20001016、0x20001019这四个存储单元中。 程序 LDR R0, =0x20001010 MOV R1, #0x12 STRB R1, [R0] MOV R1, #0x34 STRB R1, [R0, #0x3]! MOV R1, #0x56 MOV R1, #0x78 STRB R1, [R0, #0x3]
Cortex-M3存储器访问指令 IA:传输完成后(A)地址递增(I) 多次存储器访问指令 “DB:传输前(B)地址递减(D) 实例 描述 LDMIA Rd(!), <reg list> 从Rd指令的存储器位置读取多个字,每次传送后地址增加 STMIA Rd(!), <reg list> 从Rd指令的存储器位置存储多个字,每次传送后地址增加 LDMIA.W Rd(!), <reg list> LDMDB.W Rd(!), <reg list> 从Rd指令的存储器位置读取多个字,每次传送前地址减少 STMIA.W Rd(!), <reg list> STMDB.W Rd(!), <reg list> 从Rd指令的存储器位置存储多个字,每次传送前地址减少 “DB:传输前(B)地址递减(D) (R8)=0x8000; STMIA.W R8!, {R0-R3}; 存储器后R8变为0x8010(增加4个字) STMIA.W R8, {R0-R3}; 存储器后R8不变
Cortex-M3存储器访问指令 多次存储器访问 从地址0x20001000开始将后续的三个字分别读到的R1,R2和R3中。 LDMIA R0, {R1-R3} LDMIA R0!, {R1-R3} R0 0x20001000 0x20001000 0xfe 0xdc R0 0x20001000 R1 0x98badcfe 0xba R2 0x10325476 0x98 R3 0x67452301 R0 0x20001000 0x76 0x54 R0 0x20001000 0x32 R1 0x98badcfe 0x10 R2 0x10325476 0x01 R3 0x67452301 R0 0x2000100c 0x23 0x45 0x67
Cortex-M3存储器访问指令 后序存储器访问 从地址0x20001000开始将后续的三个字分别读到的R1,R2和R3中。 0x2000100c R0 从地址0x20001000开始将后续的三个字分别读到的R1,R2和R3中。 LDMDB R0, {R1-R3} LDMDB R0!, {R1-R3} 0x20001000 0xfe 0xdc R0 0x2000100c R1 0x98badcfe 0xba R2 0x10325476 0x98 R0 0x2000100c R3 0x67452301 0x76 0x54 R0 0x2000100c 0x32 0x10 R1 0x98badcfe 0x01 R2 0x10325476 0x23 R3 0x67452301 R0 0x20001000 0x45 0x67
内容 Cortex-M3存储器的分类 ARM的存储结构及存储方式 存储器操作数及变量 操作数的寻址方式 Cortex-M3存储器访问指令 栈操作
栈操作 栈 一定大小的存储空间,按先进后出读写数据 数据读写改变栈指针SP(R13) 栈指针初始在栈底(高地址) 入栈 地址值只能为4的倍数(二进制后两位都为0) 栈 一定大小的存储空间,按先进后出读写数据 数据读写改变栈指针SP(R13) 栈指针初始在栈底(高地址) 入栈 栈指针减4后在相应的地址上写入一个字 PUSH {寄存器列表} STMDB SP!, {寄存器列表} 出栈 取出栈指针所对应的一个字后栈指针加4 POP {寄存器列表} LDMIA SP!, {寄存器列表}
假定(R0)=0x12,(R1)=0x3456,(R2)=0x789abcde PUSH {R0} PUSH {R1} PUSH {R2} 入栈 SP 0x2000100c 假定(R0)=0x12,(R1)=0x3456,(R2)=0x789abcde PUSH {R0} PUSH {R1} PUSH {R2} 0x20001000 0xde 0xbc SP 0x2000100c 0x9a 0x78 0x56 SP 0x20001008 0x34 0x00 0x00 SP 0x20001004 0x12 0x00 SP 0x20001000 0x00 0x00 0x00 SP
栈操作 入栈 SP 0x2000100c 假定(R0)=0x12,(R1)=0x3456,(R2)=0x789abcde PUSH {R0-R2} STMDB SP!, {R0-R2} 0x20001000 0x12 0x00 0x00 SP 0x2000100c 0x00 0x56 0x34 SP 0x20001000 0x00 0x00 SP 0x2000100c 0xde 0xbc 0x9a SP 0x20001000 0x78 0x00 SP
栈操作 出栈 SP 0x20001000 从栈中读出三个数,使(R4)=0x12,(R5)=0x3456,(R6)=0x789abcde POP {R6} POP {R5} POP {R4} SP 0x20001000 0xde 0xbc SP 0x20001000 0x9a (R6)= 0x789abcde 0x78 0x56 SP 0x20001004 0x34 (R5)= 0x3456 0x00 0x00 SP 0x20001008 0x12 (R4)= 0x12 0x00 SP 0x2000100C 0x00 0x00 0x00
栈操作 出栈 SP 0x20001000 从栈中读出三个数,使(R4)=0x12,(R5)=0x3456,(R6)=0x789abcde POP {R4-R6} LDMIA SP!, {R4-R6} SP 0x20001000 0x12 0x00 0x00 SP 0x20001000 0x00 0x56 SP 0x2000100c 0x34 0x00 0x00 SP 0x20001000 0xde 0xbc 0x9a 0x78 SP 0x2000100c 0x00
栈操作 堆栈内开辟存储空间 在堆栈中开辟三个字空间,从低地址向高地址存放0x1234、0x5678、0xabcd。 PUSH {R0} LDR R0, =0xabcd LDR R0, =0x5678 LDR R0, =0x1234 PUSH {R0] LDR R0, [SP, #12] R0 0x98765432 R0 0x98765432 R0 0x0000abcd 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x00000000 0x0000abcd 0x00000000 0x98765432 0x98765432 R0 0x00005678 R0 0x00001234 R0 0x98765432 0x00000000 0x00001234 0x00001234 0x00005678 0x00005678 0x00005678 0x0000abcd 0x0000abcd 0x0000abcd 0x98765432 0x98765432 0x98765432
栈操作 使用堆栈中所开辟的存储空间 分别对前面所开的堆栈存储空间中所存储的值进行处理,每次操作的数都在R0中。 STR R0, [SP, #12] LDR R0, [SP, #0] LDR R0, [SP, #4] LDR R0, [SP, #8] LDR R0, [SP, #12] R0 0x23456789 R0 0x23456789 0x00001234 0x00001234 0x00005678 0x00005678 0x0000abcd 0x0000abcd 0x98765432 0x23456789 R0 0x00001234 R0 0x00005678 R0 0x0000abcd R0 0x23456789
栈操作 释放堆栈中所开辟的存储空间 将前所开辟的空间释放,堆栈指针回到原位置。 STR R0, [SP, #12] POP {R0} R0 0x12345678 R0 0x12345678 R0 0x00001234 0x00001234 0x00001234 0x00001234 0x00005678 0x00005678 0x00005678 0x0000abcd 0x0000abcd 0x0000abcd 0x23456789 0x12345678 0x12345678 R0 0x00005678 R0 0x0000abcd R0 0x12345678 0x00001234 0x00001234 0x00001234 0x00005678 0x00005678 0x00005678 0x0000abcd 0x0000abcd 0x0000abcd 0x12345678 0x12345678 0x12345678