【问题标题】:asm in C "too many memory references for `mov'"C语言中的asm“'mov'的内存引用过多”
【发布时间】:2013-02-23 00:11:20
【问题描述】:

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

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

...这是代码(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
        }
    }

【问题讨论】:

  • 您不应该使用% 进行所有注册访问吗?
  • 我认为您在注册名称之前忘记了一些 % 符号。
  • 问题末尾的那 3 行告诉我我的帖子主要是代码是什么?
  • 看来你的帖子主要是代码;请添加更多详细信息。
  • 您必须在 Intel 和 AT&T asm 语法之间进行选择。

标签: c assembly


【解决方案1】:

gcc 的汇编代码是not correctly formatted

首先,gcc 使用 AT&T 语法(编辑:by default, thanks nrz),因此它需要为每个寄存器引用添加一个%,并为立即操作数添加一个$。目标操作数总是在右边

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

您通常应该尽量减少您的汇编器,因为它可能会导致优化器出现问题。最小化所需汇编程序的最简单方法可能是将 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)                                           
    );
}

然后只需简单地调用 using;

int a=1, b, c, d;

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

另一种可能更优雅的方式是do it using macros

【讨论】:

  • 这段代码也缺少寄存器约束,所以据我所知它是完全不安全/伪造的。你必须告诉 gcc 你将使用/clobber 哪些寄存器以及输入/输出去哪里。
  • @R.. 是的,我的错,我从页面中选择了一个不好的例子。将其替换为一些信息链接和更相关的示例。
【解决方案2】:
  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 article 给出了一个返回 eax 的工作示例。

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

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

【讨论】:

    猜你喜欢
    • 2019-07-25
    • 1970-01-01
    • 1970-01-01
    • 2016-01-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-20
    相关资源
    最近更新 更多