Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 此汇编函数调用是否安全/完成?_C_Assembly_X86_Inline Assembly_Function Calls - Fatal编程技术网

C 此汇编函数调用是否安全/完成?

C 此汇编函数调用是否安全/完成?,c,assembly,x86,inline-assembly,function-calls,C,Assembly,X86,Inline Assembly,Function Calls,我没有组装方面的经验,但这就是我一直在做的。如果我缺少传递参数和通过汇编中的指针调用函数的任何基本方面,我希望输入 例如,我想知道我是否应该恢复ecx,edx,esi,edi。我读到它们是通用寄存器,但我找不到它们是否需要恢复?我接到电话后应该做什么清理工作 这是我现在拥有的代码,它确实有效: #include "stdio.h" void foo(int a, int b, int c, int d) { printf("values = %d and %d and %d and %d\

我没有组装方面的经验,但这就是我一直在做的。如果我缺少传递参数和通过汇编中的指针调用函数的任何基本方面,我希望输入

例如,我想知道我是否应该恢复
ecx
edx
esi
edi
。我读到它们是通用寄存器,但我找不到它们是否需要恢复?我接到电话后应该做什么清理工作

这是我现在拥有的代码,它确实有效:

#include "stdio.h"

void foo(int a, int b, int c, int d)
{
  printf("values = %d and %d and %d and %d\r\n", a, b, c, d);
}

int main()
{

  int a=3,b=6,c=9,d=12;
  __asm__(
          "mov %3, %%ecx;"
          "mov %2, %%edx;"
          "mov %1, %%esi;"
          "mov %0, %%edi;"
          "call %4;"
          :
          : "g"(a), "g"(b), "g"(c), "g"(d), "a"(foo)
          );

}
我读到它们是通用寄存器,但我找不到它们是否是通用寄存器 需要恢复吗

我不是该领域的专家,但从我对(图3.4)的阅读来看,以下寄存器:
%rdi
%rsi
%rdx
%rcx
在函数调用之间不被保留,因此显然不需要恢复

正如David Wohlferd所评论的,您应该小心,因为无论哪种方式,编译器都不会意识到“自定义”函数调用,因此您可能会妨碍它,特别是因为它可能不会意识到寄存器修改

我读到它们是通用寄存器,但我找不到它们是否是通用寄存器 需要恢复吗

我不是该领域的专家,但从我对(图3.4)的阅读来看,以下寄存器:
%rdi
%rsi
%rdx
%rcx
在函数调用之间不被保留,因此显然不需要恢复


正如David Wohlferd所评论的,您应该小心,因为无论哪种方式,编译器都不会意识到“自定义”函数调用,因此您可能会妨碍它,特别是因为它可能不会意识到寄存器修改。

最初的问题是
此汇编函数调用是否安全/完整?
。答案是:不。虽然在这个简单的例子中它可能会起作用(特别是在禁用优化的情况下),但您违反了最终会导致失败的规则(那些很难跟踪的规则)

我想解决(明显的)后续问题,即如何使其安全,但如果没有OP对实际意图的反馈,我真的无法做到这一点

因此,我将尽我所能,描述使其不安全的因素,以及您可以采取的措施

让我们从简化asm开始:

 __asm__(
          "mov %0, %%edi;"
          :
          : "g"(a)
          );
即使只有这一条语句,这段代码也已经不安全了。为什么?因为我们在不让编译器知道的情况下更改寄存器(edi)的值

编译器怎么可能不知道你在问什么?毕竟,它就在asm中!答案来自下面的一行:

GCC不解析汇编指令本身,也不 知道它们的意思,甚至知道它们是否是有效的汇编程序输入

在这种情况下,您如何让gcc知道发生了什么?答案在于使用约束(冒号后面的内容)来描述asm的影响

修复此代码的最简单方法可能如下所示:

  __asm__(
          "mov %0, %%edi;"
          :
          : "g"(a)
          : edi
          );
int junk;
  __asm__ volatile (
          ""
          : "=D" (junk)
          : "0"(a)
          );
这会将edi添加到数据包中。简言之,这告诉gcc edi的值将由代码更改,并且gcc不应假设asm退出时edi中会有任何特定的值

现在,虽然这是最简单的方法,但不一定是最好的方法。考虑这个代码:

  __asm__(
          ""
          :
          : "D"(a)
          );
这将使用a来告诉gcc将变量
a
的值放入edi寄存器中。通过这种方式,gcc将在“方便”的时候为您加载寄存器,可能是始终在edi中保留
a

这段代码有一个(重要的)警告:通过将参数放在第二个冒号之后,我们将其声明为输入。输入参数必须是只读的(即退出asm时必须具有相同的值)

在您的情况下,
call
语句意味着我们无法保证edi不会被更改,因此这不起作用。有几种方法可以解决这个问题。最简单的方法是将约束上移到第一个冒号之后,使其成为输出,并指定
“+D”
以指示该值为读写。但是在asm之后,
a
的内容将几乎没有定义(printf可以将其设置为任何内容)。如果销毁
a
是不可接受的,那么总会有这样的情况:

  __asm__(
          "mov %0, %%edi;"
          :
          : "g"(a)
          : edi
          );
int junk;
  __asm__ volatile (
          ""
          : "=D" (junk)
          : "0"(a)
          );
这告诉gcc,在启动asm时,它应该将变量
a
的值放在与输出约束#0(即edi)相同的位置。它还表示,在输出时,edi将不再是
a
,它将包含变量
junk

Edit:由于实际上不使用“junk”变量,我们需要添加
volatile
限定符。当没有任何输出参数时,Volatile是隐式的

这条线的另一点是:以分号结束。这是合法的,将按预期工作。但是,如果您想使用
-S
命令行选项查看生成了哪些代码(如果您想更好地使用内联asm,您会发现这会产生难以阅读的代码)。我建议使用
\n\t
而不是分号

所有这些,我们仍然在第一线

显然,这同样适用于另外两个
mov
语句

这就引出了
call
语句

Michael和我都列举了一些原因,说明在内联asm中调用很困难

  • 处理所有可能被函数调用的ABI阻塞的寄存器
  • 处理红色区域
  • 处理对齐
  • 记忆冲击器
如果这里的目标是“学习”,那么可以自由地进行实验。但我不知道我是否会感到昏昏欲睡