-
-
[原创]ARM架构笔记
-
发表于: 6天前 353
-
ARMv7 aarch32 ARM32
- armv7: ARM 第 7 代 32 位处理器架构规范(2004年发布), 仅支持 32 位指令集(A32/T32)
- aarch32: 不专属于 ARMv7, 而是 ARMv8 架构定义的 32 位执行状态, 兼容 ARMv7 指令集并扩展新功能(如加密指令、LPAE)。
- ARM32: 非官方术语, 通常泛指所有32位 ARM 架构(包括 ARMv7 及更早版本), 在 Android 系统中特指 armeabi-v7a。
ARMv8 aarch64 ARM64
- ARMv8: ARM 第 8 代架构(2011年发布), 首次引入 64 位支持, 同时兼容 32 位(AArch32)
- aarch64: ARMv8 架构中 64 位执行状态的官方名称, 支持 A64 指令集和 64 位寄存器(X0-X30)。
- ARM64: AArch64 的行业别名, 在Linux/Android 系统中广泛使用(如arm64-v8a)。
ARM64 寄存器
- X 寄存器: 64位通用寄存器, 用于处理64位数据或地址(例如 X0~X30)
- W 寄存器: 32位寄存器, 对应 X 寄存器的低32位(例如 W0 是 X0 的低32位), 写入 W 寄存器时, 会将对应 X 寄存器的高32位清零(例如写入 W0=0xFFFFFFFF 后 X0=0x00000000FFFFFFFF)
- X0-X7: 用于参数传递,
注意 X0, X1 可用于储存函数结果, 大小 ≤ 8字节: 整个返回值由 x0 容纳, 大小 ≤ 16字节: 低8字节存 x0, 高8字节存 x1
- X9-X15: 在子函数中使用这些寄存器时, 直接使用即可, 无需save/restore. 在汇编代码中x9-x15出现的频率极低
- X19-X29: 在callee子函数中使用这些寄存器时, 需要先save这些寄存器, 在退出子函数时再resotre
- X8, X16-X18, X29, X30 这些都是特殊用途的寄存器
- X8: 作为间接结果位置寄存器, 当函数返回大于 16 字节的结构体时,调用方预先分配内存并将地址存入 X8
- X16、X17: 进程内临时寄存器
- X18: 保留用于ABI
- X29: FP(frame pointer register, 帧指针寄存器)FP 指向当前函数栈帧的起始位置(栈底), 用于界定函数的栈空间范围。在函数调用链中, FP 形成“链表式”结构, 每个栈帧保存上一级函数的 FP 值, 实现栈回溯(backtrace)
- X30: LR(Link Register, 链接寄存器)保存返回地址, 当执行 BL(Branch with Link)或 BLX 指令调用子函数时, LR 自动存储下一条指令的地址, 确保函数返回后继续执行正确位置
- X0-X7: 用于参数传递,
- V 寄存器: 128 位浮点/向量寄存器, 共有 32 个(V0~V31), V0–V31 构成了完整的浮点与 SIMD(单指令多数据)运算寄存器组, 这些寄存器支持浮点运算、SIMD 并行计算(如图形处理)、加密指令等场景。
注意 ARM64 中前八个浮点型参数通过寄存器V0至V7传递, 如果函数有更多的参数, 那么超出的参数将通过堆栈传递。
可通过不同后缀访问部分位宽:- Bn: 8 位(最低字节)
- Hn: 16 位(低半字)
- Sn: 32 位(低单字)
- Dn: 64 位(低双字)
- Qn: 128 位(完整寄存器)
- SP(Stack pointer): 指向当前栈顶地址, 必须保持 16 字节对齐(否则可能触发异常), 满递减栈
- PC(Program Counter): 存储下一条指令地址。不能直接修改(通过 B、BL 等跳转指令隐式更新)
- PSTATE: ARMv8/AArch64 架构中处理器状态的逻辑集合, 并非物理上的单一寄存器, 而是通过多个专用寄存器(Special-Purpose Registers)分散存储状态信息
- NZCV: 条件标志位(Negative, Zero, Carry, Overflow)
- N: 结果为负时置 1
- Z: 结果为零时置 1
- C: 运算产生进位/借位时置 1
- V: 有符号溢出时置 1
- DAIF: 中断屏蔽位(Debug, SError, IRQ, FIQ)
- CurrentEL: 当前异常级别(Exception Level, EL0-EL3)
- SPSel: 栈指针选择位(0=使用 SP_EL0, 1=使用 SP_ELx)
- PAN: 特权访问禁止位(Privileged Access Never), 启用后内核访问用户内存会触发异常
- UAO: 用户访问覆盖位(User Access Override), 控制非特权指令的行为
- NZCV: 条件标志位(Negative, Zero, Carry, Overflow)
- CPSR: ARMv7/AArch32 架构中的单一物理寄存器, 集中存储所有处理器状态信息
- 条件标志位: NZCV(位置: bits 31-28)
- 控制位
- T: 指令集状态(0=ARM, 1=Thumb)
- I/F: 中断屏蔽(IRQ/FIQ)
- ......
- XZR/WZR: 零寄存器, 硬编码为 0, 用于简化指令, 读操作恒返回 0, 写操作无效
FP、LR 再思考
进入一个函数时, 会先将 LR FP 入栈, 然后更新 FP 为当前函数的 SP 也就是上一函数 FP 的地址, 之后再开辟所需栈空间, 假设又调用一个函数, 也是同样的流程, 等到函数开始返回时, 根据当前 FP 中存入的地址找到上一函数 FP 的值, 从栈中恢复前一函数的 FP, 获取 LR 也就是函数返回地址, 跳转 LR, 函数返回。
调用约定
- ARM: 参数1R3 寄存器中, 剩下的参数从右往左一次入栈, 调用者(Caller)实现栈平衡, 返回值存放在 R0 中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | ; 该代码是 arm - linux - androideabi - gcc + IDA PRO 生成的反汇编代码 .text: 00008438 MOV R3, #5 .text: 0000843C STR R3, [SP, #0x1C+e] ; e .text: 00008440 MOV R3, #6 .text: 00008444 STR R3, [SP, #0x1C+f] ; f .text: 00008448 MOV R3, #7 .text: 0000844C STR R3, [SP, #0x1C+g] ; g .text: 00008450 MOV R0, #1 ; a .text: 00008454 MOV R1, #2 ; b .text: 00008458 MOV R2, #3 ; c .text: 0000845C MOV R3, #4 ; d .text: 00008460 BL add .text: 00008464 STR R0, [R11, #sum] ; 调用后平衡 e / f / g 占用的 12 字节栈空间 .text: 000083C4 EXPORT add .text: 000083C4 STR R11, [SP, #-4+var_s0]! ; 保存 R11 原值 .text: 000083C8 ADD R11, SP, #0 ; 保存 SP 到 R11 .text: 000083CC SUB SP, SP, #0x1C ; 开辟所需栈空间 .text: 000083D0 STR R0, [R11, #a] .text: 000083D4 STR R1, [R11, #b] .text: 000083D8 STR R2, [R11, #c] .text: 000083DC STR R3, [R11, #d] .text: 000083E0 LDR R2, [R11, #a] .text: 000083E4 LDR R3, [R11, #b] .text: 000083E8 ADD R2, R2, R3 .text: 000083EC LDR R3, [R11, #c] .text: 000083F0 ADD R2, R2, R3 .text: 000083F4 LDR R3, [R11, #d] .text: 000083F8 ADD R2, R2, R3 .text: 000083FC LDR R3, [R11, #e] .text: 00008400 ADD R2, R2, R3 .text: 00008404 LDR R3, [R11, #f] .text: 00008408 ADD R2, R2, R3 .text: 0000840C LDR R3, [R11, #g] .text: 00008410 ADD R3, R2, R3 .text: 00008414 STR R3, [R11, #sum] .text: 00008418 LDR R3, [R11, #sum] .text: 0000841C MOV R0, R3 ; R0 返回值 .text: 00008420 SUB SP, R11, #0 ; 将 SP 恢复到刚进入函数时的值 .text: 00008424 LDR R11, [SP + var_s0], #4 ; 恢复 R11 原值 .text: 00008428 BX LR ; 返回 |
- ARM64: 参数1X7 寄存器中, 剩下的参数从右往左一次入栈, 被调用函数(Callee)实现栈平衡, 返回值存放在 X0 中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | ; 该代码是 aarch64 - linux - android - gcc + IDA PRO 生成的反汇编代码 .text: 0000000000400684 MOV W0, #9 .text: 0000000000400688 STR W0, [SP, #0x40+i] ; i .text: 000000000040068C MOV W0, #10 .text: 0000000000400690 STR W0, [SP, #0x40+j] ; j .text: 0000000000400694 MOV W0, #11 .text: 0000000000400698 STR W0, [SP, #0x40+k] ; k .text: 000000000040069C MOV W0, #12 .text: 00000000004006A0 STR W0, [SP, #0x40+l] ; l .text: 00000000004006A4 MOV W0, #1 ; a .text: 00000000004006A8 MOV W1, #2 ; b .text: 00000000004006AC MOV W2, #3 ; c .text: 00000000004006B0 MOV W3, #4 ; d .text: 00000000004006B4 MOV W4, #5 ; e .text: 00000000004006B8 MOV W5, #6 ; f .text: 00000000004006BC MOV W6, #7 ; g .text: 00000000004006C0 MOV W7, #8 ; h .text: 00000000004006C4 BL add .text: 00000000004006C8 STR W0, [X29, #0x20+sum] .text: 00000000004005E8 EXPORT add .text: 00000000004005E8 .text: 00000000004005E8 SUB SP, SP, #0x30 ; 开辟函数所需栈空间 .text: 00000000004005EC STR W0, [SP, #0x30+a] .text: 00000000004005F0 STR W1, [SP, #0x30+b] .text: 00000000004005F4 STR W2, [SP, #0x30+c] .text: 00000000004005F8 STR W3, [SP, #0x30+d] .text: 00000000004005FC STR W4, [SP, #0x30+e] .text: 0000000000400600 STR W5, [SP, #0x30+f] .text: 0000000000400604 STR W6, [SP, #0x30+g] .text: 0000000000400608 STR W7, [SP, #0x30+h] .text: 000000000040060C LDR W1, [SP, #0x30+a] .text: 0000000000400610 LDR W0, [SP, #0x30+b] .text: 0000000000400614 ADD W1, W1, W0 .text: 0000000000400618 LDR W0, [SP, #0x30+c] .text: 000000000040061C ADD W1, W1, W0 .text: 0000000000400620 LDR W0, [SP, #0x30+d] .text: 0000000000400624 ADD W1, W1, W0 .text: 0000000000400628 LDR W0, [SP, #0x30+e] .text: 000000000040062C ADD W1, W1, W0 .text: 0000000000400630 LDR W0, [SP, #0x30+f] .text: 0000000000400634 ADD W1, W1, W0 .text: 0000000000400638 LDR W0, [SP, #0x30+g] .text: 000000000040063C ADD W1, W1, W0 .text: 0000000000400640 LDR W0, [SP, #0x30+h] .text: 0000000000400644 ADD W1, W1, W0 .text: 0000000000400648 LDR W0, [SP, #0x30+i] .text: 000000000040064C ADD W1, W1, W0 .text: 0000000000400650 LDR W0, [SP, #0x30+j] .text: 0000000000400654 ADD W1, W1, W0 .text: 0000000000400658 LDR W0, [SP, #0x30+k] .text: 000000000040065C ADD W1, W1, W0 .text: 0000000000400660 LDR W0, [SP, #0x30+l] .text: 0000000000400664 ADD W0, W1, W0 .text: 0000000000400668 STR W0, [SP, #0x30+sum] .text: 000000000040066C LDR W0, [SP, #0x30+sum] ; X0 返回值 .text: 0000000000400670 ADD SP, SP, #0x30 ; 平衡栈 .text: 0000000000400674 RET |
参考链接
639K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8X3p5#2y4U0f1@1z5e0V1$3z5e0W2Q4x3V1k6S2M7Y4c8A6j5$3I4W2i4K6u0r3k6r3g2@1j5h3W2D9M7#2)9J5c8U0M7&6x3U0V1@1x3U0j5I4
a56K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6T1L8r3!0Y4i4K6u0W2j5%4y4V1L8W2)9J5k6h3&6W2N6q4)9J5c8Y4N6W2K9i4S2A6L8W2)9#2k6U0b7J5x3e0x3#2x3o6R3%4i4K6u0r3j5i4u0@1K9h3y4D9k6g2)9J5c8X3c8W2N6r3q4A6L8s2y4Q4x3V1j5I4x3e0p5J5y4U0x3%4x3U0l9`.
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 3天前
被nothing233编辑
,原因:
赞赏
他的文章
赞赏
雪币:
留言: