日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

操作系统实验报告2:Linux 下 x86 汇编语言1

發布時間:2024/6/3 linux 71 豆豆
生活随笔 收集整理的這篇文章主要介紹了 操作系统实验报告2:Linux 下 x86 汇编语言1 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

操作系統實驗報告2

實驗內容

  • 了解 Linux 下 x86 匯編語言編程環境;
  • 驗證實驗 Blum’s Book: Sample programs in Chapter 04, 05 (Moving Data)。

實驗環境

  • 架構:Intel x86_64 (虛擬機)
  • 操作系統:Ubuntu 20.04
  • 匯編器:gas (GNU Assembler) in AT&T mode
  • 編譯器:gcc

技術日志

Chapter 04

  • 驗證實驗cpuid.s

程序的源代碼略。

1.構建一般可執行程序:

執行程序命令:

as -o cpuid.o cpuid.s ld -o cpuid cpuid.o ./cpuid

執行結果如下:

The processor Vendor ID is 'GenuineIntel'

執行截圖:

2.使用編譯器進行匯編:

將原程序代碼中的:

.globl _start _start:

改為:
.globl main
main:

安裝32位的gcc庫:

sudo apt-get install libc6-dev-i386

執行程序命令:

gcc cpuid.s -m32 -o cpuid

執行結果如下:

The processor Vendor ID is 'GenuineIntel'

執行截圖:

3.使用gdb運行程序:

執行程序命令:

as -gstabs -o cpuid.o cpuid.s ld -o cpuid cpuid.o gdb cpuid

執行結果如下:

分析:

一開始在程序開始處設置斷點,然后輸入run運行,輸入命令next\n\step\s可以看見單步調試程序,輸入cont程序直接運行完畢,輸出

The processor Vendor ID is 'GenuineIntel'

重新輸入run,輸入s單步執行至cpuid語句,輸入info registers,可以看見所有寄存器中的值,再輸入s執行至下一語句,輸入info registers,可以看見寄存器中值的變化,可以看見,在執行cpuid語句前寄存器rbx,rcx,rdx的值都為0,執行cpuid后,它們包含從廠商ID字符串得來的值。

print/x $ebx, print/x $edx,print/x $ecx分別以十六進制形式顯示寄存器ebx,edx和ecx中的值,可以看到,寄存器ebx中的值為0x756e6547,寄存器edx中的值為0x49656e69,寄存器ecx中的值為0x6c65746e。

x/42cd &output以字符變量的形式顯示變量output的前42個字節

gdb基本指令總結:

break *_start:在程序開始處設置斷點 break *end:在程序結束處設置斷點 run:在gdb內運行啟動程序(碰到斷點便停止) step/s/next/n:單步調試程序 cont:使程序繼續運行 info registers:顯示全部寄存器的值 print:顯示某一寄存器或變量的值 print/d:顯示十進制的值 print/t:顯示二進制的值 print/x:顯示十六進制的值 x/nyz:顯示特定內存位置的值,n是要顯示的字段數,y是輸出格式,z是要顯示字段的長度
  • 驗證實驗cpuid2.s

在程序的源代碼開頭之前加上:

.code32

并安裝程序運行所需32位庫:

sudo apt-get update sudo apt install lib32z1 lib32ncurses5 g++-multilib libc6-dev-i386

執行程序命令:

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 processor Vendor ID is 'GenuineIntel'

執行截圖:


Chapter 05

定義數據元素

數據段:數據段是最常見的定義數據元素的位置。用于存儲項目的特定內存位置,可以被程序的指令碼引用,并且可以被隨意讀取和修改,在數據段中定義數據時,它必須被包含在可執行程序中,因為要用特定值初始化它。

bss段:在bss段定義數據元素無須聲明特定的數據類型,不需要初始化,內存區域被保留在運行時使用,并且不必包含在最終的程序中。

  • 驗證實驗sizetest1.s

程序的源代碼略。

執行程序命令:

as -o sizetest1.o sizetest1.s ld -o sizetest1 sizetest1.o ls -al sizetest1

執行結果如下:

分析:可執行程序文件的總長度為4640字節

  • 驗證實驗sizetest2.s

程序的源代碼略。

