PC SP LR

深入理解ARM的这三个寄存器,对编程以及操作系统的移植都有很大的裨益。

PC 代表程序计数器,流水线使用三个阶段,因此指令分为三个阶段执行:1.取指(从存储器装载一条指令);2.译码(识别将要被执行的指令);3.执行(处理 指令并将结果写回寄存器)。而R15(PC)总是指向“正在取指”的指令,而不是指向“正在执行”的指令或正在“译码”的指令。一般来说,人们习惯性约定 将“正在执行的指令作为参考点”,称之为当前第一条指令,因此PC总是指向第三条指令。当ARM状态时,每条指令为4字节长,所以PC始终指向该指令地址 加8字节的地址,即:PC值=当前程序执行位置+8;

ARM指令是三级流水线,取指,译指,执行时同时执行的,现在PC指向的是正在取指的地址,那么cpu正在译指的指令地址是PC-4(假设在ARM状态 下,一个指令占4个字节),cpu正在执行的指令地址是PC-8,也就是说PC所指向的地址和现在所执行的指令地址相差8。
当突然发生中断的时候,保存的是PC的地址
这样你就知道了,如果返回的时候返回PC,那么中间就有一个指令没有执行,所以用SUB pc lr-irq #4。

1、堆栈指针r13(SP):每一种异常模式都有其自己独立的r13,它通常指向异常模式所专用的堆栈,也就是说五种异常模式、非异常模式(用户模式和系统模式),都有各自独立的堆栈,用不同的堆栈指针来索引。这样当ARM进入异常模式的时候,程序就可以把一般通用寄存器压入堆栈,返回时再出栈,保证了各种模式下程序的状态的完整性。

2、连接寄存器r14(LR):每种模式下r14都有自身版组,它有两个特殊功能。

(1)保存子程序返回地址。使用BL或BLX时,跳转指令自动把返回地址放入r14中;子程序通过把r14复制到PC来实现返回,通常用下列指令之一:
                    MOV PC, LR 
                    BX LR

通常子程序这样写,保证了子程序中还可以调用子程序。
                     stmfd sp!, {lr}
                     ……
                     ldmfd sp!, {pc}

(2)当异常发生时,异常模式的r14用来保存异常返回地址,将r14如栈可以处理嵌套中断。

3、程序计数器r15(PC):PC是有读写限制的。当没有超过读取限制的时候,读取的值是指令的地址加上8个字节,由于ARM指令总是以字对齐的,故bit[1:0]总是00。当用str或stm存储PC的时候,偏移量有可能是8或12等其它值。在V3及以下版本中,写入bit[1:0]的值将被忽略,而在V4及以上版本写入r15的bit[1:0]必须为00,否则后果不可预测。

ARM处理器使用流水线来增加处理器指令流的速度,这样可使几个操作同时进行,并使处理与存储器系统之间的操作更加流畅,连续,能提供0.9MIPS/MHZ的指令执行速度。# 欢迎使用Markdown编辑器写博客

本Markdown编辑器使用[StackEdit][6]修改而来,用它写博客,将会带来全新的体验哦:

-

<think>好的,用户遇到了AddressSanitizer报告的栈溢出问题,需要帮助解决。首先,我得理解错误信息。栈溢出通常是因为递归过深或者局部变量过大。用户提供的错误信息里有pc、bp、sp的地址,这可能指向发生溢出的具体位置。 先考虑常见原因。比如,是否有无限递归或者没有正确终止条件的递归函数?或者某个函数里定义了太大的数组,比如int buffer[1000000]; 这样的局部变量会占用大量栈空间,导致溢出。栈空间通常比较小,默认可能在几MB左右,所以大数组应该用堆分配,比如用malloc或者动态容器。 接下来,用户可能需要检查代码中的递归函数,确保有正确的终止条件,并且递归深度不会太大。如果递归太深,可以考虑改为迭代算法。另外,查看是否有大局部变量,改为动态分配。 然后,查看错误信息中的pc值0x559f21a3d805,这可能需要用addr2line工具来定位代码中的位置。比如用命令addr2line -e 可执行文件 0x559f21a3d805,这样可以找到对应的源代码文件行号,帮助用户定位问题。 另外,用户可能没有意识到栈空间的大小限制,可以建议通过ulimit -s查看当前栈大小,或者编译时使用参数增加栈空间,比如-Wl,-z,stack-size=4194304来设置为4MB。但这只是临时解决办法,更好的方法是优化代码结构,避免过深的栈使用。 还要考虑是否使用了某些第三方库的函数,可能存在栈溢出的风险,比如某些递归实现的函数。需要检查文档或更新库版本,看看是否有相关修复,比如引用[3]提到修复了处理字节流的不稳定性,虽然不是直接相关,但提示检查依赖库的可能问题。 还有用户提到的NEON优化问题,引用[4]指出某些优化可能反而更慢,但这里主要问题在栈溢出,可能需要先解决代码结构问题,再考虑优化。 总结解决步骤应该是:1. 定位溢出位置;2. 检查递归大局部变量;3. 修改代码使用堆内存或迭代;4. 必要时调整栈大小;5. 检查依赖库更新。同时提供具体示例排查方法,帮助用户逐步解决。</think>### AddressSanitizer 栈溢出问题解决方案 栈溢出通常由以下原因引起: 1. 过深的递归调用 2. 局部变量占用过多栈空间 3. 编译器分配的临时缓冲区过大 #### 步骤 1:定位问题代码 通过地址信息定位具体代码位置: ```bash addr2line -e 你的可执行文件 0x559f21a3d805 ``` 这将输出对应的源码文件行号[^2] #### 步骤 2:常见修复方法 1. **递归深度优化** ```c // 错误示例:无终止条件的递归 void infinite_recursion() { infinite_recursion(); // 导致栈溢出 } // 修正方案:改为迭代算法 void iterative_approach() { while (condition) { // 处理逻辑 } } ``` 2. **大对象堆分配** ```c // 错误示例:栈上分配大数组 void process_data() { int buffer[1000000]; // 占用4MB栈空间 // ... } // 修正方案:改用堆内存 void process_data_fixed() { int* buffer = malloc(1000000 * sizeof(int)); // ... free(buffer); } ``` 3. **编译器选项调整** ```bash # 临时增加栈大小(Linux) ulimit -s 65536 # 设置栈大小为64MB # 编译时指定栈大小 gcc -Wl,-z,stack-size=4194304 # 4MB栈空间 ``` #### 步骤 3:验证修复 ```bash ASAN_OPTIONS=detect_stack_use_after_return=1 ./your_program ``` #### 典型错误模式分析 错误信息 `pc 0x559f21a3d805 bp 0x7ffc1a172010 sp 0x7ffc1a172000` 显示: - `sp` (栈指针) 接近 `bp` (基指针),说明栈空间已耗尽 - 内存地址范围属于进程的栈内存区域(通常位于高地址区) #### 进阶调试技巧 使用 GDB 分析栈帧: ```gdb (gdb) frame 0 (gdb) info locals (gdb) backtrace ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值