【问题标题】:ARM Assembly - What is happening in this code?ARM 汇编 - 这段代码发生了什么?
【发布时间】:2015-06-16 13:52:52
【问题描述】:

我正在查看一些 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 中?

【问题讨论】:

  • 实际实现在哪里......” - 你知道what a syscall is,对吧? ;)
  • @Notlikethat,当然。也许不是。你什么意思?我知道用户空间中的用户 do 的系统调用是什么,但它们的实现是我不熟悉的。
  • @sherrellbc 实现将在操作系统源代码中。
  • 这类似于函数调用,但它是系统调用,有一个系统处理程序正在执行实际工作,这只是传递参数和进行系统调用的包装器,操作系统正在工作
  • @sherrellbc 系统调用号是系统调用表中的条目。 writev 可通过 sycall 表中的第 146 个函数指针访问。这些数字是固定的,因为当发布新版本的内核时,还需要新版本的 libc(带有更新的系统调用编号)

标签: assembly arm


【解决方案1】:

writev 的实际实现位于操作系统内核的某个位置。 SWI 指令使 CPU 切换到管理员模式,并开始执行内核的异常处理程序。在超级用户模式下,内核可以做一些用户模式代码不能直接做的事情,比如访问设备。

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

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

【讨论】:

    猜你喜欢
    • 2015-06-22
    • 2016-06-09
    • 2018-07-28
    • 1970-01-01
    • 1970-01-01
    • 2012-08-29
    • 2014-11-12
    • 2012-07-26
    相关资源
    最近更新 更多