ARM程序集 - 此代码中发生了什么?

时间:2015-06-16 13:52:53

标签: assembly arm

我正在查看一些Android源代码,发现writev的实现完全在汇编中。我对ASM有一般的工作知识,但不熟悉ARM指令集的细微差别。考虑这段代码:

ENTRY(writev)
    mov     ip, r7
    ldr     r7, =__NR_writev
    swi     #0
    mov     r7, ip
    cmn     r0, #(MAX_ERRNO + 1)
    bxls    lr
    neg     r0, r0
    b       __set_errno
END(writev)

经过一番搜索,我发现了以下内容:

__NR_writev = __NR_SYSCALL_BASE+146
__NR_SYSCALL_BASE = 0

这到底发生了什么?根据我的发现,ip寄存器是r12的别名,并且还称为临时寄存器。我在源代码中找到的几乎所有ASM实现都有这样的总体布局:

代码将r7加载到ip中,r7加载了例程的实际内存地址,然后发出软件中断。虽然我不确切知道发生了什么,但我可以看到剩下的代码是使用__NR_writev子程序调用的返回值来检查错误。

  • 如果此ASM例程仅重定向调用并检查错误,那么writev的实际实现在哪里?

  • 为什么r7被保存在这里以及为什么要进入ip(r12 / scratch register)?

  • 为什么实际实现的内存地址在SWI之前加载到r7?

1 个答案:

答案 0 :(得分:3)

writev的实际实现位于操作系统内核中。 SWI指令使CPU切换到管理程序模式,并开始执行内核的异常处理程序。在管理员模式下,内核可以执行用户模式代码无法直接执行的操作,例如访问设备。

R7的值保存到IP(R12),因为遵循的调用约定要求在整个调用中保留R7的值。它不需要保存IP寄存器。

加载到R7中的值不是地址,而是数字146.由于其他系统调用也使用SWI #0,它们最终都会在内核中执行相同的异常处理程序。 R7中的值用于确定调用哪个系统调用。异常处理程序可能会跳转到内核中的系统调用实现,方法是将R7中的值用作地址表中的缩放偏移量。