Operation requirements
- On x86_ Contents in practice 2.4 under 64 architecture
- Check the contents of the register through GDB and fill in the specific values in the figure in the textbook
- The C code of 2.4 is practiced again in OpenEuler, and the logic block diagram of ARM64 is drawn
- 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.