【问题标题】:How to make a cross-platform c++ inline assembly language?如何制作跨平台的 c++ 内联汇编语言?
【发布时间】:2010-10-20 18:55:30
【问题描述】:

我破解了以下代码:

unsigned long long get_cc_time () volatile {
  uint64 ret;
  __asm__ __volatile__("rdtsc" : "=A" (ret) : :);
  return ret;
}

它适用于 g++,但不适用于 Visual Studio。 我怎样才能移植它? 检测 VS/g++ 的正确宏是什么?

【问题讨论】:

    标签: c++ cross-platform assembly


    【解决方案1】:
    #if defined(_MSC_VER)
    // visual c
    #elif defined(__GCCE__)
    // gcce
    #else
    // unknown
    #endif
    

    我的内联汇编技能生疏了,但它的工作原理如下:

    __asm
    {
    // some assembler code
    }
    

    但要仅使用 rdtsc,您可以只使用内在函数:

    unsigned __int64 counter;
    counter = __rdtsc();
    

    http://msdn.microsoft.com/en-us/library/twchhe95.aspx

    【讨论】:

    • 谢谢!内部函数 rdtsc 是否有 linux 变体?
    【解决方案2】:

    OP 搁置的具体问题:我找到了一种方法来定义适用于两种语法版本的宏:

    #ifdef _MSC_VER
    #   define ASM(asm_literal) \
            __asm { \
                asm_literal \
            };
    #elif __GNUC__ || __clang__
    #   define ASM(asm_literal) \
            "__asm__(\"" \
                #asm_literal \
            "\" : : );"
    #endif
    

    不幸的是,因为预处理器strips newlines before macro expansion,你必须用这个宏包围每个汇编语句。

    float abs(float x) {
        ASM( fld     dword ptr[x] );
        ASM( fabs                 );
        ASM( fstp    dword ptr[x] );
    
        return x;
    }
    

    但请注意 GCC 和 clang use AT&T/UNIX assembly synax 但 MSVC 使用 Intel 汇编语法(虽然找不到任何官方来源)。但幸运的是 GCC/clang 也可以是 configured to use Intel syntax。要么使用__asm__(".intel_syntax noprefix");/__asm__(".att_syntax prefix");(请务必重置更改,因为它会影响从那时起生成的所有程序集,甚至是编译器从C源代码生成的程序集)。这会给我们留下这样的宏:

    #ifdef _MSC_VER
    #   define ASM(asm_literal) \
            __asm { \
                asm_literal \
            };
    #elif __GNUC__ || __clang__
    #   define ASM(asm_literal) \
            "__asm__(\".intel_syntax noprefix\");" \
            "__asm__(\"" \
                #asm_literal \
            "\" : : );" \
            "__asm__(\".att_syntax prefix\");"
    #endif
    

    或者您也可以使用 -masm=intel 标志使用 GCC/clang 进行编译,这会全局切换语法。

    【讨论】:

      【解决方案3】:

      VC++ 中有一个 _MSC_VER 宏,它在 MSDN 中被描述为“Microsoft 特定”,并且可能在其他编译器上编译代码时没有定义。您可以使用#ifdef 来确定它是什么编译器,并为 gcc 和 VC++ 编译不同的代码。

      #ifdef _MSC_VER
          //VC++ version
      #else
          //gcc version
      #endif
      

      【讨论】:

        【解决方案4】:

        直接使用RDTSC 指令有一些严重的缺点:

        • TSC 不能保证在所有 CPU 上同步,因此如果您的线程/进程从一个 CPU 内核迁移到另一个 CPU 内核,则 TSC 可能会在时间上向前或向后“扭曲”,除非您使用线程/进程关联来防止迁移。
        • 不能保证 TSC 以恒定速率前进,尤其是在启用了电源管理或“C1 时钟斜坡”的 PC 上。对于多个 CPU,这可能会增加偏差(例如,如果您有一个线程正在旋转而另一个线程正在休眠,则一个 TSC 可能会比另一个推进得更快)。
        • 直接访问 TSC 不允许您利用 HPET

        使用 OS 计时器接口更好,但仍可能有一些相同的缺点,具体取决于实现:

        另请注意,Microsoft Visual C++ 在面向 64 位处理器时不支持内联汇编,因此 Virne 指出了 __rdtsc() 内在函数。

        【讨论】:

        • 或者更好地使用独立于平台的库组件,例如dre.vanderbilt.edu/Doxygen/Stable/ace/…
        • TSC 有其缺点,如上所述,但它也有其优点。它非常快(20-30 个时钟滴答),而所有其他机制(例如 HPET)都涉及进入环 0,因此需要 1000 个时钟滴答或更多。这是精确的,而标准操作系统工具通常提供 10 毫秒的粒度。 HPET 在许多系统上不可用,并且当它可用时,它可能只能由超级用户访问。不要问我为什么——只要找到最近的 Linux 机器并检查 /dev/hpet 的权限。
        • 至于同步,它通常在台式机 Intel 上跨内核同步(不确定移动 Intel),在 AMD 上,您可以通过修改线程的处理器亲和性来限制跨内核迁移。跨度>
        猜你喜欢
        • 2012-05-23
        • 1970-01-01
        • 2018-06-07
        • 2011-01-11
        • 2014-01-18
        • 2021-01-19
        • 1970-01-01
        • 2012-04-21
        • 1970-01-01
        相关资源
        最近更新 更多