C语言 C中的asm“`mov'的内存引用过多”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15035379/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 05:25:20  来源:igfitidea点击:

asm in C "too many memory references for `mov'"

cassembly

提问by user2101247

I've seen the post about the same error but i'm still get error :

我看过关于相同错误的帖子,但我仍然收到错误:

 too many memory references for `mov'
 junk `hCPUIDmov buffer' after expression

... here's the code (mingw compiler / C::B) :

...这是代码(mingw编译器/C::B):


    #include iostream

    using namespace std;

    union aregister
    {
        int theint;
        unsigned bits[32];
    };

    union tonibbles
    {
        int integer;
        short parts[2];
    };

    void GetSerial()
    {
        int part1,part2,part3;
        aregister issupported;
        int buffer;

        __asm(
            "mov %eax, 01h"
            "CPUID"
            "mov buffer, edx"
        );//do the cpuid, move the edx (feature set register) to "buffer"


        issupported.theint = buffer;
        if(issupported.bits[18])//it is supported
        {
            __asm(
                "mov part1, eax"
                "mov %eax, 03h"
                "CPUID"
            );//move the first part into "part1" and call cpuid with the next subfunction to get
            //the next 64 bits

            __asm(
                "mov part2, edx"
                "mov part3, ecx"
            );//now we have all the 96 bits of the serial number


            tonibbles serial[3];//to split it up into two nibbles

            serial[0].integer = part1;//first part
            serial[1].integer = part2;//second
            serial[2].integer = part3;//third
        }
    }

回答by Joachim Isaksson

Your assembly code is not correctly formattedfor gcc.

您的汇编代码格式不适合 gcc。

Firstly, gcc uses AT&T syntax (EDIT: by default, thanks nrz), so it needs a %added for each register reference and a $for immediate operands. The destination operand is always on the rightside.

首先,gcc 使用 AT&T 语法(编辑:默认情况下,感谢 nrz),因此它需要%为每个寄存器引用添加一个$,并为立即操作数添加一个。目标操作数始终在右侧

Secondly, you'll need to pass a line separator (for example \n\t) for a new line. Since gcc passes your string straight to the assembler, it requires a particular syntax.

其次,您需要\n\t为新行传递一个行分隔符(例如)。由于 gcc 将您的字符串直接传递给汇编程序,因此它需要特定的语法。

You should usually try hard to minimize your assembler since it may cause problems for the optimizer. Simplest way to minimize the assembler required would probably be to break the cpuid instruction out into a function, and reuse that.

您通常应该努力最小化您的汇编程序,因为它可能会导致优化程序出现问题。最小化所需汇编程序的最简单方法可能是将 cpuid 指令分解为一个函数,然后重用它。

void cpuid(int32_t *peax, int32_t *pebx, int32_t *pecx, int32_t *pedx)
{
    __asm(
         "CPUID"
          /* All outputs (eax, ebx, ecx, edx) */
        : "=a"(*peax), "=b"(*pebx), "=c"(*pecx), "=d"(*pedx)   
          /* All inputs (eax) */
        : "a"(*peax)                                           
    );
}

Then just simply call using;

然后只需简单地调用 using;

int a=1, b, c, d;

cpuid(&a, &b, &c, &d);

Another possibly more elegant way is to do it using macros.

另一种可能更优雅的方法是使用宏实现

回答by tc.

  1. Because of how C works,

    __asm(
        "mov %eax, 01h"
        "CPUID"
        "mov buffer, edx"
    );
    

    is equivalent to

    __asm("mov %eax, 01h" "CPUID" "mov buffer, edx");
    

    which is equivalent to

    __asm("mov %eax, 01hCPUIDmov buffer, edx");
    

    which isn't what you want.

  2. AT&T syntax (GAS's default) puts the destination register at the end.

  3. AT&T syntax requires immediates to be prefixed with $.

  4. You can't reference local variables like that; you need to pass them in as operands.

  1. 由于 C 的工作方式,

    __asm(
        "mov %eax, 01h"
        "CPUID"
        "mov buffer, edx"
    );
    

    相当于

    __asm("mov %eax, 01h" "CPUID" "mov buffer, edx");
    

    这相当于

    __asm("mov %eax, 01hCPUIDmov buffer, edx");
    

    这不是你想要的。

  2. AT&T 语法(GAS 的默认值)将目标寄存器放在最后。

  3. AT&T 语法要求立即数以 $ 为前缀。

  4. 你不能像那样引用局部变量;您需要将它们作为操作数传入。

Wikipedia's articlegives a working example that returns eax.

维基百科的文章给出了一个返回 eax 的工作示例。

The following snippet might cover your use-cases (I'm not intricately familiar with GCC inline assembly or CPUID):

以下代码段可能涵盖您的用例(我对 GCC 内联汇编或 CPUID 并不十分熟悉):

int eax, ebx, ecx, edx;
eax = 1;
__asm( "cpuid"
     : "+a" (eax), "+b" (ebx), "+c" (ecx), "+d" (edx));
buffer = edx