C语言函数调用的底层实现

最近在阅读大名鼎鼎的《深入理解计算机系统》,读到第三章,介绍了函数的底层实现。下面来听我娓娓道来。

为了理解,我就用书上的例子,如果在中途有新的术语,我会就近解释。

1. 背景

全文将会围绕下面两个函数来介绍所有的实现机制,这两个函数是:

第一个,主调用函数(它去调用另外一个函数 proc)

long call_proc()
{
        long  x1 = 1; int  x2 = 2;
        short x3 = 3; char x4 = 4;
        proc(x1, &x1, x2, &x2, x3, &x3, x4, &x4);
        return (x1+x2)*(x3-x4);
}

第二个,被调用函数 (它接受其他函数的调用)

void proc(long  a1, long  *a1p,
          int   a2, int   *a2p,
          short a3, short *a3p,
          char  a4, char  *a4p)
{
        *a1p += a1;
        *a2p += a2;
        *a3p += a3;
        *a4p += a4;
}

将这个函数分别 设置保存为两个文件,例如以函数名为文件名,proc.c 和 call_proc.c。 用gcc自带的汇编功能将两个文件汇编成汇编文件。例如:

gcc -Og -S call_proc.c

对这两个C文件汇编,将得到两个以 .s 为后缀的汇编文件。如,call_proc.s 和 proc.s 。

2. 汇编文件介绍

下面,将通过介绍上面两个汇编文件来了解底层对函数调用的支持。

按照顺序,先来看看主调用函数 call_proc.s 的内容

	.file	"p171_call_proc.c"
	.text
	.globl	call_proc
	.type	call_proc, @function
call_proc:
.LFB0:
	.cfi_startproc
	subq	$40, %rsp
	.cfi_def_cfa_offset 48
	movq	%fs:40, %rax
	movq	%rax, 24(%rsp)
	xorl	%eax, %eax
	movq	$1, 16(%rsp)
	movl	$2, 12(%rsp)
	movw	$3, 10(%rsp)
	movb	$4, 9(%rsp)
	leaq	9(%rsp), %rax
	pushq	%rax
	.cfi_def_cfa_offset 56
	pushq	$4
	.cfi_def_cfa_offset 64
	leaq	26(%rsp), %r9
	movl	$3, %r8d
	leaq	28(%rsp), %rcx
	movl	$2, %edx
	leaq	32(%rsp), %rsi
	movl	$1, %edi
	movl	$0, %eax
	call	proc
	movslq	28(%rsp), %rax
	addq	32(%rsp), %rax
	movq	%rax, %rcx
	movswl	26(%rsp), %edx
	movsbl	25(%rsp), %eax
	subl	%eax, %edx
	movslq	%edx, %rax
	imulq	%rcx, %rax
	addq	$16, %rsp
	.cfi_def_cfa_offset 48
	movq	24(%rsp), %rdi
	xorq	%fs:40, %rdi
	je	.L2
	call	__stack_chk_fail
.L2:
	addq	$40, %rsp
	.cfi_def_cfa_offset 8
	ret
	.cfi_endproc
.LFE0:
	.size	call_proc, .-call_proc
	.ident	"GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609"
	.section	.note.GNU-stack,"",@progbits

猜你喜欢

转载自blog.csdn.net/tuijiangmeng87/article/details/87900557
今日推荐