OpenEuler中C语言中的函数调用测试

1. 在X86_64架构下实践2.4中的内容

main.c测试

main.c测试代码

#include <stdio.h>

int sub(int x,int y)
{
    int u,v;
    u = 4;v = 5;
    return x+y+u+v;
}

int main()
{
    int a,b,c;
    a = 1;b = 2;c = 3;
    c = sub(a,b);
    printf("c = %d\n",c);
}

运行截图:

测试代码汇编

	.file	"main.c"
	.text
	.globl	sub
	.type	sub, @function
sub:
.LFB0:
	.cfi_startproc
	pushq	%rbp	//把main函数的ebp放入栈顶
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp	/ebp指向新的栈帧
	.cfi_def_cfa_register 6
	movl	%edi, -20(%rbp)	//入参
	movl	%esi, -24(%rbp)	//入参
	movl	$4, -4(%rbp)	//栈内变量u = 4
	movl	$5, -8(%rbp)	//栈内变量v = 5
	movl	-20(%rbp), %edx	//rbp向上读取a = 1 
	movl	-24(%rbp), %eax	//rbp向上读取b = 2
	addl	%eax, %edx		//计算a+b+u+v
	movl	-4(%rbp), %eax
	addl	%eax, %edx
	movl	-8(%rbp), %eax
	addl	%edx, %eax
	popq	%rbp			//弹出%rbp
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	sub, .-sub
	.section	.rodata
.LC0:
	.string	"c = %d\n"
	.text
	.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
	subq	$16, %rsp
	movl	$1, -4(%rbp)	//变量a = 1
	movl	$2, -8(%rbp)	//变量b = 2
	movl	$3, -12(%rbp)	//变量c = 3
	movl	-8(%rbp), %edx	//把参数b放入栈顶
	movl	-4(%rbp), %eax	//把参数a放入栈顶
	movl	%edx, %esi
	movl	%eax, %edi
	call	sub				//调用sub
	movl	%eax, -12(%rbp)
	movl	-12(%rbp), %eax	//返回值赋给c
	movl	%eax, %esi
	movl	$.LC0, %edi
	movl	$0, %eax
	call	printf			//打印
	movl	$0, %eax
	leave					//函数结束,返回
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE1:
	.size	main, .-main
	.ident	"GCC: (Uos 8.3.0.3-3+rebuild) 8.3.0"
	.section	.note.GNU-stack,"",@progbits

函数栈变化流程

一,局部变量分配

二,准备调用函数sub

当前PC会被推入栈中,随后用sub的入口地址替换PC,这样下一条指令就会跳到sub函数。

三,现场保护以及局部变量分配

继续进行现场保护工作,保存main函数的ebp。之后ebp可以指向为sub分配的栈帧了,再为sub分配局部变量空间16个字节,创建两个变量。并为这两个变量赋值

四,表达式的计算

sub执行x+y+u+v,对表达式进行求值,将结果存入返回寄存器%eax

五,准备返回main函数的下一条指令

先让esp指向当前栈帧的底部ebp,然后pop出ebp回复main的栈帧,pop出EIP回复main的代码指针,即把ebp所指的被调用函数的栈底作为新的栈顶,把被调用函数的栈底弹出,esp指向返回地址。ret是将esp所指栈顶地址中的内容赋值给PC,接下来将执行main函数的下一条指令。

六,返回到main函数下一条指令,将返回值赋给c,并打印

七,main函数结束,执行leave,ret返回

总结流程图

longjump.c测试

测试代码

#include <stdio.h>
#include <setjmp.h>
jmp_buf env;

int main()
{
    int r,a=100;
    printf("call setjmp to save environment\n");
    if ((r = setjmp(env)) == 0)
    {
        A();
        printf("normal return\n");
    }
    else
        printf("back to main() via long jump, r = %d a = %d\n",r,a);
}

int A()
{
    printf("enter A()\n");
    B();
    printf("exit A()\n");
}

int B()
{
    printf("enter B()\n");
    printf("long jump? (y|n) ");
    if(getchar()=='y')
        longjmp(env,1234);
    printf("exit B()\n");
}

运行截图:

汇编代码

	.file	"longjump.c"
	.text
	.comm	env,156,32
	.section	.rodata
	.align 4
.LC0:
	.string	"call setjmp to save environment"
.LC1:
	.string	"normal return"
	.align 4
