You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Supervisor模式下用C内联汇编写入lr_usr寄存器

问题分析与解决方案

1. lr_usr寄存器识别错误的问题

GCC内联汇编不支持直接使用lr_usr作为寄存器名,正确的用户模式LR寄存器的ARM指令命名是r14_usr。同时你的代码存在逻辑错误:"=r"(syscall_exit)是输出约束,意味着要把寄存器的值写入变量,但你实际是要把变量的值写入r14_usr,应该用输入约束。

修正后的代码:

asm volatile("msr r14_usr, %0" : : "r"(syscall_exit) : "memory");
  • volatile:防止编译器优化掉这条汇编指令
  • "r"(syscall_exit):让编译器把syscall_exit的值放到某个通用寄存器,替换%0
  • "memory":告诉编译器这段汇编会修改内存相关状态,确保内存操作的正确性

另外注意:你的第一行代码uint32_t syscall_exit = (uint32_t) syscall_exit;是自赋值,会导致未定义行为,应该改成正确的函数地址赋值,比如uint32_t syscall_exit = (uint32_t)&syscall_exit_func;(假设函数名为syscall_exit_func)。

2. ldr SPSR, #0x10的错误

这条指令是非法的:ARM架构中,SPSR只能通过msr/mrs指令访问,不能直接用ldr加载立即数。如果你想设置SPSR为0x10(用户模式的PSR值),应该用:

asm volatile("msr spsr_cxsf, #0x10");

3. ldmia &registers,{r0-r12,PC}^的有效性问题

这条指令存在两个问题:

  • 直接在汇编里写&registers会导致编译器无法正确处理地址,应该通过输入约束传递数组地址
  • ldmia的^后缀会在加载PC的同时,将SPSR的值恢复到CPSR,这会直接切换到用户模式,符合你的需求,但需要确保SPSR已经正确设置为用户模式的状态(即前面的msr spsr_cxsf, #0x10是正确的)

修正后的代码:

asm volatile("ldmia %0, {r0-r12, pc}^" : : "r"(registers) : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "pc");
  • "r"(registers):传递数组的首地址到通用寄存器,替换%0
  • clobber列表显式声明被修改的寄存器,告诉编译器这些寄存器的值会被覆盖,避免优化冲突

完整修正后的代码示例

// 假设你的函数定义
void syscall_exit_func(void) { /* ... */ }
void idle_thread_main(void) { /* ... */ }

void setup_user_mode(void) {
    uint32_t syscall_exit = (uint32_t)&syscall_exit_func;
    uint32_t registers[14] = {97,6,7,6,7,6,7,6,7,6,7,5,7,(uint32_t)idle_thread_main};

    // 设置SPSR为用户模式(0x10是ARM用户模式的PSR模式位)
    asm volatile("msr spsr_cxsf, #0x10");

    // 写入用户模式LR寄存器
    asm volatile("msr r14_usr, %0" : : "r"(syscall_exit) : "memory");

    // 加载r0-r12并跳转到用户模式的idle_thread_main
    asm volatile("ldmia %0, {r0-r12, pc}^" : : "r"(registers) : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "pc");
}

关键注意事项

  • 确保代码运行在Supervisor模式下,否则无法访问r14_usr和修改SPSR
  • ldmia ... pc^指令执行后,CPU会立即切换到用户模式,执行idle_thread_main,同时r0-r12被设置为数组中的值
  • 编译时需要添加ARM架构相关的编译选项,比如-march=armv7-a(根据你的实际架构调整)

内容的提问来源于stack exchange,提问作者user28496108

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 16:25:14