为什么eax包含许多矢量参数?

时间:2018-07-23 23:55:41

标签: assembly x86-64 calling-convention abi sysv

为什么在汇编中al包含向量参数的数量?

为什么被调用方的矢量参数与常规参数有什么不同?

1 个答案:

答案 0 :(得分:5)

该值用于ABI文档中所述的优化

  

序言应使用%rax以避免不必要地保存XMM寄存器。这对于仅整数程序以防止XMM单元初始化特别重要。

     

https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf

调用va_start时,它将把寄存器中传递的所有参数保存到寄存器保存区域

  

首先,任何已知要使用va_start的函数都必须在该函数的开始处将所有可能用于将参数传递到堆栈的寄存器保存到“寄存器保存区域”中”,以供va_startva_arg将来访问。这是显而易见的一步,我相信在任何具有寄存器调用约定的平台上,它都是非常标准的。寄存器另存为整数寄存器,后跟浮点寄存器...

但是保存所有8个向量寄存器可能会很慢,因此编译器可能会选择使用al中传递的值对其进行优化

  

...作为一种优化,在函数调用期间,需要%rax来保存用于保存参数的SSE寄存器的数量,以允许varargs调用程序完全避免触摸FPU(如果没有)浮点参数。

     

https://blog.nelhage.com/2010/10/amd64-and-va_arg/

由于您要至少保存使用的寄存器,因此该值可以大于实际使用的寄存器数。这就是为什么ABI中有此行

  

%al的内容不必与寄存器的数量完全匹配,但必须是所使用的矢量寄存器的数量的上限,且范围为0-8。

您可以从prolog of ICC

看到效果
    sub       rsp, 216                                      #5.1
    mov       QWORD PTR [8+rsp], rsi                        #5.1
    mov       QWORD PTR [16+rsp], rdx                       #5.1
    mov       QWORD PTR [24+rsp], rcx                       #5.1
    mov       QWORD PTR [32+rsp], r8                        #5.1
    mov       QWORD PTR [40+rsp], r9                        #5.1
    movzx     r11d, al                                      #5.1
    lea       rax, QWORD PTR [r11*4]                        #5.1
    lea       r11, QWORD PTR ..___tag_value_varstrings(int, ...).6[rip] #5.1
    sub       r11, rax                                      #5.1
    lea       rax, QWORD PTR [175+rsp]                      #5.1
    jmp       r11                                           #5.1
    movaps    XMMWORD PTR [-15+rax], xmm7                   #5.1
    movaps    XMMWORD PTR [-31+rax], xmm6                   #5.1
    movaps    XMMWORD PTR [-47+rax], xmm5                   #5.1
    movaps    XMMWORD PTR [-63+rax], xmm4                   #5.1
    movaps    XMMWORD PTR [-79+rax], xmm3                   #5.1
    movaps    XMMWORD PTR [-95+rax], xmm2                   #5.1
    movaps    XMMWORD PTR [-111+rax], xmm1                  #5.1
    movaps    XMMWORD PTR [-127+rax], xmm0                  #5.1
..___tag_value_varstrings(int, ...).6: 

它本质上是Duff's device。在{x1保存}指令之后,将向r11寄存器加载地址,然后从结果中减去al*4(因为movaps XMMWORD PTR [rax-X], xmmX为4字节长)以跳转到{{1} }我们应该运行的指令

如我所见,其他编译器总是保存所有向量寄存器,或者根本不保存它们,因此它们不在乎movaps的值,而只是检查它是否为零

始终保存通用寄存器,这可能是因为将6个寄存器移至内存而不是花时间进行条件检查,地址计算和跳转会更便宜。结果,您不需要为寄存器中传递多少个整数的参数

这里是similar question to yours。您可以在以下链接中找到更多信息