.LC2:
	.string	"back to main() via long jump, r = %d a = %d\n"
	.text
	.globl	main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	leal	4(%esp), %ecx
	.cfi_def_cfa 1, 0
	andl	$-16, %esp
	pushl	-4(%ecx)
	pushl	%ebp
	.cfi_escape 0x10,0x5,0x2,0x75,0
	movl	%esp, %ebp
	pushl	%ecx
	.cfi_escape 0xf,0x3,0x75,0x7c,0x6
	subl	$20, %esp
	movl	$100, -12(%ebp)
	subl	$12, %esp
	pushl	$.LC0
	call	puts
	addl	$16, %esp
	subl	$12, %esp
	pushl	$env
	call	_setjmp
	addl	$16, %esp
	movl	%eax, -16(%ebp)
	cmpl	$0, -16(%ebp)
	jne	.L3
	call	A
	subl	$12, %esp
	pushl	$.LC1
	call	puts
	addl	$16, %esp
	jmp	.L4
.L3:
	subl	$4, %esp
	pushl	-12(%ebp)
	pushl	-16(%ebp)
	pushl	$.LC2
	call	printf
	addl	$16, %esp
.L4:
	movl	$0, %eax
	movl	-4(%ebp), %ecx
	.cfi_def_cfa 1, 0
	leave
	.cfi_restore 5
	leal	-4(%ecx), %esp
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.section	.rodata
.LC3:
	.string	"enter A()"
.LC4:
	.string	"exit A()"
	.text
	.globl	A
	.type	A, @function
A:
.LFB1:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	subl	$8, %esp
	subl	$12, %esp
	pushl	$.LC3
	call	puts
	addl	$16, %esp
	call	B
	subl	$12, %esp
	pushl	$.LC4
	call	puts
	addl	$16, %esp
	nop
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
.LFE1:
	.size	A, .-A
	.section	.rodata
.LC5:
	.string	"enter B()"
.LC6:
	.string	"long jump? (y|n) "
.LC7:
	.string	"exit B()"
	.text
	.globl	B
	.type	B, @function
B:
.LFB2:
	.cfi_startproc
	pushl	%ebp
	.cfi_def_cfa_offset 8
	.cfi_offset 5, -8
	movl	%esp, %ebp
	.cfi_def_cfa_register 5
	subl	$8, %esp
	subl	$12, %esp
	pushl	$.LC5
	call	puts
	addl	$16, %esp
	subl	$12, %esp
	pushl	$.LC6
	call	printf
	addl	$16, %esp
	call	getchar
	cmpl	$121, %eax
	jne	.L8
	subl	$8, %esp
	pushl	$1234
	pushl	$env
	call	longjmp
.L8:
	subl	$12, %esp
	pushl	$.LC7
	call	puts
	addl	$16, %esp
	nop
	leave
	.cfi_restore 5
	.cfi_def_cfa 4, 4
	ret
	.cfi_endproc
.LFE2:
	.size	B, .-B
	.ident	"GCC: (Uos 8.3.0.3-3+rebuild) 8.3.0"
	.section	.note.GNU-stack,"",@progbits

函数流程:

1,进入main函数

2,打印“call setjmp to save environment”

3,调用setjmp函数并对返回值进行判断

4,调用A函数

5,打印“enter A()”

调用B函数

6,打印“enter B()”

7,打印“longjump?”

8,对输入进行判断

9,调用longjump函数,函数栈指针回退到之前保存的状态,即r = setjmp(env)) == 0

所以最终输出为:back to main() via long jump, r = 1234 a = 100

函数具体运行参考图

2.在arm64架构下的openeuler实践2.4内容

main.c测试

运行截图:main.c

在arm64架构下的汇编代码:main.c

        .arch armv8-a
        .file   "main.c"
        .text
        .section        .rodata
        .align  3
.LC0:
        .string "c = %d\n"
        .text
        .align  2
        .global main
        .type   main, %function
main:
.LFB0:
        .cfi_startproc
        stp     x29, x30, [sp, -32]!
        .cfi_def_cfa_offset 32
        .cfi_offset 29, -32
        .cfi_offset 30, -24
        mov     x29, sp
        mov     w0, 1
        str     w0, [sp, 28]
        mov     w0, 2
        str     w0, [sp, 24]
        mov     w0, 3
        str     w0, [sp, 20]
        ldr     w1, [sp, 24]
        ldr     w0, [sp, 28]
        bl      sub
        str     w0, [sp, 20]
        ldr     w1, [sp, 20]
        adrp    x0, .LC0
        add     x0, x0, :lo12:.LC0
        bl      printf
        mov     w0, 0
        ldp     x29, x30, [sp], 32
        .cfi_restore 30
        .cfi_restore 29
        .cfi_def_cfa_offset 0
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .align  2
        .global sub
        .type   sub, %function
