扩展GCC asm中多个输入和输出操作数的正确用法是什么? [英] What is the correct use of multiple input and output operands in extended GCC asm?

查看:187
本文介绍了扩展GCC asm中多个输入和输出操作数的正确用法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在寄存器约束下,扩展GCC asm中多个输入和输出操作数的正确用法是什么?考虑这个问题的最小版本.以下是GCC,AT& T语法中扩展的简短的asm代码:

What is the correct use of multiple input and output operands in extended GCC asm under register constraint? Consider this minimal version of my problem. The following brief extended asm code in GCC, AT&T syntax:

    int input0 = 10;
    int input1 = 15;
    int output0 = 0;
    int output1 = 1;

    asm volatile("mov %[input0], %[output0]\t\n"
                 "mov %[input1], %[output1]\t\n"
                 : [output0] "=r" (output0), [output1] "=r" (output1)
                 : [input0] "r" (input0), [input1] "r" (input1)
                 :);

    printf("output0: %d\n", output0);
    printf("output1: %d\n", output1);

基于 https://gcc.gnu.org/,语法似乎正确onlinedocs/gcc/Extended-Asm.html 但是,我一定忽略了某些东西,或者犯了一些我出于某种原因看不到的小错误.

The syntax appears correct based on https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html However, I must have overlooked something or be committing some trivial mistake that I for some reason can't see.

GCC 5.3.0 p1.0的输出(无编译器参数)为:

The output with GCC 5.3.0 p1.0 (no compiler arguments) is:

输出0:10
输出1:10

output0: 10
output1: 10

预期输出为:

输出0:10
输出1:15

output0: 10
output1: 15

在GDB中查看它会显示:

Looking at it in GDB shows:

0x0000000000400581< +43>:mov eax,DWORD PTR [rbp-0x10]
0x0000000000400584< +46>:mov edx,DWORD PTR [rbp-0xc]
0x0000000000400587< +49>:mov edx,eax
0x0000000000400589< +51>:mov eax,edx
0x000000000040058b< +53>:mov DWORD PTR [rbp-0x8],edx
0x000000000040058e< +56>:mov DWORD PTR [rbp-0x4],eax

0x0000000000400581 <+43>: mov eax,DWORD PTR [rbp-0x10]
0x0000000000400584 <+46>: mov edx,DWORD PTR [rbp-0xc]
0x0000000000400587 <+49>: mov edx,eax
0x0000000000400589 <+51>: mov eax,edx
0x000000000040058b <+53>: mov DWORD PTR [rbp-0x8],edx
0x000000000040058e <+56>: mov DWORD PTR [rbp-0x4],eax

据我所见,它在input0中加载eax,在input1中加载edx.然后,它用eax覆盖edx和用edx覆盖eax,使它们相等.然后将它们写回到output0和output1.

From what I can see it loads eax with input0 and edx with input1. It then overwrites edx with eax and eax with edx, making these equal. It then writes these back into output0 and output1.

如果我对输出使用内存约束(= m)而不是寄存器约束(= r),它将提供预期的输出,并且汇编看起来更加合理.

If I use a memory constraint (=m) instead of a register constraint (=r) for the output, it gives the expected output and the assembly looks more reasonable.

推荐答案

问题是GCC假定所有输入操作数都被消耗完之后,所有所有输出操作数都只写在指令的末尾.这意味着它可以使用相同的操作数(例如寄存器)作为输入操作数和输出操作数,这就是这里发生的情况.解决方案是在[output0]上标记早期破坏者约束,以便GCC知道它写在asm语句结束之前.

The problem is that GCC assumes that all all output operands are only written at the end of the instruction, after all input operands have been consumed. This means it can use the same operand (eg. a register) as an input operand and an output operand which is what is happening here. The solution is to mark [output0] with an early clobber constraint so that GCC knows that its written to before the end of the asm statement.

例如:

 asm volatile("mov %[input0], %[output0]\t\n"
              "mov %[input1], %[output1]\t\n"
              : [output0] "=&r" (output0), [output1] "=r" (output1)
              : [input0] "r" (input0), [input1] "r" (input1)
              :);

您不需要将[output1]标记为早期破坏者,因为它仅在指令末尾写入,因此使用与[input0][input1]相同的寄存器无关紧要.

You don't need to mark [output1] as early clobber because it's only written to at the end of the instruction so it doesn't matter if it uses the same register as [input0] or [input1].

这篇关于扩展GCC asm中多个输入和输出操作数的正确用法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