Operation requirements
- On X86_64 architecture, submit code and practice screenshots
- Practice the content of 2.5 in OpenEuler again, and submit relevant codes and screenshots
- The experimental content can only get the corresponding score after oral defense
Practice process - in x86_ Implementation under 64 architecture
The computer is x86_64 architecture, first implemented in ubuntu.
1. Compile C code into assembly code
a.c:
#include <stdio.h> extern int B(); int A(int X, int y) { int d,e,f; d = 4; e = 5; f = 6; f = B(d,e); }
Compile as a.s and use cc -m32 -S a.c -o a.s
a.s:
.file "a.c" .text .globl A .type A, @function A: .LFB0: .cfi_startproc endbr32 pushl %ebp .cfi_def_cfa_offset 8 .cfi_offset 5, -8 movl %esp, %ebp .cfi_def_cfa_register 5 pushl %ebx subl $20, %esp .cfi_offset 3, -12 call __x86.get_pc_thunk.ax addl $_GLOBAL_OFFSET_TABLE_, %eax movl $4, -20(%ebp) movl $5, -16(%ebp) movl $6, -12(%ebp) subl $8, %esp pushl -16(%ebp) pushl -20(%ebp) movl %eax, %ebx call B@PLT addl $16, %esp movl %eax, -12(%ebp) nop movl -4(%ebp), %ebx leave .cfi_restore 5 .cfi_restore 3 .cfi_def_cfa 4, 4 ret .cfi_endproc .LFE0: .size A, .-A .section .text.__x86.get_pc_thunk.ax,"axG",@progbits,__x86.get_pc_thunk.ax,comdat .globl __x86.get_pc_thunk.ax .hidden __x86.get_pc_thunk.ax .type __x86.get_pc_thunk.ax, @function __x86.get_pc_thunk.ax: .LFB1: .cfi_startproc movl (%esp), %eax ret .cfi_endproc .LFE1: .ident "GCC: (Ubuntu 9.4.0-1ubuntu1~20.04) 9.4.0" .section .note.GNU-stack,"",@progbits .section .note.gnu.property,"a" .align 4 .long 1f - 0f .long 4f - 1f .long 5 0: .string "GNU" 1: .align 4 .long 0xc0000002 .long 3f - 2f 2: .long 0x3 3: .align 4 4:
2. Implement simple functions in assembly language and call them in C
s.s:
.global get_esp, get_ebp get_esp: movl %esp, %eax ret get_ebp: movl %ebp, %eax ret
s.c:
#include <stdio.h> int main() { int ebp, esp; ebp = get_ebp(); esp = get_esp(); printf("ebp=%8x esp=%8x\n",ebp, esp); }
Mixed compilation of s.s and s.c, mixed compilation of C code and assembly code.
Use GCC - M32 s.s.c - O s. The program prints the values of the current eax and ebp registers.
Screenshot of compilation and operation:
3. Implement mysum() function with assembly code and call it with C
mysum.s:
.text .global mysum, printf #mysum is called and printf is called mysum: # First, the stack frame is established pushl %ebp movl %esp, %ebp # mysum function code movl 8(%ebp), %eax # AX = x addl 12(%ebp), %eax # AX += y movl %ebp, %esp pop %ebp ret
mysum.c:
#include <stdio.h> int main() { int a,b,c; a = 2019; b = 1320; c = mysum(a,b); printf("c=%d\n", c); }
Screenshot of compilation and operation:
Compile using gcc -m32 mysum.s mysum.c -o mysum.
4. Use assembly to call C function
printf.s:
.text .global sub, a, b, printf sub: pushl %ebp movl %esp, %ebp pushl b pushl a pushl $fmt call printf addl $12, %esp movl %ebp, %esp popl %ebp ret .data fmt: .asciz "a=%d,b=%d\n"
printf.c:
#include <stdio.h> int a,b; int main() { a = 13; b = 20; sub(); return 0; }
Screenshot of compilation and operation:
Practice process -- implementation and problem solving under openEuler
Because there is no package in openEuler that supports compiling and running 32-bit code, it can only be implemented under 64 bit. (assembly code needs to be modified)
1. Convert C code into assembly code
2. Implement simple functions in assembly language and call them in C
There are no problems in the above two steps. The 32-bit and 64 bit codes in ubuntu are compatible in openEuler.
3. Implement mysum() function with assembly code and call it with C
In this step, if the source assembly code is not modified, there will be problems during compilation, as shown in the figure:
It was found that there was a problem with push and pop. It's been revised for a long time, but it hasn't been solved. If you try to change it to pushl, there will be errors, segment errors, etc.
Later, I looked at some assembly code compiled in openEuler, such as the code in a.s. It is observed that in 64 bit openEuler, the sp and bp registers used are not esp and ebp, but rsp and rbp.
As shown in the figure:
I modify all ebp and esp in my assembly code to rbp and rsp, and then compile it. The following error is reported:
Originally, the number of bits of rbp and rsp is 64 bits. push and pop (the l suffix is 32 bits) can not be used. push and pop can be put on and out of the stack according to their size.
Modified mysum.s:
.text .global mysum, printf #mysum is called and printf is called mysum: # First, the stack frame is established push %rbp mov %rsp, %rbp # mysum function code movl 8(%rbp), %eax # AX = x addl 12(%rbp), %eax # AX += y mov %rbp, %rsp pop %rbp ret
Finally, it was compiled and run successfully, and there was a problem in the result:
Estimation is also a problem caused by the number of digits.
Through cgdb, I checked the corresponding data storage location in the run, recalculated the difference between the location of a and b in memory and the location of ebp, and then modified the code.
(view the memory address of its value)
The difference is 24 and 28. After modifying the code, the program gets the correct results.
The final mysum.s code is:
.text .global mysum, printf #mysum is called and printf is called mysum: # First, the stack frame is established push %rbp mov %rsp, %rbp # mysum function code mov 24(%rbp), %rax # AX = x add 28(%rbp), %rax # AX += y mov %rbp, %rsp pop %rbp ret
4. Use assembly to call C function
Through the attempt, it is found that only modifying the register to 64 bits can not solve the problem, and the segment error is still prompted. Through cgdb debugging, it is found that it occurs when calling printf.
Write a hello.c and call the printf function to see the principle.
hello.c:
#include <stdio.h> int main() { int a,b; a=13; b=20; printf("a=%d,b=%d\n",a,b); return 0; }
Use gcc -S hello.c -o hello.s to get the assembly code of hello.c. The following is a screenshot of hello.s
It is found that different from the 32-bit in ubuntu, in the 64 bit of openeuler, the parameters of printf function not only exist in the stack, but also in ESI, EDX and EDI respectively.
Modified code:
.text .global sub, a, b, printf sub: push %rbp mov %rsp, %rbp push a push b movl -8(%rbp),%esi movl -16(%rbp),%edx movl $fmt,%edi call printf add $16, %rsp mov %rbp, %rsp pop %rbp ret .data fmt: .asciz "a=%d,b=%d\n"
By modifying the code, the printf parameter in 64 bit is transferred again, and the final output is completed. The results are shown as follows: