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