執行程序命令:

as -o sizetest2.o sizetest2.s ld -o sizetest2 sizetest2.o ls -al sizetest2

執行結果如下:

分析:在bss段聲明添加了10000字節的緩沖區后,可執行程序文件的總長度為4800字節,比原來只增加了160字節,說明在bss段聲明數據不必包含在可執行程序中。

  • 驗證實驗sizetest3.s

程序的源代碼略。

執行程序命令:

as -o sizetest3.o sizetest3.s ld -o sizetest3 sizetest3.o ls -al sizetest3

執行結果如下:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-goPlbdyE-1626174832894)(http://stugeek.gitee.io/operating-system/Labwork2-pictures/8.png)]

分析:用.fill命令在數據段聲明添加了10000字節的緩沖區后,可執行程序文件的總長度為18880字節,比原來增加了14240字節,.fill命令使匯編器自動地創建了10000個數據元素,使它比必要的長度大了很多,說明在數據段定義數據時,其必須被包含在可執行程序中。

傳送數據元素

MOV指令基本格式:

movx source, destination

source和destination可以是內存地址,存儲在內存中的數據值,指令語句中定義的數據值,或者是寄存器

  • 驗證實驗movetest1.s

程序的源代碼略。

執行程序命令:

as -gstabs -o movtest1.o movtest1.s ld -o movtest1 movtest1.o gdb -q movtest1

執行結果如下:

分析:可以看到,執行了movl value, %ecx命令后,內存中存儲的值1被傳送到了ecx寄存器,ecx寄存器的值從原來的0變成了1,內存位置中的值被傳送到了另一寄存器中

  • 驗證實驗movetest2.s

程序的源代碼略。

執行程序命令:

as -gstabs -o movtest2.o movtest2.s ld -o movtest2 movtest2.o gdb -q movtest2

執行結果如下:

分析:一開始查看value中的值,發現初始值為1,單步執行程序,一直到eax寄存器中的值被傳送給了value內存中的位置后,再次查看value中的值,發現值為100,寄存器中的值被傳送到了內存位置中

  • 驗證實驗movetest3.s

程序的源代碼略。

執行程序命令:

as --32 -o movtest3.o movtest3.s ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -lc -o movtest3 movtest3.o ./movtest3

執行結果如下:

分析:程序遍歷了values標簽指定的數據數組,用edi寄存器作為遍歷數組用的變址,每個值顯示后,edi寄存器的值被遞增,依次從10每次增加5打印到60

  • 驗證實驗movetest4.s

程序的源代碼略。

執行程序命令:

as -gstabs -o movtest4.o movtest4.s ld -o movtest4 movtest4.o gdb -q movtest4

執行結果如下:

分析:程序開始時,首先查看values標簽引用的內存位置中存儲的值,前4個元素為10,15,20,25。

然后單步運行程序,發現第一個元素從values數組中加載到eax寄存器,即10,現在eax寄存器中的值為10。

繼續單步執行,發現values標簽引用的內存地址加載到了edi寄存器中,下一條指令又將100傳送到了edi寄存器保存的地址之后4字節位置的內存地址,使用寄存器間接尋址,查看發現100保存到了values數組中的第二個元素的位置。

再下一條指令把數組的第二個元素加載到了ebx寄存器中,使用echo $?命令查看第二個數據數組元素的值,也是100。

條件傳送指令

指令格式:

cmovx source, destination

其中x是一個或者兩個字母的代碼,表示將觸發傳送操作的條件,取決于EFLAGS寄存器的當前值。

  • 驗證實驗cmovetest.s

程序的源代碼略。

執行程序命令:

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

執行結果如下:

分析:寄存器ebx用來保存當前找到的最大整數,然后數組元素被逐個加載到寄存器eax中,并且和寄存器ebx中的值比較,如果寄存器eax中的值更大,就用寄存器eax中的值代替寄存器ebx中的值。

程序一開始,數組的第一個值被加載到寄存器ebx中。為105,第二個值被加載到寄存器eax中,為235,運行cmp和cmova指令,發現寄存器ebx寄存器中的值變成了更大的235,持續操作,直到數組的數全部被遍歷完,最后寄存器ebx中的數就是數組中的數的最大值,為315。

數據交換指令

基本指令:

XCHG:在兩個寄存器之間或者寄存器和內存位置之間交換它們的值 BSWAP:反轉一個32位寄存器中的字節順序 XADD:交換兩個值并且把它們的總和存儲在目標操作數中 CMPXCHG:把一個值和一個外部的 值進行比較,并且交換它和另一個的值 CMPXCHG8B:比較兩個64位的值并且交換它們的值
  • 驗證實驗swaptest.s

程序的源代碼略。

執行程序命令:

as --gstabs -o swaptest.o swaptest.s ld -o swaptest swaptest.o gdb -q swaptest

執行結果如下:

分析:程序在第一條movl指令后停止,查看寄存器ebx中的值,為0x12345678,單步執行bswap指令后,顯示寄存器ebx中的值,為0x78563412,和原始值尾數順序相反。

  • 驗證實驗cmpxchgtest.s

程序的源代碼略。

執行程序命令:

as --gstabs -o cmpxchgtest.o cmpxchgtest.s ld -o cmpxchgtest cmpxchgtest.o gdb -q cmpxchgtest

執行結果如下:

分析:在執行cmpxchg指令前,寄存器ebx中的值為5,data中的值為10,執行cmpxchg指令后,data中的值變為5,寄存器ebx中的值被傳送到data的內存位置

  • 驗證實驗cmpxchg8btest.s

程序的源代碼略。

執行程序命令:

as -gstabs -o cmpxchg8btest.o cmpxchg8btest.s ld -o cmpxchg8btest cmpxchg8btest.o gdb -q cmpxchg8btest

執行結果如下:

分析:cmpxchg8b data使data引用一個內存位置,其中的8字節值會與寄存器edx和寄存器eax進行比較,如果目標值和edx:eax中包含的值匹配,就把位于ecx:ebx中的64位值傳送給目標內存位置,如果不匹配,就把目標內存位置地址中的值加載到edx:eax寄存器對中,從輸出可以看出,ecx:ebx中的值確實傳送給了data目標內存位置

  • 驗證實驗bubble.s

程序的源代碼略。

執行程序命令:

as -gstabs -o bubble.o bubble.s ld -o bubble bubble.o gdb -q bubble

執行結果如下:

分析:程序為冒泡排序算法,程序運行前,values數組為亂序,程序運行完畢后,values數組為升序排序

壓入數據和彈出數據

PUSH指令的簡單格式:

pushx source

其中x表示數據元素的長度,source是要放入堆棧的數據元素

POP指令的格式:

popx destination

其中x表示數據元素的長度,destination是接收數據的位置

  • 驗證實驗pushpop.s

程序的源代碼略。

執行程序命令:

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

執行結果如下:

分析:啟動程序前,寄存器esp中的值為0xffffd0d0,當執行完所有的push指令后,寄存器esp中的值為0xffffd0be,開始的值和最后的值相差了18個字節,所有經過push指令的操作數據加起來總長度也是18字節,說明執行push操作時寄存器esp會遞減,指向堆棧新的起始位置。

遇到問題

1.一開始當使用gcc運行cpuid.s時,會發生錯誤:

原因是gcc庫是64位的,不能編譯運行32位的程序

2.當按照課本上命令運行cpuid2.s,會發生錯誤:

原因是源代碼是32位的,在64位的系統上會生成64位的程序,運行時會發生兼容性錯誤,導致程序無法運行。

解決方法:

1.需要安裝32位的庫:

sudo apt-get install libc6-dev-i386

執行程序命令改為:

gcc cpuid.s -m32 -o cpuid

執行結果如下:

The processor Vendor ID is 'GenuineIntel'

執行截圖:

2.可以將文件從64位強行編譯成32位的程序,然后再運行。

在程序的源代碼開頭之前加上:

.code32

并安裝程序運行所需32位庫:

sudo apt-get update sudo apt install lib32z1 lib32ncurses5 g++-multilib libc6-dev-i386

執行程序命令改為:

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 processor Vendor ID is 'GenuineIntel'

執行截圖:

總結

以上是生活随笔為你收集整理的操作系统实验报告2:Linux 下 x86 汇编语言1的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。