ARM开放——阶段问题综述(一)

一、ARM理论相关问题

1. ARM内核中包含的器件及其作用

主要功能单元:

器件 作用 位置(是否在内核中)
ALU(算术逻辑单元) 执行算术和逻辑运算 内核内部
寄存器组 32个通用寄存器,快速数据存取 内核内部
CPSR/SPSR 当前/保存的程序状态寄存器 内核内部
MMU(内存管理单元) 虚拟内存到物理内存的转换 内核内部(Cortex-A)
Cache(高速缓存) L1指令/数据缓存,提高访问速度 内核内部
TLB(转换旁路缓冲) 加速虚拟地址转换 内核内部
流水线 3-13级流水线,提高指令吞吐量 内核内部
NEON(SIMD单元) 单指令多数据,加速多媒体处理 可选,Cortex-A
VFP(浮点单元) 硬件浮点运算 可选,Cortex-A
ETM(嵌入式跟踪宏单元) 实时指令跟踪 可选
PMU(性能监控单元) 性能计数和监控 可选
GIC(通用中断控制器) 集中式中断管理 外部(通常集成在SoC)

2. ARM内核工作模式与异常向量表

ARM工作模式(7种):

模式 编码 用途 备注
User(用户模式) 0b10000 正常程序执行 非特权模式
FIQ(快速中断) 0b10001 快速中断处理 高优先级中断
IRQ(普通中断) 0b10010 普通中断处理 通用外设中断
Supervisor(管理模式) 0b10011 操作系统内核 复位/软中断入口
Abort(中止模式) 0b10111 内存访问异常 页错误/权限错误
Undefined(未定义模式) 0b11011 未定义指令 指令解码失败
System(系统模式) 0b11111 特权操作系统任务 使用用户模式寄存器

异常向量表:

复制代码
@ ARM异常向量表(基地址通常为0x00000000或0xFFFF0000)
Vector_Table:
    LDR PC, Reset_Addr       @ 0x00: 复位异常
    LDR PC, Undefined_Addr   @ 0x04: 未定义指令异常
    LDR PC, SWI_Addr         @ 0x08: 软件中断(SWI)
    LDR PC, Prefetch_Addr    @ 0x0C: 预取中止
    LDR PC, DataAbort_Addr   @ 0x10: 数据中止
    NOP                      @ 0x14: 保留
    LDR PC, IRQ_Addr         @ 0x18: IRQ中断
    LDR PC, FIQ_Addr         @ 0x1C: FIQ中断

作用:

  1. 异常入口:每个异常类型对应固定的地址

  2. 快速响应:硬件自动跳转到对应地址

  3. 模式切换:进入异常时自动切换处理器模式

  4. 上下文保存:自动保存CPSR到SPSR_<mode>

二、ARM汇编相关问题

1. 什么是立即数?如何判断12位立即数?

立即数:直接编码在指令中的常数数值

ARM中12位立即数的构成8位数据 + 4位循环右移值

  • 合法立即数 = 8位数据循环右移(2×n)位,n=0-15

  • 范围:0-255 × 2^(0-30),步长为2的偶次幂

判断方法

复制代码
// C语言判断函数
int is_legal_immediate(uint32_t val) {
    uint32_t temp;
    for(int i = 0; i < 32; i += 2) {
        temp = (val >> i) | (val << (32 - i));  // 循环右移i位
        if((temp & 0xFF) == temp) {  // 低8位是否等于自身
            return 1;  // 是合法立即数
        }
    }
    return 0;  // 不是合法立即数
}

// 示例:
// 0xFF(合法)      -> 0xFF循环右移0位
// 0x104(合法)     -> 0x41循环右移30位
// 0x101(不合法)   -> 无法用8位表示

2. b, bl, bx指令的区别

指令 功能 用途 链接寄存器
B(Branch) 无条件跳转 局部跳转,±32MB范围 不保存返回地址
BL(Branch with Link) 带链接的跳转 函数调用,保存返回地址到LR LR = 下一条指令地址
BX(Branch and eXchange) 带状态切换的跳转 切换ARM/Thumb状态 目标地址最低位=1则切换到Thumb
复制代码
@ 示例:
b   label           @ 简单跳转到label
bl  function        @ 调用function函数,LR保存返回地址
bx  r0              @ 跳转到r0指向的地址,可切换状态

3. ARM内核采用的栈类型

ARM支持四种栈类型:

栈类型 SP变化方向 满/空栈
FD(Full Descending) 递减 满栈(最常用)
ED(Empty Descending) 递减 空栈
FA(Full Ascending) 递增 满栈
EA(Empty Ascending) 递增 空栈

ARM标准使用FD栈(满递减栈):

  • 满栈:SP指向最后一个入栈的数据

  • 递减:SP向低地址增长

  • 对应汇编指令:STMFD / LDMFD

4. CPSR条件标志位置位条件

标志位 名称 置位条件 含义
N Negative 结果最高位为1 结果为负数
Z Zero 结果为0 结果为零
C Carry 无符号溢出/移位 加法进位/减法借位
V oVerflow 有符号溢出 有符号数溢出
Q Saturation 饱和运算溢出 DSP饱和标志

具体规则:

  • N位Rd[31] == 1

  • Z位Rd == 0

  • C位

    • 加法:CarryOut == 1

    • 减法:Borrow == 0(无借位)

    • 移位:移出的最后一位

  • V位 :有符号溢出,(A[31]==B[31]) && (Rd[31]!=A[31])

5. ARM汇编与C语言函数调用规范

ARM过程调用标准(AAPCS)

