Function call test in C language in OpenEuler (optional)

Operation requirements On x86_ Contents in practice 2.4 under 64 architecture Check the contents of the register throug...
Code and assembly conversion
gdb analysis
Code and assembly conversion
Parameter transfer process analysis
Operation requirements
  1. On x86_ Contents in practice 2.4 under 64 architecture
  2. Check the contents of the register through GDB and fill in the specific values in the figure in the textbook
  3. The C code of 2.4 is practiced again in OpenEuler, and the logic block diagram of ARM64 is drawn
  4. The experimental content can only get the corresponding score after oral defense
Practice flow 1 - in x86_ Under 64 architecture

Code and assembly conversion

According to the textbook, there are differences in parameter transfer between 64 bit and 32 bit. 32-bit transfers parameters directly through the stack, while 64-bit transfers the first six parameters into rdi, rsi, rdx, rcx, r8 and r9 in turn, and then the remaining parameters are passed through the stack like 32-bit. In the 2.5 operation, a segment error occurs when calling printf function directly on 64 bit with 32-bit code. The textbook directly explains here, This difference is the cause.
Example code t.c:

#include <stdio.h> int sub(int a,int b,int c,int d,int e,int f,int g,int h) { int u,v,w; u = 9; v = 10; w = 11; return a+g+u+v; } int main() { int a,b,c,d,e,f,g,h,i; a=1; b=2; c=3; d=4; e=5; f=6; g=7; h=8; i=sub(a,b,c,d,e,f,g,h); }

In x86_ Convert openEuler of 64 to assembly code and view:

t.s:

.file "t.c" .text .globl sub .type sub, @function sub: .LFB0: .cfi_startproc pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movl %edi, -20(%rbp) movl %esi, -24(%rbp) movl %edx, -28(%rbp) movl %ecx, -32(%rbp) movl %r8d, -36(%rbp) movl %r9d, -40(%rbp) movl $9, -4(%rbp) movl $10, -8(%rbp) movl $11, -12(%rbp) movl -20(%rbp), %edx movl 16(%rbp), %eax addl %eax, %edx movl -4(%rbp), %eax addl %eax, %edx movl -8(%rbp), %eax addl %edx, %eax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size sub, .-sub .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 $48, %rsp movl $1, -4(%rbp) movl $2, -8(%rbp) movl $3, -12(%rbp) movl $4, -16(%rbp) movl $5, -20(%rbp) movl $6, -24(%rbp) movl $7, -28(%rbp) movl $8, -32(%rbp) movl -24(%rbp), %r9d movl -20(%rbp), %r8d movl -16(%rbp), %ecx movl -12(%rbp), %edx movl -8(%rbp), %esi movl -4(%rbp), %eax movl -32(%rbp), %edi pushq %rdi movl -28(%rbp), %edi pushq %rdi movl %eax, %edi call sub addq $16, %rsp movl %eax, -36(%rbp) movl $0, %eax leave .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE1: .size main, .-main .ident "GCC: (GNU) 7.3.0" .section .note.GNU-stack,"",@progbits

gdb analysis

Use gcc -g t.s -o t to compile t.s. you can directly debug the assembly code through cgdb t and view it.

Use b main, r to start stepping.

Before the function is executed, it will push its rbp onto the stack.
Use s to step.

The first is the variable definition of the main function. First, esp is reduced by 48 to provide space for a~h.
View the value of the register: use i r to view the value in the corresponding memory, and use x 0x012345678abcdef

Corresponding to the value of ebp in the figure above, view the value of a~h in the stack:

Analyze the stack state after saving the value of main function:

After entering the sub function, the numbers in the six registers are stored on the stack before operation:

However, I see that the code does not restore the two extra parameters (g and h).
In operation, you need to add a, g, u and v.
Where u and v are defined in the sub function, a is passed in through the register, and h is passed through the stack. Through analysis, the value of h is 16(%rbp).
The box in the following figure is the addition part.

The following figure shows the stack analysis diagram:

After the final calculation, restore rbp and return to. The return value exists in rax.

Practice process 2 - under Arm64 architecture

Huawei Kunpeng server is based on Arm64 architecture.

Code and assembly conversion

t.s under arm64 architecture:

.cpu generic+fp+simd .file "t.c" .text .align 2 .global sub .type sub, %function sub: .LFB0: .cfi_startproc sub sp, sp, #48 .cfi_def_cfa_offset 48 str w0, [sp,28] str w1, [sp,24] str w2, [sp,20] str w3, [sp,16] str w4, [sp,12] str w5, [sp,8] str w6, [sp,4] str w7, [sp] mov w0, 9 str w0, [sp,44] mov w0, 10 str w0, [sp,40] mov w0, 11 str w0, [sp,36] ldr w1, [sp,28] ldr w0, [sp,4] add w1, w1, w0 ldr w0, [sp,44] add w1, w1, w0 ldr w0, [sp,40] add w0, w1, w0 add sp, sp, 48 .cfi_def_cfa_offset 0 ret .cfi_endproc .LFE0: .size sub, .-sub .align 2 .global main .type main, %function main: .LFB1: .cfi_startproc stp x29, x30, [sp, -64]! .cfi_def_cfa_offset 64 .cfi_offset 29, -64 .cfi_offset 30, -56 add x29, sp, 0 .cfi_def_cfa_register 29 mov w0, 1 str w0, [x29,60] mov w0, 2 str w0, [x29,56] mov w0, 3 str w0, [x29,52] mov w0, 4 str w0, [x29,48] mov w0, 5 str w0, [x29,44] mov w0, 6 str w0, [x29,40] mov w0, 7 str w0, [x29,36] mov w0, 8 str w0, [x29,32] ldr w0, [x29,60] ldr w1, [x29,56] ldr w2, [x29,52] ldr w3, [x29,48] ldr w4, [x29,44] ldr w5, [x29,40] ldr w6, [x29,36] ldr w7, [x29,32] bl sub str w0, [x29,28] ldp x29, x30, [sp], 64 .cfi_restore 30 .cfi_restore 29 .cfi_def_cfa 31, 0 ret .cfi_endproc .LFE1: .size main, .-main .ident "GCC: (GNU) 4.8.5 20150623 (Red Hat 4.8.5-39)" .section .note.GNU-stack,"",%progbits

Parameter transfer process analysis

In arm: str is storage and ldr is fetch.

In the above figure, save a-h to the corresponding positions of x29,60~x29,32.
Stack and flowchart after analysis:

It can be seen that the function parameter transfer in arm64 in this example is realized through w0-w7.

5 December 2021, 13:51 | Views: 9868

Add new comment

For adding a comment, please log in
or create account

0 comments