Android 臂组件。将r13(堆栈指针)用作通用寄存器是否安全?

Android 臂组件。将r13(堆栈指针)用作通用寄存器是否安全?,android,linux,assembly,arm,stack-pointer,Android,Linux,Assembly,Arm,Stack Pointer,我正在编写一个非常优化的叶函数,为了让它运行得更快,我想使用R13作为通用寄存器。在使用R13之前,我通过将其移动到一个VFP寄存器来保护它,在从函数返回之前,我通过将其移回来恢复它。看起来是这样的: /* Start of the function */ push { r4 - r12, r14 } vmov s0, r13 /* Body of the function. Here I use R13 * as a general purpose register */ vmov r13,

我正在编写一个非常优化的叶函数,为了让它运行得更快,我想使用R13作为通用寄存器。在使用R13之前,我通过将其移动到一个VFP寄存器来保护它,在从函数返回之前,我通过将其移回来恢复它。看起来是这样的:

/* Start of the function */
push { r4 - r12, r14 }
vmov s0, r13
/* Body of the function. Here I use R13
 * as a general purpose register */
vmov r13, s0
pop { r4 - r12, r14 }
bx lr

它是有效的。但我读到一些操作系统假设R13总是用作堆栈指针,而将其用作通用寄存器可能会导致崩溃。我还应该说,这个功能只打算在Android(Linux)上运行。谢谢 LR <强>,并且不能将一些工作移到霓虹灯寄存器,例如使用填充整数,即使只关心低32位。

(对于更多的标量整数,使用SIMD REG通常仅在算法中存在一组孤立的值,这些值不与其他值交互,并且您不需要对它们进行分支或将它们用作指针时才有用。在某些ARM CPU上,int和SIMD之间的传输很慢。)

这是非常不标准的,甚至只可能在用户空间中安全,而不是在内核中
如果安装了任何信号处理程序,则当其中一个信号到达时,堆栈指针必须有效。(这是异步的。)

除了信号处理程序之外,Linux中没有其他异步使用用户空间堆栈指针的方法。(除非您正在使用GDB进行调试,并使用
print foo(123)
,其中foo是目标进程中的一个函数。)

正如上的评论(x86-64相当于这个问题)中提到的,即使对于信号,也有一个变通方法:

使用
sigaltstack
设置替代堆栈,并在安装处理程序时在
sigaction
的标志中指定
sau ONSTACK

正如@Timothy指出的,如果SP的scratch值可能是一个正好“指向”alt堆栈的整数,那么信号分派机制将假定这是一个嵌套信号,并且不会修改SP(因为在实际的嵌套信号情况下,它将覆盖第一个信号处理程序仍在使用的堆栈)。因此,您可以将
从SP推到未映射页面,除非分配两倍于您需要的量,并且只将上半部分传递给
sigaltstack
。(对于简单的信号处理程序,可能只有2k或4k,它们在不做太多工作后返回)

即使使用嵌套信号,这也应该是安全的:只有最外层的信号处理程序可以在alt堆栈底部附近启动,并使用实际altstack之外的一些分配空间。如果SP仍在altstack内,则另一个信号将使用低于该值的空间。或者,如果SP已超出altstack,它将使用altstack的顶部

或者,如果您的任何GP寄存器需要成为指针,您可以通过使用SP来保存指向肯定不是alt堆栈的其他对象的指针来避免这种过度分配的需要。如果调试器使用当前SP进行某些操作,则将其作为有效指针会导致损坏而不是出现故障,或者如果altstack机制出错。但这只是故障模式的不同之处:两者都是灾难性的


硬件中断保存内核堆栈上的状态,而不是用户空间堆栈上的状态。如果他们使用了用户堆栈:

  • 用户空间可能因SP无效而导致操作系统崩溃
  • 用户空间可以通过让另一个用户空间线程修改内核的堆栈数据(包括返回地址)来获得内核权限
  • (进程的所有用户空间线程共享同一页表,并且可以读/写彼此的堆栈映射。)


    Linux/Android与没有虚拟内存或严格执行权限分离的轻量级RTO非常不同。

    当您的代码执行时触发上下文切换/irq时,OS/hw可能会假设R13是TOS,因此它会将其保存为可以恢复 恢复执行时的TOS

    在你的情况下,这可能是个问题

    一种明智的方法是使代码变得关键,并以某种方式强制系统勾选/irq挂起,直到例程完成/R13恢复


    如果您确实需要额外的寄存器,那么使用LR(R14)可能会更好。

    这不是一个好主意,也没有真正的理由将其用于堆栈以外的任何东西。如果你被打断,游戏就结束了,你会崩溃。用中断保护包装这段代码比仅仅用推、弹出其他寄存器并使用它包装这段代码更糟糕。所以只需使用另一个寄存器。不确定r13寄存器是否用于中断堆栈。ARM上的中断很奇怪。@old_timer:我假设/希望OP已经在使用所有其他GP寄存器,否则他们不会试图通过保存/恢复堆栈指针来获取更多的1。那么使用堆栈,不要干扰中断,尤其是在android、linux上。是否使用r13取决于内核和模式。,不过,这是一个很好的观点……由于堆栈切换是使用堆栈指针值触发的,因此需要分配两倍所需的堆栈大小,并将上半部分传递给
    sigaltstack
    @TimothyBaldwin:为什么它必须与线程的主堆栈相邻?还是同样大小?如果您的信号处理程序都很简单,您可能只需要一两页,它们就可以运行并进行
    sigreurn
    系统调用,以获取内核以还原旧上下文。OP使用堆栈指针作为通用寄存器,它可能包含任何值,包括传递给
    sigaltstack
    的范围内的值。假设堆栈指针指向传递给
    sigaltstack
    的范围底部时出现信号,在这种情况下,堆栈指针的当前值将用作alte