sub:
.LFB1:
        .cfi_startproc
        sub     sp, sp, #32
        .cfi_def_cfa_offset 32
        str     w0, [sp, 12]
        str     w1, [sp, 8]
        mov     w0, 4
        str     w0, [sp, 28]
        mov     w0, 5
        str     w0, [sp, 24]
        ldr     w1, [sp, 12]
        ldr     w0, [sp, 8]
        add     w1, w1, w0
        ldr     w0, [sp, 28]
        add     w1, w1, w0
        ldr     w0, [sp, 24]
        add     w0, w1, w0
        add     sp, sp, 32
        .cfi_def_cfa_offset 0
        ret
        .cfi_endproc
.LFE1:
        .size   sub, .-sub
        .ident  "GCC: (GNU) 10.3.1"
        .section        .note.GNU-stack,"",@progbits

main.c程序逻辑框图

longjump测试

在arm64架构下的openeuler运行截图:longjump.c

在arm64架构下的汇编代码:longjump.c

        .arch armv8-a
        .file   "longjump.c"
        .text
        .global env
        .bss
        .align  3
        .type   env, %object
        .size   env, 312
env:
        .zero   312
        .section        .rodata
        .align  3
.LC0:
        .string "call setjmp to save environment"
        .align  3
.LC1:
        .string "normal return"
        .align  3
.LC2:
        .string "back to main() via long jump, r = %d a = %d\n"
        .text
        .align  2
        .global main
        .type   main, %function
main:
.LFB0:
        .cfi_startproc
        stp     x29, x30, [sp, -32]!
        .cfi_def_cfa_offset 32
        .cfi_offset 29, -32
        .cfi_offset 30, -24
        mov     x29, sp
        mov     w0, 100
        str     w0, [sp, 28]
        adrp    x0, .LC0
        add     x0, x0, :lo12:.LC0
        bl      puts
        adrp    x0, env
        add     x0, x0, :lo12:env
        bl      _setjmp
        str     w0, [sp, 24]
        ldr     w0, [sp, 24]
        cmp     w0, 0
        bne     .L3
        bl      A
        adrp    x0, .LC1
        add     x0, x0, :lo12:.LC1
        bl      puts
        b       .L4
.L3:
        ldr     w2, [sp, 28]
        ldr     w1, [sp, 24]
        adrp    x0, .LC2
        add     x0, x0, :lo12:.LC2
        bl      printf
.L4:
        mov     w0, 0
        ldp     x29, x30, [sp], 32
        .cfi_restore 30
        .cfi_restore 29
        .cfi_def_cfa_offset 0
        ret
        .cfi_endproc
.LFE0:
        .size   main, .-main
        .section        .rodata
        .align  3
.LC3:
        .string "enter A()"
        .align  3
.LC4:
        .string "exit A()"
        .text
        .align  2
        .global A
        .type   A, %function
A:
.LFB1:
        .cfi_startproc
        stp     x29, x30, [sp, -16]!
        .cfi_def_cfa_offset 16
        .cfi_offset 29, -16
        .cfi_offset 30, -8
        mov     x29, sp
        adrp    x0, .LC3
        add     x0, x0, :lo12:.LC3
        bl      puts
        bl      B
        adrp    x0, .LC4
        add     x0, x0, :lo12:.LC4
        bl      puts
        nop
        ldp     x29, x30, [sp], 16
        .cfi_restore 30
        .cfi_restore 29
        .cfi_def_cfa_offset 0
        ret
        .cfi_endproc
.LFE1:
        .size   A, .-A
        .section        .rodata
        .align  3
.LC5:
        .string "enter B()"
        .align  3
.LC6:
        .string "long jump? (y|n) "
        .align  3
.LC7:
        .string "exit B()"
        .text
        .align  2
        .global B
        .type   B, %function
B:
.LFB2:
        .cfi_startproc
        stp     x29, x30, [sp, -16]!
        .cfi_def_cfa_offset 16
        .cfi_offset 29, -16
        .cfi_offset 30, -8
        mov     x29, sp
        adrp    x0, .LC5
        add     x0, x0, :lo12:.LC5
        bl      puts
        adrp    x0, .LC6
        add     x0, x0, :lo12:.LC6
        bl      printf
        bl      getchar
        cmp     w0, 121
        bne     .L8
        mov     w1, 1234
        adrp    x0, env
        add     x0, x0, :lo12:env
        bl      longjmp
.L8:
        adrp    x0, .LC7
        add     x0, x0, :lo12:.LC7
        bl      puts
        nop
        ldp     x29, x30, [sp], 16
        .cfi_restore 30
        .cfi_restore 29
        .cfi_def_cfa_offset 0
        ret
        .cfi_endproc
.LFE2:
        .size   B, .-B
        .ident  "GCC: (GNU) 10.3.1"
        .section        .note.GNU-stack,"",@progbits

longjump程序逻辑框图

posted @ 2021-12-05 11:15  Bzrael  阅读(82)  评论(0编辑  收藏  举报