寄存器使用约定:

  • r0-r3:参数传递和返回值

  • r4-r11:被调用者保存

  • r12(IP):内部过程调用暂存

  • r13(SP):栈指针

  • r14(LR):链接寄存器

  • r15(PC):程序计数器

汇编调用C函数:
复制代码
@ 汇编代码调用C函数 int add(int a, int b)
mov r0, #5          @ 第一个参数
mov r1, #3          @ 第二个参数
bl  add             @ 调用C函数
@ 返回值在r0中
C调用汇编函数:
复制代码
// C代码声明
extern int asm_function(int a, int b);

// 调用
int result = asm_function(5, 3);

汇编函数实现:

复制代码
@ 汇编函数实现
.global asm_function
asm_function:
    @ 参数:r0 = a, r1 = b
    add r0, r0, r1   @ 计算 a + b
    bx  lr           @ 返回,返回值在r0
参数传递规则:
  1. ≤4个参数:使用r0-r3

  2. >4个参数:剩余参数压栈

  3. 返回值

    • 32位:r0

    • 64位:r0-r1

    • 浮点数:s0/d0

  4. 栈对齐:SP必须8字节对齐

三、嵌入式开发相关问题

1. LED点灯过程需要配置的寄存器

以i.MX6 GPIO控制LED为例:

复制代码
// 1. 使能GPIO时钟(CCM模块)
CCM_CCGR1 |= (3 << 26);  // 使能GPIO1时钟

// 2. 配置引脚复用(IOMUXC)
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = 0x5;  // 复用为GPIO功能

// 3. 配置引脚电气属性
IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 = 0x10B0;  // 驱动能力、上下拉等

// 4. 配置GPIO方向
GPIO1_GDIR |= (1 << 3);  // 设置GPIO1_IO03为输出

// 5. 控制LED亮灭
GPIO1_DR |= (1 << 3);    // 输出高电平,LED灭
GPIO1_DR &= ~(1 << 3);   // 输出低电平,LED亮

关键寄存器:

  • CCM_CCGRx:时钟门控寄存器

  • IOMUXC_SW_MUX_CTL:引脚复用控制

  • IOMUXC_SW_PAD_CTL:引脚电气属性

  • GPIO_GDIR:GPIO方向寄存器

  • GPIO_DR:GPIO数据寄存器

2. ELF文件格式及各段数据

ELF(Executable and Linkable Format)结构:

复制代码
ELF文件头
├── 程序头表(Program Header Table)
├── 节头表(Section Header Table)
├── .text段     ← 代码段(机器指令)
├── .data段     ← 已初始化全局/静态变量
├── .bss段      ← 未初始化全局/静态变量(不占文件空间)
├── .rodata段   ← 只读数据(字符串常量等)
├── .symtab段   ← 符号表
├── .strtab段   ← 字符串表
├── .rel.*段    ← 重定位表
└── 其他调试信息段

各段内容:

段名 内容 属性 文件偏移
.text 可执行代码 R+X 固定
.data 初始化的全局/静态变量 R+W 固定
.bss 未初始化的全局/静态变量 R+W 不占文件空间
.rodata 只读数据(常量字符串) R 固定
.heap 动态分配内存 R+W 运行时
.stack 局部变量、函数调用 R+W 运行时

3. 链接脚本的作用

1. 定义绝对运行地址

复制代码
. = 0x87800000;  /* 程序必须运行在这个地址 */

为什么重要:

  • i.MX6ULL裸机程序必须从DDR内存开始执行

  • 0x87800000 = 0x80000000(DDR起始) + 120MB偏移

  • 确保程序加载到正确位置

2. 控制启动代码顺序

复制代码
.text :
{
    obj/start.o    /* 强制放在最前面 */
    *(.text)       /* 其他代码放后面 */
}

为什么重要:

  • ARM要求异常向量表必须在内存最前端

  • start.o包含复位向量、异常处理

  • 确保芯片复位后能正确执行

3. 提供BSS段边界(用于内存初始化)

复制代码
__bss_start = .;    /* 标记开始 */
.bss : {*(.bss)}    /* BSS段定义 */
__bss_end = .;      /* 标记结束 */

为什么重要:

  • BSS段存储未初始化的全局变量

  • 启动时需要清零这些变量

  • 提供__bss_start__bss_end符号供汇编代码使用

链接脚本的作用:将分散编译的.o文件,按照硬件要求(特定地址、特定顺序)组织成能在i.MX6ULL芯片上直接运行的内存映像。

相关推荐
试试勇气2 小时前
Linux学习笔记(十二)--用户缓冲区
linux·笔记·学习
你的秋裤穿反了2 小时前
笔记13--------报警记录
笔记
大江东去浪淘尽千古风流人物2 小时前
【Project Aria】Meta新一代的AR眼镜及其数据集
人工智能·嵌入式硬件·算法·性能优化·ar·dsp开发
电饭叔2 小时前
has_solution = False 是什么 费马大定律代码化和定理《计算机科学中的数学》外扩学习3
学习·算法
wdfk_prog2 小时前
[Linux]学习笔记系列 -- [drivers][base]faux
linux·笔记·学习
后来后来啊2 小时前
2026.1.19学习笔记
笔记·学习·算法
鄭郑2 小时前
【Wordpress笔记02】文章分类与标签
笔记
一路往蓝-Anbo2 小时前
第46期:低功耗设计:软硬件协奏曲
驱动开发·stm32·单片机·嵌入式硬件
王卫东2 小时前
Vibe Coding:AI原生时代的编程范式革命与架构实践
架构·ai-native·vibe coding