【问题标题】:Why this function can't be static in Linux driver为什么这个函数在 Linux 驱动程序中不能是静态的
【发布时间】:2016-01-15 09:00:17
【问题描述】:

我有一些汇编代码封装在我的驱动程序代码的静态函数中。我的代码就像

static int _ARMVAtoPA(void *pvAddr)
{
__asm__ __volatile__(
    /* ; INTERRUPTS_OFF" */
    " mrs            r2, CPSR;\n" /* r2 saves current status */
    "CPSID  iaf;\n" /* Disable interrupts */

    /*In order to handle PAGE OUT scenario, we need do the same operation
      twice. In the first time, if PAGE OUT happens for the input address,
      translation abort will happen and OS will do PAGE IN operation
      Then the second time will succeed.
    */

    "mcr    p15, 0, r0, c7, c8, 0;\n "
    /*  ; get VA = <Rn> and run nonsecure translation
        ; with nonsecure privileged read permission.
        ; if the selected translation table has privileged
        ; read permission, the PA is loaded in the PA
        ; Register, otherwise abort information is loaded
        ; in the PA Register.
    */

    /* read in <Rd> the PA value */
     "mrc    p15, 0, r1, c7, c4, 0;\n"
    /* get VA = <Rn> and run nonsecure translation */
    " mcr    p15, 0, r0, c7, c8, 0;\n"

    /*  ; with nonsecure privileged read permission.
        ; if the selected translation table has privileged
        ; read permission, the PA is loaded in the PA
        ; Register, otherwise abort information is loaded
        ; in the PA Register.
    */
    "mrc    p15, 0, r0, c7, c4, 0;\n" /* read in <Rd> the PA value */

    /* restore INTERRUPTS_ON/OFF status*/
    "msr            cpsr, r2;\n" /* re-enable interrupts */

    "tst    r0, #0x1;\n"
    "ldr    r2, =0xffffffff;\n"

    /* if error happens,return INVALID_PHYSICAL_ADDRESS */
    "movne   r0, r2;\n"
    "biceq  r0, r0, #0xff;\n"
    "biceq  r0, r0, #0xf00;" /* if ok, clear the flag bits */
);
}

static unsigned long CpuUmAddrToCpuPAddr(void *pvCpuUmAddr)
{
    int phyAdrs;
    int mask = 0xFFF;  /* low 12bit */
    int offset = (int)pvCpuUmAddr & mask;
    int phyAdrsReg = _ARMVAtoPA((void *)pvCpuUmAddr);

    if (INVALID_PHYSICAL_ADDRESS != phyAdrsReg)
        phyAdrs = (phyAdrsReg & (~mask)) + offset;
    else
        phyAdrs = INVALID_PHYSICAL_ADDRESS;

    return phyAdrs;
}

如您所见,我尝试将虚拟地址从用户空间转换为物理地址。我正在从另一个项目中移植此代码,但我将 _ARMVAtoPA 函数修改为静态函数。

当我使用static int _ARMVAtoPA(void *pvAddr)时:

  • 这个转换函数(里面有一堆汇编代码)总是返回fffffff,肯定是错误情况。

当我使用int _ARMVAtoPA(void *pvAddr)时:

  • 这个转换函数可以正常工作。

谁能给我解释一下,为什么我使用静态和非静态函数时结果会有所不同。

谢谢

【问题讨论】:

  • 您可以在这两种情况下检查您的函数的结果(汇编程序)核心并进行比较。可能,序言或结语是不同的。
  • @Tsyvarev 我做了这个考试。汇编代码返回不同的值。

标签: c linux static linux-kernel


【解决方案1】:

ASM 代码没有定义哪个寄存器保存函数参数pvAddr 以及哪个寄存器保存返回值。它只是假设编译器遵循 mips ABI。

但是如果函数是内联的(static 可能是内联的),寄存器分配可能会改变,因此 asm 代码可能完全错误。

为了解决这个问题,你应该使用 gcc 扩展来为函数参数和返回值分配寄存器。并声明它将使用哪些寄存器而不使用恢复,以便编译器可以在调用后恢复寄存器,以防函数被内联。

【讨论】:

  • 谢谢,您的回答很有见地。
  • 静态修饰符,在 C 中,对于一个函数,只是意味着不能从某个外部文件访问该函数。它不会强制内联。
  • @user3629249 是的,你是对的,但inline 也是编译器优化行为。谢谢
猜你喜欢
  • 2010-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-01
  • 1970-01-01
  • 2014-06-06
  • 2018-08-25
  • 1970-01-01
相关资源
最近更新 更多