Operating system experiment report 2
Experimental content
- Understand x86 assembly language programming environment under Linux;
- Blum's Book: Sample programs in Chapter 04, 05 (Moving Data).
Experimental environment
- Architecture: Intel x86_64 (virtual machine)
- Operating system: Ubuntu 20.04
- Assembler: gas (GNU assembler) in at & T mode
- Compiler: gcc
Technical log
Chapter 04
- Validation experiment CPUID s
The source code of the program is omitted.
1. Build a general executable program:
Execute program commands:
as -o cpuid.o cpuid.s ld -o cpuid cpuid.o ./cpuid
The results are as follows:
The processor Vendor ID is 'GenuineIntel'
Execution screenshot:
2. Assemble with compiler:
Add the following in the original program code:
.globl _start _start:
Replace with:
.globl main
main:
To install a 32-bit gcc Library:
sudo apt-get install libc6-dev-i386
Execute program commands:
gcc cpuid.s -m32 -o cpuid
The results are as follows:
The processor Vendor ID is 'GenuineIntel'
Execution screenshot:
3. Run the program using gdb:
Execute program commands:
as -gstabs -o cpuid.o cpuid.s ld -o cpuid cpuid.o gdb cpuid
The results are as follows:
analysis:
At the beginning, set a breakpoint at the beginning of the program, and then enter run to run. Enter the command next\n\step\s to see the single-step debugging program. Enter cont to run directly and output
The processor Vendor ID is 'GenuineIntel'
Re enter run, enter s to execute cpuid statement step by step, enter info registers, you can see the values in all registers, then enter s to execute to the next statement, enter info registers, you can see the change of the value in the register, you can see that the values of rbx, rcx and rdx are all 0 before cpuid statement is executed, and after cpuid is executed, They contain values derived from the vendor ID string.
print/x $ebx, print/x $edx,print/x $ecx respectively display the values in registers ebx,edx and ecx in hexadecimal form. You can see that the value in register ebx is 0x756e6547, the value in register edx is 0x49656e69, and the value in register ecx is 0x6c65746e.
X / 42cd & output displays the first 42 bytes of variable output in the form of character variables
Summary of gdb basic instructions:
break *_start:Set a breakpoint at the beginning of the program break *end:Set breakpoint at the end of the program run:stay gdb Run startup program in(Stop at breakpoint) step/s/next/n:Single step debugger cont:Keep the program running info registers:Displays the values of all registers print:Displays the value of a register or variable print/d:Displays decimal values print/t:Displays binary values print/x:Displays hexadecimal values x/nyz:Displays the value of a specific memory location,n Is the number of fields to display,y Is the output format,z Is the length of the field to display
- Validation experiment cpuid2 s
Add before the beginning of the program's source code:
.code32
And install the 32-bit libraries required to run the program:
sudo apt-get update sudo apt install lib32z1 lib32ncurses5 g++-multilib libc6-dev-i386
Execute program commands:
as --32 -o cpuid2.o cpuid2.s ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o cpuid2 -lc cpuid2.o ./cpuid2
The results are as follows:
The processor Vendor ID is 'GenuineIntel'
Execution screenshot:
Chapter 05
Define data elements
Data segment: data segment is the most common location to define data elements. The specific memory location used to store the project can be referenced by the program's instruction code, and can be read and modified at will. When defining data in the data segment, it must be included in the executable program because it needs to be initialized with a specific value.
bss segment: data elements defined in the bss segment do not need to declare specific data types, do not need to be initialized, and the memory area is reserved for use at run time and does not need to be included in the final program.
- Validation experiment sizetest1 s
The source code of the program is omitted.
Execute program commands:
as -o sizetest1.o sizetest1.s ld -o sizetest1 sizetest1.o ls -al sizetest1
The results are as follows:
Analysis: the total length of the executable file is 4640 bytes
- Validation experiment sizetest2 s
The source code of the program is omitted.
Execute program commands:
as -o sizetest2.o sizetest2.s ld -o sizetest2 sizetest2.o ls -al sizetest2
The results are as follows:
Analysis: after adding 10000 bytes of buffer in the bss segment declaration, the total length of the executable program file is 4800 bytes, which is only 160 bytes more than the original, indicating that the data declared in the bss segment does not have to be included in the executable program.
- Validation experiment sizetest3 s
The source code of the program is omitted.
Execute program commands:
as -o sizetest3.o sizetest3.s ld -o sizetest3 sizetest3.o ls -al sizetest3
The results are as follows:
[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (IMG goplbdye-1626174832894)( http://stugeek.gitee.io/operating-system/Labwork2-pictures/8.png )]
Analysis: use After adding 10000 bytes of buffer in the data segment declaration of the fill command, the total length of the executable program file is 18880 bytes, an increase of 14240 bytes The fill command makes the assembler automatically create 10000 data elements, which is much larger than the necessary length, indicating that when the data segment defines the data, it must be included in the executable program.
Transfer data element
Basic format of MOV instruction:
movx source, destination
source and destination can be memory addresses, data values stored in memory, data values defined in instruction statements, or registers
- Validation experiment movetest1 s
The source code of the program is omitted.
Execute program commands:
as -gstabs -o movtest1.o movtest1.s ld -o movtest1 movtest1.o gdb -q movtest1
The results are as follows:
Analysis: it can be seen that after the movl value% ecx command is executed, the value 1 stored in the memory is transferred to the ecx register, the value of the ecx register is changed from 0 to 1, and the value in the memory location is transferred to another register
- Validation experiment movetest2 s
The source code of the program is omitted.
Execute program commands:
as -gstabs -o movtest2.o movtest2.s ld -o movtest2 movtest2.o gdb -q movtest2
The results are as follows:
Analysis: at first, check the value in value and find that the initial value is 1. Execute the program step by step until the value in eax register is transferred to the location in value memory. Then check the value in value again and find that the value is 100 and the value in register is transferred to the location in memory
- Validation experiment movetest3 s
The source code of the program is omitted.
Execute program commands:
as --32 -o movtest3.o movtest3.s ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -lc -o movtest3 movtest3.o ./movtest3
The results are as follows:
Analysis: the program traverses the data array specified by the values tag and uses the edi register as the index for traversing the array. After each value is displayed, the value of the edi register is incremented, increasing 5 from 10 to 60 each time
- Validation experiment movetest4 s
The source code of the program is omitted.
Execute program commands:
as -gstabs -o movtest4.o movtest4.s ld -o movtest4 movtest4.o gdb -q movtest4
The results are as follows:
Analysis: at the beginning of the program, first check the value stored in the memory location referenced by the values tag. The first four elements are 10, 15, 20 and 25.
Then run the program step by step and find that the first element is loaded into the eax register from the values array, that is, 10. Now the value in the eax register is 10.
Continue the step-by-step execution. It is found that the memory address referenced by the values tag is loaded into the edi register, and the next instruction transfers 100 to the memory address 4 bytes after the address saved in the edi register. Use register indirect addressing to check and find that 100 is saved to the position of the second element in the values array.
The next instruction loads the second element of the array into the ebx register, using echo $? Command to view the value of the second data array element, also 100.
Conditional transfer instruction
Instruction format:
cmovx source, destination
Where x is a one or two letter code indicating the condition that will trigger the transfer operation, depending on the current value of the EFLAGS register.
- Validation experiment cmovetest s
The source code of the program is omitted.
Execute program commands:
as --32 -gstabs -o cmovtest.o cmovtest.s ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -lc -o cmovtest cmovtest.o ./cmovtest
The results are as follows:
Analysis: register ebx is used to save the maximum integer currently found, and then the array elements are loaded into register eax one by one, and compared with the value in register ebx. If the value in register eax is larger, the value in register eax is used to replace the value in register ebx.
At the beginning of the program, the first value of the array is loaded into register ebx. 105, the second value is loaded into the register eax, 235. Run the cmp and cmova instructions and find that the value in the register ebx becomes a larger 235. Continue the operation until all the numbers of the array are traversed. Finally, the number in the register ebx is the maximum value of the number in the array, 315.
Data exchange instruction
Basic instructions:
XCHG:Exchange their values between two registers or between registers and memory locations BSWAP:Inverts the byte order in a 32-bit register XADD:Swap two values and store their sum in the destination operand CMPXCHG:Compare a value with an external value and exchange it with another value CMPXCHG8B:Compare two 64 bit values and exchange their values
- Validation experiment swaptest s
The source code of the program is omitted.
Execute program commands:
as --gstabs -o swaptest.o swaptest.s ld -o swaptest swaptest.o gdb -q swaptest
The results are as follows:
Analysis: the program stops after the first movl instruction. Check the value in register ebx, which is 0x12345678. After the bswap instruction is executed in one step, the value in register ebx is displayed, which is 0x78563412, which is opposite to the mantissa of the original value.
- Validation experiment cmpxchgtest s
The source code of the program is omitted.
Execute program commands:
as --gstabs -o cmpxchgtest.o cmpxchgtest.s ld -o cmpxchgtest cmpxchgtest.o gdb -q cmpxchgtest
The results are as follows:
Analysis: before executing the cmpxchg instruction, the value in register ebx is 5 and the value in data is 10. After executing the cmpxchg instruction, the value in data becomes 5 and the value in register ebx is transferred to the memory location of data
- Validation experiment cmpxchg8btest s
The source code of the program is omitted.
Execute program commands:
as -gstabs -o cmpxchg8btest.o cmpxchg8btest.s ld -o cmpxchg8btest cmpxchg8btest.o gdb -q cmpxchg8btest
The results are as follows:
Analysis: cmpxchg8b data makes data refer to a memory location. The 8-byte value will be compared with register edx and register eax. If the target value matches the value contained in edx:eax, the 64 bit value in ecx:ebx will be transferred to the target memory location. If not, the value in the address of the target memory location will be loaded into the edx:eax register pair. It can be seen from the output, The value in ecx:ebx was indeed passed to the data target memory location
- Validation experiment bubble s
The source code of the program is omitted.
Execute program commands:
as -gstabs -o bubble.o bubble.s ld -o bubble bubble.o gdb -q bubble
The results are as follows:
Analysis: the program is a bubble sorting algorithm. Before the program runs, the values array is out of order. After the program runs, the values array is sorted in ascending order
Push in data and pop-up data
Simple format of PUSH instruction:
pushx source
Where x represents the length of the data element and source is the data element to be put on the stack
Format of POP instruction:
popx destination
Where x represents the length of the data element and destination is the location where the data is received
- Validation experiment pushpop s
The source code of the program is omitted.
Execute program commands:
as --32 -gstabs -o pushpop.o pushpop.s ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -lc -o pushpop pushpop.o gdb -q pushpop
The results are as follows:
Analysis: before starting the program, the value in register esp is 0xffffd0d0. After all push instructions are executed, the value in register esp is 0xffffd0be. The difference between the starting value and the last value is 18 bytes. The total length of all operation data through push instructions is also 18 bytes, indicating that register esp will decrease during push operation and point to the new starting position of the stack.
Problems encountered
1. At first, when running CPUID with gcc S, an error occurs:
The reason is that the gcc library is 64 bit and cannot compile and run 32-bit programs
2. When running cpuid2 according to the command in the textbook s. An error will occur:
The reason is that the source code is 32-bit. A 64 bit program will be generated on a 64 bit system. Compatibility errors will occur when running, resulting in the program being unable to run.
resolvent:
1. 32-bit libraries need to be installed:
sudo apt-get install libc6-dev-i386
Execute the program command to read:
gcc cpuid.s -m32 -o cpuid
The results are as follows:
The processor Vendor ID is 'GenuineIntel'
Execution screenshot:
2. The file can be forcibly compiled from 64 bit to 32-bit program, and then run.
Add before the beginning of the program's source code:
.code32
And install the 32-bit libraries required to run the program:
sudo apt-get update sudo apt install lib32z1 lib32ncurses5 g++-multilib libc6-dev-i386
Execute the program command to read:
as --32 -o cpuid2.o cpuid2.s ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o cpuid2 -lc cpuid2.o ./cpuid2
The results are as follows:
The processor Vendor ID is 'GenuineIntel'
Execution screenshot: