首页 文章

为什么包含在函数中的GAS内联汇编为调用者生成与纯汇编函数不同的指令

提问于
浏览
1

我've been writing some basic functions using GCC' s asm 练习实际应用 .

我的函数 prettywrappure 生成相同的指令,将64位整数解包为128位向量 . 分别调用 prettywrapadd1add2 也会生成相同的指令 . 但 add3 的不同之处在于通过将其推送到堆栈而不是将其复制到另一个 xmm 寄存器来保存其 xmm0 寄存器 . 这个我不明白,因为编译器可以看到 pure 的详细信息,知道其他 xmm 寄存器都不会被破坏 .

这是C

#include <immintrin.h>

__m128i pretty(long long b) { return (__m128i){b,b}; }

__m128i wrap(long long b) {
    asm ("mov qword ptr [rsp-0x10], rdi\n"
         "vmovddup xmm0, qword ptr [rsp-0x10]\n"
         :
         : "r"(b)
         );
}

extern "C" __m128i pure(long long b);
asm (".text\n.global pure\n\t.type pure, @function\n"
     "pure:\n\t"
     "mov qword ptr [rsp-0x10], rdi\n\t"
     "vmovddup xmm0, qword ptr [rsp-0x10]\n\t"
     "ret\n\t"
     );

__m128i add1(__m128i in, long long in2) { return in + pretty(in2);}
__m128i add2(__m128i in, long long in2) { return in + wrap(in2);}
__m128i add3(__m128i in, long long in2) { return in + pure(in2);}

g++ -c so.cpp -march=native -masm=intel -O3 -fno-inline 编译并用 objdump -d -M intel so.o | c++filt 反汇编 .

so.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <pure>:
   0:   48 89 7c 24 f0          mov    QWORD PTR [rsp-0x10],rdi
   5:   c5 fb 12 44 24 f0       vmovddup xmm0,QWORD PTR [rsp-0x10]
   b:   c3                      ret
   c:   0f 1f 40 00             nop    DWORD PTR [rax+0x0]

0000000000000010 <pretty(long long)>:
  10:   48 89 7c 24 f0          mov    QWORD PTR [rsp-0x10],rdi
  15:   c5 fb 12 44 24 f0       vmovddup xmm0,QWORD PTR [rsp-0x10]
  1b:   c3                      ret
  1c:   0f 1f 40 00             nop    DWORD PTR [rax+0x0]

0000000000000020 <wrap(long long)>:
  20:   48 89 7c 24 f0          mov    QWORD PTR [rsp-0x10],rdi
  25:   c5 fb 12 44 24 f0       vmovddup xmm0,QWORD PTR [rsp-0x10]
  2b:   c3                      ret
  2c:   0f 1f 40 00             nop    DWORD PTR [rax+0x0]

0000000000000030 <add1(long long __vector(2), long long)>:
  30:   c5 f8 28 c8             vmovaps xmm1,xmm0
  34:   48 83 ec 08             sub    rsp,0x8
  38:   e8 00 00 00 00          call   3d <add1(long long __vector(2), long long)+0xd>
  3d:   48 83 c4 08             add    rsp,0x8
  41:   c5 f9 d4 c1             vpaddq xmm0,xmm0,xmm1
  45:   c3                      ret
  46:   66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
  4d:   00 00 00

0000000000000050 <add2(long long __vector(2), long long)>:
  50:   c5 f8 28 c8             vmovaps xmm1,xmm0
  54:   48 83 ec 08             sub    rsp,0x8
  58:   e8 00 00 00 00          call   5d <add2(long long __vector(2), long long)+0xd>
  5d:   48 83 c4 08             add    rsp,0x8
  61:   c5 f9 d4 c1             vpaddq xmm0,xmm0,xmm1
  65:   c3                      ret
  66:   66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
  6d:   00 00 00

0000000000000070 <add3(long long __vector(2), long long)>:
  70:   48 83 ec 18             sub    rsp,0x18
  74:   c5 f8 29 04 24          vmovaps XMMWORD PTR [rsp],xmm0
  79:   e8 00 00 00 00          call   7e <add3(long long __vector(2), long long)+0xe>
  7e:   c5 f9 d4 04 24          vpaddq xmm0,xmm0,XMMWORD PTR [rsp]
  83:   48 83 c4 18             add    rsp,0x18
  87:   c3                      ret

1 回答

  • 2

    GCC不了解汇编语言 .

    由于 pure 是外部函数,因此无法确定它所改变的寄存器,因此根据ABI必须假设所有 xmm 寄存器都已更改 .

    wrap 具有未定义的行为,因为 asm 语句clobbers xmm0[rsp-0x10] 未列为clobbers或输出(对于可能依赖于 b 或可能不依赖于 b 的值),并且该函数没有 return 语句 .

    编辑:ABI不适用于内联汇编,如果从命令行中删除 -fno-inline ,我希望您的程序不起作用 .

相关问题