为什么gcc将8字节格式的char类型传递给函数汇编

问题描述 投票:0回答:2

为了学习汇编,我正在查看 GCC 使用 -S 命令为一些简单的 c 程序生成的汇编。我有一个 add 函数,它接受一些整数和一些字符并将它们添加在一起。我只是想知道为什么 char 参数会以 8 个字节的形式压入堆栈(pushq)?为什么不只推送一个字节?

    .file   "test.c"
    .text
    .globl  add
    .type   add, @function
add:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    %edi, -4(%rbp)
    movl    %esi, -8(%rbp)
    movl    %edx, -12(%rbp)
    movl    %ecx, -16(%rbp)
    movl    %r8d, -20(%rbp)
    movl    %r9d, -24(%rbp)
    movl    16(%rbp), %ecx
    movl    24(%rbp), %edx
    movl    32(%rbp), %eax
    movb    %cl, -28(%rbp)
    movb    %dl, -32(%rbp)
    movb    %al, -36(%rbp)
    movl    -4(%rbp), %edx
    movl    -8(%rbp), %eax
    addl    %eax, %edx
    movl    -12(%rbp), %eax
    addl    %eax, %edx
    movl    -16(%rbp), %eax
    addl    %eax, %edx
    movl    -20(%rbp), %eax
    addl    %eax, %edx
    movl    -24(%rbp), %eax
    addl    %eax, %edx
    movsbl  -28(%rbp), %eax
    addl    %eax, %edx
    movsbl  -32(%rbp), %eax
    addl    %eax, %edx
    movsbl  -36(%rbp), %eax
    addl    %edx, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   add, .-add
    .globl  main
    .type   main, @function
main:
.LFB1:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    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    add
    addq    $24, %rsp
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.9.2-10ubuntu13) 4.9.2"
    .section    .note.GNU-stack,"",@progbits
#include <stdio.h>

int add(int a, int b, int c, int d, int e, int f, char g, char h, char i)
{
    return a + b + c + d + e + f + g + h + i;
}

int main()
{
    return add(1, 2, 3, 4, 5, 6, 7, 8, 9);
}
c assembly gcc x86-64 calling-convention
2个回答
10
投票

就像这样,因为 x86-64 SystemV ABI 需要它。

请参阅 https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-r252.pdf 以获取当前版本规范的副本。另请参阅 tag wiki,获取 ABI 的链接(以及更多好东西。)

参见abi PDF第17页:

分类 每个参数的大小四舍五入为八字节。 (脚注:因此堆栈将始终是八字节对齐的)。

进一步(第 16 页:堆栈框架):

输入参数区域的末尾应对齐在 16(32,如果

__m256
在堆栈)字节边界上传递。换句话说,值 当控制为 16 (32) 时 (
%rsp + 8
) 始终为 转移到函数入口点。

如果他们将其设计为不同的整数类型在堆栈上具有不同的宽度,但 8 字节类型仍然始终是 8 字节对齐,那么关于填充的位置就会有复杂的规则(以及被调用函数在哪里找到)它的参数)取决于当前和先前参数的类型。这意味着像 printf 这样的可变参数函数将需要一个不打包参数的不同调用约定。


8 位推送根本不可编码。仅 16 位(带

0x66
前缀)或 64 位(无前缀或
REX.W=1
)可用。英特尔手册对此有点令人困惑,在文本中暗示
push r32
可以在 64 位模式下进行编码(可能 REX.W=0),但事实并非如此:参见 当我不指定操作数大小时,push指令会压入多少字节?.


3
投票

既然您谈论的是 X86_64,那么您将谈论的是 64 位字。我的理解是,字大小通常与寻址系统 RAM 上的任何值所需的最小字节数有关。由于您有 64 位内存空间,因此需要 64 位(或 8 个字节,基于原始 16 位字大小的“四字”)。

© www.soinside.com 2019 - 2024. All rights reserved.