【问题标题】:In-line assembly to perform syscall with return value in ARM在 ARM 中执行带返回值的系统调用的内联汇编
【发布时间】:2018-04-13 05:07:55
【问题描述】:

我发现了许多使用 asm 运行 Hello World 系统调用的示例,但没有一个涉及使用返回值调用系统调用。我的代码是

int my_syscall(int sn)
{
    int output_variable = 0;
    int input_variable = sn;
    __asm__ volatile(
    "mov r7,%1\n\t"
    "svc 0\n\t"
    "mov %0,r0\n\t"
    :"=r"(output_variable)
    :"r"(input_variable)
    );
    return output_variable;
}

在 ARM linux(BeagleBone Black) 上运行它会给我一个分段错误。

【问题讨论】:

  • 应该是哪个系统调用?通过strace 运行它。此外,您在不告诉编译器的情况下(至少)破坏r0r7。如果您需要特定寄存器中的内容,请使用寄存器变量,而不是 mov 指令。
  • 正如 Jester 所说,使用register int retval asm("r0") 来控制哪个寄存器"=r" 为没有特定寄存器约束的机器选择is a supported use of asm register variables。你的 asm 中不需要任何 mov 指令,应该尽量避免它们。
  • 你有没有先尝试真正的组装?从那里开始工作,然后如果绝对必要,然后使用内联
  • Start as thumb, klibc common and shims, static library arm cross compile...write() 的一个工作示例在最后一个链接中,您可以使用它来制作粗略的“打印”工具。 write("Hello World") 返回一个值。

标签: linux linux-kernel arm system-calls inline-assembly


【解决方案1】:

修复:修复是在使用 arm-linux-gnueabihf-gcc 编译时使用“-fomit-frame-pointer”指令(可能也适用于其他风格)。

$arm-linux-gnueabihf-gcc {YOUR FILE NAME}.c -fomit-frame-pointer -o {YOUR OUTPUT FILE NAME}

感谢你们所有的 cmets。因此,为了记录,问题中的上述代码逻辑有效。据我了解,问题在于编译器出于某种原因使用 r7 作为帧指针。您可以继续添加参数作为输入,并使用内联汇编创建更通用的系统调用实现。考虑一下人们在 cmets 中所说的话,以便更好地实施。

伪代码

returntype my_syscall(int syscallnumber,type arg1,type arg2,..)
{
    int output_variable = 0;
    __asm__ volatile
    (
        "mov r7,[sysnum]\n\t"
        "mov r0,[var1]\n\t"
        "mov r1,[var2]\n\t"
                             //continue similarly for more input arguments etc 
        "svc 0\n\t"
        "mov %0,r0\n\t"      //Return value of syscall will be available in r0 for ARM EABI
        :"=r"(output_variable)
        :[sysnum]"r"(syscallnumber),[var1]"r"(arg1),[var2]"r"(arg2) //and so on for other arguments
        :"memory" //clobber others based on usage
    );
    return output_variable;
}

背景故事(对于任何感兴趣的人):当我实现一个简单的“Hello World”字符串写入(更改包括不同的系统调用号和参数)时,相同的代码(问题中存在的那个)略有不同。但是当我调用返回所需值的自定义系统调用时它不起作用(或者,您可以将系统调用设计为使用参数而不是返回指令返回值以避免整个问题。我没有这样做,因为那时我会必须重新编译整个内核,但我离题了)。我用内置的 syscall() 函数测试了我的系统调用,它运行良好。但是 syscall() 函数的 MY 实现无法调用 MY 自定义系统调用。 我尝试了寄存器变量,尝试了不同的指令并破坏了 r0、内存等(在我在这里提出问题之前),但似乎没有任何效果。然后我尝试破坏 r7 并且编译器说你不能这样做。所以那时我发现 r7 寄存器也被用于其他用途。当我搜索错误时,我发现了上面的fix。 具有讽刺意味的是,在修复后它没有破坏 r7 或其他任何东西。哈哈。

【讨论】:

  • 这个内联汇编不正确:编译器可能决定使用r7 代替arg1,然后您将用系统调用号覆盖它。它可能不会,但您没有告诉编译器您在程序集中使用它。请参阅ethernut.de/en/documents/arm-inline-asm.html,以全面了解 ARM 中的内联汇编以及如何安全使用它。
猜你喜欢
  • 2020-06-07
  • 1970-01-01
  • 2021-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-28
  • 1970-01-01
相关资源
最近更新 更多