【嵌入式学习笔记】ARM指令集和寻址方式

发布时间:2026/10/4 19:20:59
【嵌入式学习笔记】ARM指令集和寻址方式 ARM指令集-特点存储方式优缺点ARM指令集原生的32位指令集以字对齐4字节效率高代码密度低Thumb指令集16位指令集是ARM指令集的子集2字节边界对齐具有较高的代码密度保持ARM大多数性能优势Thumb-2指令集具有16位和32位指令提供几乎和ARM指令集完全相同的功能2字节边界对齐16位和32位指令可自由混合继承了Thumb指令集的高代码密度又实现了ARM指令集的高性能ARM寻址方式ARM指令系统支持的寻址方式如下立即寻址寄存器寻址寄存器间接寻址基址加偏址寻址块拷贝寻址堆栈寻址相对寻址立即寻址也叫立即数寻址操作数本身就在指令中给出只要取出指令也就是取到了操作数这个操作数被称为立即数对应的方式也叫立即寻址。基本形式MOV R0, #0x10 ; R0 0x10ADD R1, R2, #5 ; R1 R2 5CMP R3, #100 ; 比较 R3 和 100#后面就是立即数CPU 译码时直接从指令编码里把它抠出来用。注意立即数以 “#” 为前缀第二个源操作数才能取立即数。有效立即数合法立即数规则不是所有数都能当立即数。一个数如果能由一个 8 位常数循环右移偶数位得到它就是合法立即数。ARM 指令是 32 位固定长度要留出操作码、寄存器编号等字段留给立即数的空间只有 12 位。但 12 位最大只能表示 0~4095远远不够用。ARM 的解决方案是用 8 位常数 4 位循环右移来编码立即数。ARM指令格式Shifter_operand第二操作数bit0~bit11最大12位有效立即数的判定方法把它写成 32 位二进制看能不能用一个 8 位模式循环右移偶数位得到。例10xFF二进制0000 0000 0000 0000 0000 0000 1111 1111集中在低 8 位 → 窗口就是 0xFF不移位 → ✅ 合法例20x104二进制0000 0000 0000 0000 0000 0001 0000 0100分散在 bit 2 和 bit 8跨度 7 位 → 能塞进 8 位窗口窗口内容0100 0001 0x410x41 循环右移 30 位 → 0x104 → ✅ 合法例30x101二进制0000 0000 0000 0000 0000 0001 0000 00011 在 bit 0 和 bit 8跨度 9 位 → 超过 8 位窗口 → ❌ 非法寄存器寻址利用寄存器中的数值作为操作数不需要访问内存是一种执行效率较高的寻址方式。基本形式MOV R0, R1 ; R0 R1ADD R2, R3, R4 ; R2 R3 R4SUB R5, R6, R7 ; R5 R6 - R7CMP R0, R1 ; 比较 R0 和 R1寄存器寻址速度快的原因因为寄存器在 CPU 核内部和 ALU 直接相连。CPU 读寄存器不需要走系统总线也不会有 Cache Miss 的问题。这也是为什么 ARM 的 Load/Store 架构要求所有算术运算的操作数必须来自寄存器内存数据必须先 LDR 到寄存器才能参与运算。寄存器移位寻址寄存器移位寻址是 ARM 的一个特色在读取寄存器的同时顺便做一次移位操作不额外消耗时钟周期MOV R0, R1, LSL #2 ; R0 R1 2ADD R2, R3, R4, ASR #1 ; R2 R3 (R4 1)操作数移位方式LSL逻辑左移低位补 0。LSR逻辑右移高位补 0。ASL算数左移由于左移空出的有效位用0填充因此它与LSL同义。ASR算术右移高位补符号位保持负数符号不变正数0负数1。ROR循环右移移出的位补到另一端。RRX带进位循环右移通过进位标志位一起循环。寄存器间接寻址将寄存器中存放的数作为操作数的有效地址而操作数本身存放在内存中。指令中用于间接寻址的寄存器必须用”[]“括起来。LDR R0, [R1] ; R0 内存[R1]STR R0, [R1] ; 内存[R1] R0[R1] 表示“R1 里存的是地址去那个地址取/写数据”。R1 本身不存数据只存地址所以叫“间接”。在 C 语言里的对应int *p a; // p 存的是 a 的地址int b *p; // 通过 p 间接访问 a编译成汇编就是LDR R1, a ; R1 aLDR R0, [R1] ; R0 *p寄存器间接寻址是 Load/Store 架构的基础地址存在寄存器里CPU 通过这个寄存器去访问内存。ARM 不能直接对内存做算术运算。所有内存数据必须先用LDR通过寄存器间接寻址读到寄存器算完再用STR写回。基址加偏址寻址它是在“寄存器间接寻址”的基础上加了一个偏移量用来访问数组、结构体这类连续内存。基本形式LDR R0, [R1, #4] ; R0 内存[R1 4]STR R0, [R1, #-8] ; 内存[R1 - 8] R0偏移量立即数LDR R0, [R1, #4]寄存器LDR R0, [R1, R2]R2 加到 R1 上寄存器加移位LDR R0, [R1, R2, LSL #2]R2 左移 2 位再加到 R1 上在 C 语言里的对应int arr[10];int x arr[2]; // 访问数组第 3 个元素编译成汇编就是LDR R1, arr ; R1 arr 的基地址LDR R0, [R1, #8] ; R0 内存[R1 8]因为 int 占 4 字节arr[2] 偏移是 8前索引模式先算地址访问内存然后更新基址寄存器。LDR R0, [R1, #4]! ; R0 内存[R14]然后 R1 R1 4末尾的!表示写回。后索引模式先用基址访问内存然后更新基址寄存器。LDR R0, [R1], #4 ; R0 内存[R1]然后 R1 R1 4块拷贝寻址块拷贝寻址Block Copy Addressing是 ARM 里用来一次读写多个寄存器的寻址方式也叫多寄存器寻址。一条指令就能把一串寄存器的值搬到内存或者反过来。LDMIA R0!, {R1-R4} ; 从 R0 指向的内存连续读取依次放入 R1-R4STMIA R0!, {R1-R4} ; 把 R1-R4 的值连续写入 R0 指向的内存LDM Load Multiple批量读STM Store Multiple批量写!表示写回基址寄存器即操作完后 R0 自动指向下一个位置。块拷贝寻址有 4 种地址变化模式后缀含义地址变化IAIncrement After先访问后递增IBIncrement Before先递增后访问DADecrement After先访问后递减DBDecrement Before先递减后访问STMIA R9, {R0,R1,R5} ; 把 R0,R1,R5 的值依次写入 R9先访问后递增 指向的内存STMIB R9, {R0,R1,R5} ; 把 R0,R1,R5 的值依次写入 R9先递增后访问 指向的内存STMDA R9, {R0,R1,R5} ; 把 R0,R1,R5 的值依次写入 R9先访问后递减 指向的内存STMDB R9, {R0,R1,R5} ; 把 R0,R1,R5 的值依次写入 R9先递减后访问 指向的内存堆栈寻址堆栈是一个按特定顺序进行存取的存储区操作顺序为“后进先出”。堆栈寻址是块拷贝寻址的特例专门用于函数调用时的现场保存和恢复。它把 SPR13作为基址寄存器按栈的规则自动增减地址。基本形式STMFD SP!, {R0-R3, LR} ; 压栈把 R0-R3 和 LR 保存到栈里LDMFD SP!, {R0-R3, PC} ; 出栈从栈里恢复 R0-R3LR 写回 PCSTMFD Store Multiple Full DescendingLDMFD Load Multiple Full Descending! 表示 SP 自动更新。ARM 的四种栈模式栈模式全称含义对应块拷贝后缀FDFull Descending满递减ARM 最常用DBFAFull Ascending满递增IBEDEmpty Descending空递减DAEAEmpty Ascending空递增IA满SP 指向栈顶最后一个有效数据。空SP 指向栈顶下一个空位。递减栈向低地址方向增长。递增栈向高地址方向增长。ARM 默认用 FD满递减即 SP 指向最后一个压入的数据压栈时地址减小。相对寻址相对寻址是 ARM 里专门用于跳转和位置无关代码的寻址方式以 PC程序计数器为基址加上一个偏移量算出目标地址。B label ; 跳转到 label目标地址 PC 偏移BL func ; 调用函数目标地址 PC 偏移LDR R0, [PC, #4] ; 从 PC4 处加载数据偏移量是相对于当前 PC 的差值不是绝对地址。AM64x/AM243xCortex-A53跳转指令 B、BL 都是相对寻址。Linux 用户态程序编译成 PIE位置无关可执行文件时大量使用相对寻址。Cortex-R5F函数调用、中断向量表入口都用相对跳转。在异常向量表里每个表项只有 4 字节放的就是一条相对跳转指令。Cortex-M4FB、BL 同样是相对寻址。M4F 的向量表里存的也是绝对地址但跳转指令本身用相对偏移。相对寻址 以 PC 为基址 偏移量算出目标地址。 它让代码不依赖绝对地址支持位置无关代码是跳转和常量加载的常用方式。总结寻址方式操作数来源是否访存典型指令应用场合立即寻址指令里直接编码的常数否MOV R0, #5赋初值、小常数运算寄存器寻址寄存器里的值否MOV R0, R1寄存器间搬数据、算术运算寄存器间接寻址寄存器指向的内存数据是LDR R0, [R1]通过指针访问内存、读外设寄存器基址加偏址寻址基址寄存器 偏移量指向的内存是LDR R0, [R1, #4]访问数组、结构体成员堆栈寻址SP 指向的栈内存是STMFD SP!, {R0-R3}函数现场保存、中断压栈块拷贝寻址基址寄存器指向的连续内存是LDMIA R0!, {R1-R4}批量数据搬运、内存拷贝相对寻址PC 偏移量指向的地址否B label跳转、位置无关代码