cha*_*255 5 c assembly gcc x86-64
为了学习汇编,我正在查看GCC使用-S命令为一些简单的c程序生成的汇编.我有一个add函数,它接受一些int和一些char并将它们加在一起.我只是想知道为什么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
Run Code Online (Sandbox Code Playgroud)
#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);
}
Run Code Online (Sandbox Code Playgroud)
就是这样,因为x86-64 SystemV ABI需要它.
请参阅https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-r252.pdf以获取当前版本规范的副本.另请参阅x86 标签wiki以获取ABI的链接(以及更多好东西.)
参见abi PDF的第17页:
分类每个参数的大小最多为八字节.(脚注:因此堆栈将始终是八字节对齐).
进一步(第16页:堆栈框架):
输入参数区域的末尾应在16(32,如果
__m256在栈上传递)字节边界上对齐 .换句话说,%rsp + 8当控制转移到函数入口点时,value()总是16(32)的倍数.
如果他们设计了它,那么不同的整数类型在堆栈上有不同的宽度,但是8字节类型仍然总是8字节对齐,关于填充的位置会有复杂的规则(因此被调用的函数找到它的位置) args)取决于当前和先前args的类型.这意味着像printf这样的可变函数需要一个不包含args的不同调用约定.
8位推送根本不可编码.只有16位(带0x66前缀)或64位(无前缀或REX.W=1)可用.英特尔手册对此有点混淆,暗示在push r3264位模式下可编码的文本(可能是REX.W = 0),但情况并非如此:请参阅
push指令推送到堆栈的字节数什么时候我没有指定操作数大小?.
将值压入堆栈时,压入必须始终基于系统的字大小。如果您像我一样是个老用户,那就是 16 位(尽管我确实有一些 12 位字大小的系统!),但它确实取决于系统。
既然您谈论的是 X86_64,那么您将谈论的是 64 位字。我的理解是,字大小通常与寻址系统 RAM 上的任何值所需的最小字节数有关。由于您有 64 位内存空间,因此需要 64 位(或 8 个字节,基于原始 16 位字大小的“四字”)。
| 归档时间: |
|
| 查看次数: |
424 次 |
| 最近记录: |