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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

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

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

操作系統(tǒng)實(shí)驗(yàn)報(bào)告2

實(shí)驗(yàn)內(nèi)容

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

實(shí)驗(yàn)環(huán)境

  • 架構(gòu):Intel x86_64 (虛擬機(jī))
  • 操作系統(tǒng):Ubuntu 20.04
  • 匯編器:gas (GNU Assembler) in AT&T mode
  • 編譯器:gcc

技術(shù)日志

Chapter 04

  • 驗(yàn)證實(shí)驗(yàn)cpuid.s

程序的源代碼略。

1.構(gòu)建一般可執(zhí)行程序:

執(zhí)行程序命令:

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

執(zhí)行結(jié)果如下:

The processor Vendor ID is 'GenuineIntel'

執(zhí)行截圖:

2.使用編譯器進(jìn)行匯編:

將原程序代碼中的:

.globl _start _start:

改為:
.globl main
main:

安裝32位的gcc庫:

sudo apt-get install libc6-dev-i386

執(zhí)行程序命令:

gcc cpuid.s -m32 -o cpuid

執(zhí)行結(jié)果如下:

The processor Vendor ID is 'GenuineIntel'

執(zhí)行截圖:

3.使用gdb運(yùn)行程序:

執(zhí)行程序命令:

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

執(zhí)行結(jié)果如下:

分析:

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

The processor Vendor ID is 'GenuineIntel'

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

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

x/42cd &output以字符變量的形式顯示變量output的前42個(gè)字節(jié)

gdb基本指令總結(jié):

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

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

.code32

并安裝程序運(yùn)行所需32位庫:

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

執(zhí)行程序命令:

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

執(zhí)行結(jié)果如下:

The processor Vendor ID is 'GenuineIntel'

執(zhí)行截圖:


Chapter 05

定義數(shù)據(jù)元素

數(shù)據(jù)段:數(shù)據(jù)段是最常見的定義數(shù)據(jù)元素的位置。用于存儲(chǔ)項(xiàng)目的特定內(nèi)存位置,可以被程序的指令碼引用,并且可以被隨意讀取和修改,在數(shù)據(jù)段中定義數(shù)據(jù)時(shí),它必須被包含在可執(zhí)行程序中,因?yàn)橐锰囟ㄖ党跏蓟?/p>

bss段:在bss段定義數(shù)據(jù)元素?zé)o須聲明特定的數(shù)據(jù)類型,不需要初始化,內(nèi)存區(qū)域被保留在運(yùn)行時(shí)使用,并且不必包含在最終的程序中。

  • 驗(yàn)證實(shí)驗(yàn)sizetest1.s

程序的源代碼略。

執(zhí)行程序命令:

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

執(zhí)行結(jié)果如下:

分析:可執(zhí)行程序文件的總長度為4640字節(jié)

  • 驗(yàn)證實(shí)驗(yàn)sizetest2.s

程序的源代碼略。

執(zhí)行程序命令:

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

執(zhí)行結(jié)果如下:

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

  • 驗(yàn)證實(shí)驗(yàn)sizetest3.s

程序的源代碼略。

執(zhí)行程序命令:

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

執(zhí)行結(jié)果如下:

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

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

傳送數(shù)據(jù)元素

MOV指令基本格式:

movx source, destination

source和destination可以是內(nèi)存地址,存儲(chǔ)在內(nèi)存中的數(shù)據(jù)值,指令語句中定義的數(shù)據(jù)值,或者是寄存器

  • 驗(yàn)證實(shí)驗(yàn)movetest1.s

程序的源代碼略。

執(zhí)行程序命令:

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

執(zhí)行結(jié)果如下:

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

  • 驗(yàn)證實(shí)驗(yàn)movetest2.s

程序的源代碼略。

執(zhí)行程序命令:

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

執(zhí)行結(jié)果如下:

分析:一開始查看value中的值,發(fā)現(xiàn)初始值為1,單步執(zhí)行程序,一直到eax寄存器中的值被傳送給了value內(nèi)存中的位置后,再次查看value中的值,發(fā)現(xiàn)值為100,寄存器中的值被傳送到了內(nèi)存位置中

  • 驗(yàn)證實(shí)驗(yàn)movetest3.s

程序的源代碼略。

執(zhí)行程序命令:

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

執(zhí)行結(jié)果如下:

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

  • 驗(yàn)證實(shí)驗(yàn)movetest4.s

程序的源代碼略。

執(zhí)行程序命令:

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

執(zhí)行結(jié)果如下:

分析:程序開始時(shí),首先查看values標(biāo)簽引用的內(nèi)存位置中存儲(chǔ)的值,前4個(gè)元素為10,15,20,25。

然后單步運(yùn)行程序,發(fā)現(xiàn)第一個(gè)元素從values數(shù)組中加載到eax寄存器,即10,現(xiàn)在eax寄存器中的值為10。

