MicroPython 是一种适用于微控制器和其他受限环境的 Python 编程语言的实现。它旨在提供与 Python 3 语言的紧密兼容,同时考虑到内存和计算资源的限制。MicroPython 库是这门语言的核心组成部分,提供了一系列的模块和函数,使得开发者能够在硬件上执行各种任务。
下面将通过系列文章,逐一解读microPython,以便让读者了解掌握microPython的整个核心逻辑.,以便读者可以透过这个Python的最小内核,掌握Python解析器的核心实现逻辑,学习世界上最优秀的源码设计之一.
microPython Python最小内核源码解析
这段代码是针对MicroPython运行在POWERPC架构上的非局部返回(Non-Local Return,NLR)机制的实现。它包括两个主要的函数:nlr_push
和nlr_jump
。nlr_push
函数用于在进入一个可能抛出异常的代码块之前保存当前的寄存器状态,而nlr_jump
函数则用于在异常发生后从保存的状态中恢复寄存器,并跳转回异常发生前的位置继续执行。
在64位LP64体系结构和32位体系结构中,这些函数的实现略有不同,主要体现在寄存器的存储和恢复指令上。此外,代码中使用了内联汇编,这是一种在C代码中直接嵌入汇编指令的方法,用于实现对硬件寄存器的直接操作。
#include "py/mpstate.h"
// 针对POWERPC架构,取消默认的nlr_push函数定义
#if MICROPY_NLR_POWERPC
#undef nlr_push
// 为64位LP64体系结构定义nlr_push函数
#ifdef __LP64__
// 保存所有ABI非易失性寄存器
unsigned int nlr_push(nlr_buf_t *nlr) {
// 汇编代码块开始,使用volatile关键字防止编译器优化
__asm__ volatile (
// 将0x4eed这个值存储到寄存器4中,作为canary(一种调试辅助值)
"li 4, 0x4eed ; "
// 依次将通用寄存器0到31的值存储到nlr_buf_t结构体中对应的位置
"std 0, 0x08(%0) ;"
"std 1, 0x10(%0) ;"
// ... 省略中间的寄存器存储代码 ...
"std 31, 0xA8(%0) ;"
// 将CR寄存器的值存储到nlr_buf_t结构体中
"mfcr 4 ; "
"std 4, 0xB0(%0) ;"
// 将LR寄存器的值存储到nlr_buf_t结构体中
"mflr 4 ;"
"std 4, 0xB8(%0) ;"
// 准备跳转到nlr_push_tail标签,这是一个异常处理的尾部代码
"li 4, nlr_push_tail@l ;"
"oris 4, 4, nlr_push_tail@h ;"
// 设置CTR寄存器为上面计算出的异常处理尾部代码的地址
"mtctr 4 ;"
// 将nlr_buf_t指针保存到寄存器3中
"mr 3, %1 ; "
// 跳转到CTR寄存器指向的代码,即nlr_push_tail
"bctr ;"
:
: "r" (&nlr->regs), "r" (nlr)
:
);
// 函数返回0,表示成功
return 0;
}
// nlr_jump函数,用于跳转到非局部返回点
NORETURN void nlr_jump(void *val) {
// 这里使用了宏MP_NLR_JUMP_HEAD,它的作用是加载非局部跳转的头部信息
MP_NLR_JUMP_HEAD(val, top)
// 汇编代码块开始,用于从nlr_buf_t结构体中恢复寄存器的值
__asm__ volatile (
// 检查canary值,如果不等于0x4eed则跳转到当前位置,这通常意味着发生了栈破坏
"ld 3, 0x0(%0) ;"
"cmpdi 3, 0x4eed ; "
"bne . ; "
// 从nlr_buf_t结构体中恢复所有通用寄存器的值
"ld 0, 0x08(%0) ;"
"ld 1, 0x10(%0) ;"
// ... 省略中间的寄存器恢复代码 ...
"ld 31, 0xA8(%0) ;"
// 从nlr_buf_t结构体中恢复CR寄存器的值
"ld 3, 0xB0(%0) ;"
"mtcr 3 ;"
// 从nlr_buf_t结构体中恢复LR寄存器的值
"ld 3, 0xB8(%0) ;"
"mtlr 3 ; "
// 跳转到LR寄存器指向的代码,完成非局部返回
"li 3, 1;"
"blr ;"
:
: "r" (&top->regs)
: "memory"