Yanyg - Software Engineer

X86_64参数传递

目录

1 从一个问题引入

如下不正确调用的输出是什么?

int main(int argc, char *argv[])
{
  printf("%d\n");
  return 0;
}

不给printf提供更多参数, 如何稳定的输出100 ?

int main(int argc, char *argv[])
{
  __asm__ volatile("movq $100, %rsi");
  printf("%d\n");
  return 0;
}

2 寄存器规范

常用寄存器37个, 21个通用寄存器, 16个浮点寄存器.

2.1 通用寄存器

2.1.1 函数参数传递

整型参数入参6个, rdi, rsi, rdx, rcx, r8, r9. 超过6个入参, 压入堆栈.

写了一个9个参数的demo, 输出如下:

[yanyg@x1{192.168.1.116} ~/test ]
$ ./a.out
 rdi : index=1, value=1
 rsi : index=2, value=2
 rdx : index=3, value=3
 rcx : index=4, value=4
  r8 : index=5, value=5
  r9 : index=6, value=6
sta0 : index=0, value=7
sta1 : index=1, value=8
sta2 : index=2, value=9

demo代码如下, 为了使汇编能工作, 需要设置优化级别为0. gcc -Wall -O0 demo.c

#include <stdarg.h>
#include <stdio.h>

#define GetRegValueByName(reg)                                  \
    ({                                                          \
        long ret;                                               \
        __asm__ volatile("movq %%" # reg ", %0" : "=m"(ret));   \
        ret;                                                    \
    })

#define GetStackValueByOffset(offset)                           \
    ({                                                          \
        long ret;                                               \
        __asm__ volatile("movq " #offset "(%rbp), %rax");       \
        __asm__ volatile("movq %%rax, %0" : "=m"(ret));         \
        ret;                                                    \
    })

int get_gp_index(long reg, long v1, long v2, long v3, long v4, long v5, long v6)
{
    if (reg == v1)
    {
        return 1;
    }
    if (reg == v2)
    {
        return 2;
    }
    if (reg == v3)
    {
        return 3;
    }
    if (reg == v4)
    {
        return 4;
    }
    if (reg == v5)
    {
        return 5;
    }
    if (reg == v6)
    {
        return 6;
    }
    return 0;
}

#define PRINT_REG(reg)                                                  \
    printf("%4s : index=%d, value=%ld\n",                               \
           #reg, get_gp_index(reg, v1, v2, v3, v4, v5, v6), reg);

#define PRINT_STACK(stackIdx)                                           \
    printf("sta%d : index=%d, value=%ld\n",                             \
           stackIdx, stackIdx, stack ## stackIdx);

void print_gp_registers(long v1, long v2, long v3, long v4, long v5, long v6,
                        long v7, long v8, long v9)
{
    long rsi = GetRegValueByName(rsi);
    long rdi = GetRegValueByName(rdi);
    long rdx = GetRegValueByName(rdx);
    long rcx = GetRegValueByName(rcx);
    long r8 = GetRegValueByName(r8);
    long r9 = GetRegValueByName(r9);
    // call + pushq rbp = 16 bytes
    long stack0 = GetStackValueByOffset(16);
    long stack1 = GetStackValueByOffset(24);
    long stack2 = GetStackValueByOffset(32);
    PRINT_REG(rdi);
    PRINT_REG(rsi);
    PRINT_REG(rdx);
    PRINT_REG(rcx);
    PRINT_REG(r8);
    PRINT_REG(r9);
    PRINT_STACK(0);
    PRINT_STACK(1);
    PRINT_STACK(2);
}

int main(int argc, char *argv[])
{
    print_gp_registers(1, 2, 3, 4, 5, 6, 7, 8, 9);
    return 0;
}

优化为0时的部分关联汇编如下:

print_gp_registers:
        pushq   %rbp
        movq    %rsp, %rbp
        ...

main:
        pushq   $9
        pushq   $8
        pushq   $7
        movl    $6, %r9d
        movl    $5, %r8d
        movl    $4, %ecx
        movl    $3, %edx
        movl    $2, %esi
        movl    $1, %edi
        call    print_gp_registers
        ...

优化等级为2时的部分关联汇编如下, 可以看出rbp的数值有所差异. 我所在平台上, 优化等级为2 运行会core, core位置是第一次从栈取数据的位置.

print_gp_registers:
        pushq   %r15
        movq    %rcx, %rax
        movq    %rdx, %r15
        pushq   %r14
        ...

main:
.LFB13:
        movl    $6, %r9d
        movl    $5, %r8d
        movl    $4, %ecx
        pushq   $9
        movl    $3, %edx
        movl    $2, %esi
        movl    $1, %edi
        pushq   $8
        pushq   $7
        call    print_gp_registers
        ...

2.1.2 浮点寄存器

8个浮点寄存器: xmm0~xmm7. 当浮点参数和整型参数混杂时, 各自独立计算参数位置. 例如, 参数1为double, 参数2为long, 则xmm0保存参数1, rdi保存参数2.

2.1.3 使用者需要保存的寄存器

rbx, r12~r15.

2.1.4 特殊寄存器

rbp, rsp, rip.