繼續(xù)單步執(zhí)行,發(fā)現(xiàn)values標(biāo)簽引用的內(nèi)存地址加載到了edi寄存器中,下一條指令又將100傳送到了edi寄存器保存的地址之后4字節(jié)位置的內(nèi)存地址,使用寄存器間接尋址,查看發(fā)現(xiàn)100保存到了values數(shù)組中的第二個(gè)元素的位置。

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

條件傳送指令

指令格式:

cmovx source, destination

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

  • 驗(yàn)證實(shí)驗(yàn)cmovetest.s

程序的源代碼略。

執(zhí)行程序命令:

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

執(zhí)行結(jié)果如下:

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

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

數(shù)據(jù)交換指令

基本指令:

XCHG:在兩個(gè)寄存器之間或者寄存器和內(nèi)存位置之間交換它們的值 BSWAP:反轉(zhuǎn)一個(gè)32位寄存器中的字節(jié)順序 XADD:交換兩個(gè)值并且把它們的總和存儲(chǔ)在目標(biāo)操作數(shù)中 CMPXCHG:把一個(gè)值和一個(gè)外部的 值進(jìn)行比較,并且交換它和另一個(gè)的值 CMPXCHG8B:比較兩個(gè)64位的值并且交換它們的值
  • 驗(yàn)證實(shí)驗(yàn)swaptest.s

程序的源代碼略。

執(zhí)行程序命令:

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

執(zhí)行結(jié)果如下:

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

  • 驗(yàn)證實(shí)驗(yàn)cmpxchgtest.s

程序的源代碼略。

執(zhí)行程序命令:

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

執(zhí)行結(jié)果如下:

分析:在執(zhí)行cmpxchg指令前,寄存器ebx中的值為5,data中的值為10,執(zhí)行cmpxchg指令后,data中的值變?yōu)?,寄存器ebx中的值被傳送到data的內(nèi)存位置

  • 驗(yàn)證實(shí)驗(yàn)cmpxchg8btest.s

程序的源代碼略。

執(zhí)行程序命令:

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

執(zhí)行結(jié)果如下:

分析:cmpxchg8b data使data引用一個(gè)內(nèi)存位置,其中的8字節(jié)值會(huì)與寄存器edx和寄存器eax進(jìn)行比較,如果目標(biāo)值和edx:eax中包含的值匹配,就把位于ecx:ebx中的64位值傳送給目標(biāo)內(nèi)存位置,如果不匹配,就把目標(biāo)內(nèi)存位置地址中的值加載到edx:eax寄存器對(duì)中,從輸出可以看出,ecx:ebx中的值確實(shí)傳送給了data目標(biāo)內(nèi)存位置

  • 驗(yàn)證實(shí)驗(yàn)bubble.s

程序的源代碼略。

執(zhí)行程序命令:

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

執(zhí)行結(jié)果如下:

分析:程序?yàn)槊芭菖判蛩惴?#xff0c;程序運(yùn)行前,values數(shù)組為亂序,程序運(yùn)行完畢后,values數(shù)組為升序排序

壓入數(shù)據(jù)和彈出數(shù)據(jù)

PUSH指令的簡單格式:

pushx source

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

POP指令的格式:

popx destination

其中x表示數(shù)據(jù)元素的長度,destination是接收數(shù)據(jù)的位置

  • 驗(yàn)證實(shí)驗(yàn)pushpop.s

程序的源代碼略。

執(zhí)行程序命令:

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

執(zhí)行結(jié)果如下:

分析:啟動(dòng)程序前,寄存器esp中的值為0xffffd0d0,當(dāng)執(zhí)行完所有的push指令后,寄存器esp中的值為0xffffd0be,開始的值和最后的值相差了18個(gè)字節(jié),所有經(jīng)過push指令的操作數(shù)據(jù)加起來總長度也是18字節(jié),說明執(zhí)行push操作時(shí)寄存器esp會(huì)遞減,指向堆棧新的起始位置。

遇到問題

1.一開始當(dāng)使用gcc運(yùn)行cpuid.s時(shí),會(huì)發(fā)生錯(cuò)誤:

原因是gcc庫是64位的,不能編譯運(yùn)行32位的程序

2.當(dāng)按照課本上命令運(yùn)行cpuid2.s,會(huì)發(fā)生錯(cuò)誤:

原因是源代碼是32位的,在64位的系統(tǒng)上會(huì)生成64位的程序,運(yùn)行時(shí)會(huì)發(fā)生兼容性錯(cuò)誤,導(dǎo)致程序無法運(yùn)行。

解決方法:

1.需要安裝32位的庫:

sudo apt-get install libc6-dev-i386

執(zhí)行程序命令改為:

gcc cpuid.s -m32 -o cpuid

執(zhí)行結(jié)果如下:

The processor Vendor ID is 'GenuineIntel'

執(zhí)行截圖:

2.可以將文件從64位強(qiáng)行編譯成32位的程序,然后再運(yùn)行。

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

.code32

并安裝程序運(yùn)行所需32位庫:

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

執(zhí)行程序命令改為:

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

執(zhí)行結(jié)果如下:

The processor Vendor ID is 'GenuineIntel'

執(zhí)行截圖:

總結(jié)

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

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。