将此嵌入式汇编代码转换为可与gcc

时间:2018-12-07 21:14:00

标签: assembly x86 g++ inline-assembly x87

我正在尝试转换这段代码,以便与g ++使用的AT&T程序集一起工作:

double sqrt13(double n)
{
__asm{
 fld n
 fsqrt
 }
}

基于此链接:https://ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html: 我尝试过:

double raiz (double n)
    __asm__ ( "fld n\n\t"
    "fsqrt\n\t" );

但我一直收到:

/tmp/cc2AQhHj.s|662|Error: junk `n' after expression|

同一错误消息在此文件的其他行中发生了四次以上

我下载了一个名为“ intel2gas”的程序,他对我说代码应该是这样的:

    __asm__ volatile__ (
    "fld %0\n"
    "fsqrt\n"
    :"=m"(n)
    :
    :"memory", "esi", "edi", "eax", "ebx", "ecx", "edx"
    );

将其放入函数中并尝试运行它,我收到:

 |39|error: expected ‘(’ before ‘volatile__’|
|42|error: expected ‘)’ before ‘:’ token|
|45|error: ‘volatile__’ was not declared in this scope|

加一个     | 46 |警告:函数中没有return语句,返回non-void |

那么,有什么建议吗?

1 个答案:

答案 0 :(得分:4)

intel2gas显然没有实现MSVC的支持,即在asm中的EAX(或ST0)中保留返回值,然后退出非void函数的末尾。即使内联包含__asm块的函数,MSVC仍将其视为实际返回值。在GNU C内联汇编中,仅当您使用输出或读/写约束时,寄存器值才是输出。

这就是为什么您得到warning: no return statement in function returning non-void并破坏代码的原因。

正如@MichaelPetch指出的那样,您应该使用t约束(x87堆栈的顶部)向编译器询问x87 FP寄存器堆栈上的输入浮点数。

double raiz (double n) {
    __asm__ ("fsqrt"
       : "+t"(n)          // read-write operand: top of x87 stack
    );
     return n;
}
不需要

asm volatile:即使没有使用输出,asm块也不需要运行任何副作用,并且输出是输入的纯函数。 (除非您要更改x87的舍入模式或精度)。

最好让编译器对其进行优化,或者在多次运行之间进行CSE。

作为独立功能,它将(on Godbolt)编译为

# gcc8.2 -O3 -ffast-math -m32   uses x87 by default, not SSE2
_Z4raizd:
    fld     QWORD PTR [esp+4]
   # start of inline asm
    fsqrt
   # end of inline asm.
    ret