Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.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_Gcc_Inline Assembly - Fatal编程技术网

C 如何忽略内联程序集中的输出?

C 如何忽略内联程序集中的输出?,c,gcc,inline-assembly,C,Gcc,Inline Assembly,在内联汇编中,第一个:引用输出,第二个引用输入,如果我不想使用输出呢?我可以这样空着吗 asm ("add $0, %rcx" : :"m"(Example) /* intput */ ); 另外,如果我只想使用输出,我可以删除另一个:?如果冒号后面的所有部分都为空,则可以将输出部分保留为空并省略冒号 引自: 如果没有输出操作数,但有输入操作数,请将两个连续冒号放在输出操作数的位置: __asm__ ("some instructions&qu

在内联汇编中,第一个:引用输出,第二个引用输入,如果我不想使用输出呢?我可以这样空着吗

asm ("add $0, %rcx"
:
:"m"(Example) /* intput */
);

另外,如果我只想使用输出,我可以删除另一个

如果冒号后面的所有部分都为空,则可以将输出部分保留为空并省略冒号

引自:

如果没有输出操作数,但有输入操作数,请将两个连续冒号放在输出操作数的位置:

__asm__ ("some instructions"
   : /* No outputs. */
   : "r" (Offset / 8));
请注意,通常需要使用输出操作数或clobber将修改的寄存器告知编译器。您可以在同一行上放置多个冒号,例如

asm(“:”内存”)
是编写编译器屏障的常用方法。

如果冒号后面的所有部分都为空,则可以将输出部分保留为空并省略冒号

引自:

如果没有输出操作数,但有输入操作数,请将两个连续冒号放在输出操作数的位置:

__asm__ ("some instructions"
   : /* No outputs. */
   : "r" (Offset / 8));
请注意,通常需要使用输出操作数或clobber将修改的寄存器告知编译器。您可以在同一行上放置多个冒号,例如

asm(“::“内存”)
是编写编译器屏障的常用方法。

GCC确定哪些操作数是从冒号输出的还是从冒号输入的,而不是从缺少
“=”
“+”
推断出来的。是的,这是多余的,但不,你对此无能为力

您可以在同一行上放置多个冒号,例如
asm(“:”内存”)
是编写编译器屏障的常用方法。因此,包含必要的冒号并不痛苦。您可以编写
asm(“…”:“m”(输入))如果没有任何输出或碰撞,这实际上是安全的

但是您通常需要告诉编译器关于您修改的寄存器的信息,或者使用输出操作数,或者使用clobber,因此您通常需要全部三个冒号。或者,如果您不写任何寄存器,通常是因为您正在包装一些“系统”指令,这些指令具有某种效果,您通常不希望编译器重新排序内存访问。如
invlpg
。或例如:

asm("clflush %0" ::"m"(*ptr) : "memory");
应该有一个内存缓冲区,以便在任何早期存储(可能是到同一行)之后刷新缓存线


您的代码有一些语法错误,以及正确性/UB,至少如果您想添加内存操作数,而不是常量
0

在GNU C扩展Asm中,模板字符串非常类似于printf格式字符串,编译器可以在使用
%something
的操作数中替换它。(是的,它只是一个愚蠢的文本替换,创建文本以馈送给汇编程序,
作为
。GCC不“理解”asm,这就是为什么您必须使用输入/输出/克隆约束向编译器准确描述它)

当您想要一个文本
%
,如AT&T语法中的寄存器名,如
%rcx
,您必须实际写入
%%rcx

(通常最好避免硬编码寄存器;使用伪输出操作数让编译器选择要使用的寄存器。您甚至可以命名它们,如
%[input]

我假设您打算将内存源操作数添加到RCX。那将是
%0

$0
是立即数0,即
RCX+=0
,因此指令实际上只修改标志

假设您的意思是添加%0、%%rcx
,那么您的代码将写入一个寄存器(rcx)您必须告诉编译器有关您修改的寄存器/内存的信息。否则,它可能在RCX中有一个C变量,并期望在asm语句之后读取其值。因此,您需要一个(虚拟)输出或一个重击器

(如果您的意思是“添加$0,%%rcx”,那么唯一的体系结构效果就是设置标志。i386/amd64的内联asm已经隐式地有了一个
“cc”
clobber,因此我们不必告诉编译器这一副作用。)

您的
“添加%0,%%rcx”
安全选项包括:

使用重击器:

asm ("add %0, %%rcx"    // %0 expands the first operand, $0 was an immediate
    :
    : "Irm"(Example) /* input, also allow reg or 32-bit immediate */
    : "rcx"
);
使用伪输出操作数(并使其易失性,就像没有输出操作数时隐含的那样)。注意,我们可以省略asm语句的
:clobbers
部分

uint64_t dummy;
asm volatile ("add %0, %%rcx"
    : "=c"(dummy);       // "c" forces picking cl/cx/ecx/rcx based on size
    : "Irm"(Example)
);
// without volatile, the asm statement can be optimized away if you don't read dummy later
请注意,
push%%rcx;在add周围弹出%%rcx
是不安全的:它修改RSP,这可能会影响编译器为
“m”(示例)
选择的寻址模式,并在RSP下方的红色区域上移动


有关更多信息,请参阅。

GCC确定哪些操作数是从冒号输出的,而不是从缺少
“=”
“+”
推断出来的。是的,这是多余的,但不,你对此无能为力

您可以在同一行上放置多个冒号,例如
asm(“:”内存”)
是编写编译器屏障的常用方法。因此,包含必要的冒号并不痛苦。您可以编写
asm(“…”:“m”(输入))如果没有任何输出或碰撞,这实际上是安全的

但是您通常需要告诉编译器关于您修改的寄存器的信息,或者使用输出操作数,或者使用clobber,因此您通常需要全部三个冒号。或者,如果您不写任何寄存器,通常是因为您正在包装一些“系统”指令,这些指令具有某种效果,您通常不希望编译器重新排序内存访问。如
invlpg
。或例如:

asm("clflush %0" ::"m"(*ptr) : "memory");
应该有一个内存缓冲区,以便在任何早期存储(可能是到同一行)之后刷新缓存线


您的代码有一些语法错误,以及正确性/UB,至少如果您想添加内存操作数,而不是常量
0

在GNUC扩展Asm中,模板字符串非常类似于pri