中山大学操作系统lab week 4

操作系统实验报告3

一、实验内容

验证实验 Blum’s Book: Sample programs in Chapter 08, 10 (Basic Math Functions and Using Strings)

二、实验环境

Ubuntu 18.04(64位)

三、实验过程

1、Sample programs in Chapter 08

第八章通过无符号和带符号数字的加减乘除指令的程序范例,介绍了整数运算是如何在处理器上执行的,以及如何在汇编语言程序中使用它们。

整数加法与二进制数值如何相加有关。

1)addtest1.s

ADD指令:add source, destination

ADD指令可以用于无符号和带符号整数。其中source可以是立即值、内存位置或者寄存器,destination可以是寄存器或者内存位置中存储的值,但是不能同时使用内存位置作为源和目标。

ADD指令可以将8位、16位或者32位值相加,通过在ADD助记符的结尾添加b(用于字节)、w(用于字)或者l(用于双字)来指定操作数的长度。

该程序演示使用这些ADD指令执行加法。

在终端中输入命令行:

 $ as -gstabs --32 -o addtest1.o addtest1.s
 $ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o addtest1 -lc addtest1.o
 $ gdb -q addtest1

输出结果:

2)addtest2.s

该程序演示使用ADD指令执行一些带符号整数的加法。

在终端中输入命令行:

 $ as -gstabs --32 -o addtest2.o addtest2.s
 $ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o addtest2 -lc addtest2.o
 $ gdb -q addtest2

输出结果:

3)addtest3.s

该程序演示如何检测加法程序有无进位。

在终端中输入命令行:

 $ as -gstabs --32 -o addtest3.o addtest3.s
 $ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o addtest3 -lc addtest3.o
 $ ./addtest3
 $ echo $?

输出结果:

 

表示正确地检测到了进位情况,改动寄存器值,使加法不产生进位:

movb $190, %bl

movb $10, %al

再次运行程序,得到结果:

加法没有产生进位,没有采取跳转。

4)addtest4.s

该程序演示在带符号整数加法中使用溢出标志检测错误。

在终端中输入命令行:

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

输出结果:

 

输出表明检测到了溢出,修改MOVL指令,使两个值的相加不产生溢出:

movl $-190876934, %ebx

movl $-159230143, %eax

得到结果:

5)adctest1.s

ADC指令:·adc source, destination

其中source可以是立即值或者8位、16位或32位寄存器或内存位置值,destination可以是8位、16位或32位寄存器或内存位置值,但两者不能同时是内存位置。此外,和ADD指令一样,GNU汇编器要求在助记符中用附加的字符来表明操作数长度(b/w/l)

该程序演示如何使用ADC指令将两个64位无符号整数值相加。

在终端中输入命令行:

 $ as -gstabs --32 -o adctest.o adctest.s
 $ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o adctest -lc adctest.o
 $ gdb -q adctest
 $ ./adctest

输出结果:

6)subtest1.s

SUB指令:sub source, destination

其中从destination的值中减去source的值,结果储存在destination操作数的位置。

source可以是立即值、内存位置或者寄存器,destination可以是寄存器或者内存位置中存储的值,但是不能同时使用内存位置作为源和目标。

SUB指令可以将8位、16位或者32位值相加,通过在助记符的结尾添加b(用于字节)、w(用于字)或者l(用于双字)来指定操作数的长度。

该程序演示使用SUB指令执行减法。

在终端中输入命令行:

 $ as -gstabs --32 -o subtest1.o subtest1.s
 $ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o subtest1 -lc subtest1.o
 $ gdb -q subtest1

输出结果:

7)subtest2.s

该程序演示如何检测无符号整数减法程序有无进位。

在终端中输入命令行:

 $ as -gstabs --32 -o subtest2.o subtest2.s
 $ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o subtest2 -lc subtest2.o
 $ ./subtest2
 $ echo $?
 $ gdb -q subtest2

输出结果:

8)subtest3.s

该程序演示如何检测带符号整数减法程序有无溢出。

在终端中输入命令行:

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

输出结果:

说明溢出。改动文件中的movl语句:movl $-1259230143, %eax

再次运行程序:

没有溢出。

9)sbbtest.s

SBB指令:sbb source, destination

其中进位位被添加到source值,然后从destination值中减去source值得到结果。结果存储到destination的位置中。同样的,source可以是立即值、内存位置或者寄存器,destination可以是寄存器或者内存位置中存储的值,但是不能同时使用内存位置作为源和目标。

该程序演示在多字节减法操作中使用SBB指令。

在终端中输入命令行:

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

输出结果:

递增指令:dec destination

递减指令:inc destination

10)multest.s

MUL指令:mul source

该指令用于两个无符号整数相乘,目标操作数是隐藏的,根据源操作数的值长度,乘法操作的另一个操作数必须存放在AL/AX/EAX寄存器中。

该程序演示两个32位无符号整数的乘法操作。

在终端中输入命令行:

$ as -gstabs --32 -o multest.o multest.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o multest -lc multest.o
$ gdb -q multest

输出结果:

11)imultest.s

IMUL指令:

imul source

imul source, destination

imul multiplier, source, destination

该指令可以用于带符号和无符号整数的相乘,注意,对于较大的值,IMUL指令只对带符号整数是合法的。其中,multiplier是一个立即值。

该程序演示两个32位无符号整数的乘法操作。

在终端中输入命令行:

$ as -gstabs --32 -o imultest.o imultest.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o imultest -lc imultest.o
$ gdb -q imultest

输出结果:

12)imultest2.s

该程序演示检查带符号整数相乘的结果是否溢出。

在终端中输入命令行:

$ as -gstabs --32 -o imultest2.o imultest2.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o imultest2 -lc imultest2.o
$ ./imultest2
$ echo $?

输出结果:

结果代码为1,说明溢出。

13)divtest.s

DIV指令:div divisor

该指令用于无符号整数除法操作。其中divisor(除数)是隐含的被除数要除以的值,在执行DIV指令时,被除数必须已经存储到了AX寄存器(16位),DX:AX寄存器(32位),或者EDX:EAX寄存器(64位)。除法操作的结果是两个单独的数字:商和余数,两者都存储在被除数值使用的相同寄存器。这意味着当除法操作完成时,会丢失被除数。

该程序演示简单的除法操作。

在终端中输入命令行:

$ as -gstabs --32 -o divtest.o divtest.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o divtest -lc divtest.o
$ gdb -q divtest
$ ./divtest

输出结果:

当把程序中的divisor值设置为0时,再次运行:

除数为0时会报错。

IDIV指令:idiv divisor

该指令用于带符号整数的除法操作,其余与DIV指令相似。

14)saltest.s

SAL指令:

sal destination

sal %cl, destination

sal shifter, destination

该程序演示使用SAL指令的基本情况。

在终端中输入命令行:

$ as -gstabs --32 -o saltest.o saltest.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o saltest -lc saltest.o
$ gdb -q saltest

输出结果:

15)aaatest.s

该程序演示两个多字节不打包BCD值的加法操作。

在终端中输入命令行:

$ as --32 -gstabs  -o aaatest.o aaatest.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o aaatest -lc aaatest.o
$ gdb -q aaatest

输出结果:

在运行该程序时出现问题:eax寄存器一直是一个绝对值较大的负数值,原因是eax寄存器是未赋初值清零,初始值为乱码。

 

程序赋值时仅改动低位,未修改高位,在程序中clc语句前添加movl $0, %eax赋初值为0即可解决。

16)dastest.s

该程序演示使用SBB和DAS指令执行减法操作。

在终端中输入命令行:

$ as --32 -gstabs  -o dastest.o dastest.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o dastest -lc dastest.o
$ gdb -q dastest

输出结果:

52933 - 28125 = 24808, 与结果相符。

17)cpuidtest.s

该程序演示反转EFLAGS寄存器中的ID位。

在终端中输入命令行:

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

输出结果:

CPUID指令可用,证明ID标志位改变了。

2、Sample programs in Chapter 10

第十章指导如何处理字符串,包括介绍在内存中传送字符串、比较字符串与在字符串中搜索字符串的指令。

1)movstest1.s

 

该程序演示使用MOVS指令传送一些字符串:

在终端中输入命令行:

$ as -gstabs --32 -o movstest1.o movstest1.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o movstest1 -lc movstest1.o
$ gdb -q movstest1

输出结果:

2)movstest2.s

在终端中输入命令行:

$ as -gstabs --32 -o movstest2.o movstest2.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o movstest2 -lc movstest2.o
$ gdb -q movstest2

输出结果:

(gdb) x/23b &output
0x804a018 <output>:     0       0       0       0       0       0       0   
00x804a020 <output+8>:   0       0       0       0       0       0       0   
00x804a028 <output+16>:  0       0       0       110     103     46      10

3)movstest3.s

该程序演示用MOVSL指令循环复制大型字符串的情况。

在终端中输入命令行:

$ as -gstabs --32 -o movstest3.o movstest3.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o movstest3 -lc movstest3.o
$ gdb -q movstest3

输出结果:

4)reptest1.s

该程序演示MOVSB指令和REP指令一起使用,每次1字节地把字符串传送到另一个位置。

在终端中输入命令行:

$ as -gstabs --32 -o reptest1.o reptest1.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o reptest1 -lc reptest1.o
$ gdb -q reptest1

输出结果:

5)reptest2.s

该程序演示使用MOVSW和MOVSL指令遍历字符串时,超出字符串边界的情况。

在终端中输入命令行:

$ as -gstabs --32 -o reptest2.o reptest2.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o reptest2 -lc reptest2.o
$ gdb -q reptest2

输出结果:

 

结果错误。

6)reptest3.s

该程序演示当知道字符串长度时,用整数除法确定字符串中包含多少双字,余数则用MOVSB指令传送的情况。

在终端中输入命令行:

$ as -gstabs --32 -o reptest3.o reptest3.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o reptest3 -lc reptest3.o
$ gdb -q reptest3

输出结果:

7)reptest4.s

该程序演示将DF标志设置为对字符串进行向后处理,按照相反的方向在内存位置之间传送它的情况。

在终端中输入命令行:

$ as -gstabs --32 -o reptest4.o reptest4.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o reptest4 -lc reptest4.o
$ gdb -q reptest4

输出结果:

8)stostest1.s

该程序演示STOS指令与REP指令一起使用,多次把一个字符串值复制到大型字符串值中。

在终端中输入命令行:

$ as -gstabs --32 -o stostest1.o stostest1.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o stostest1 -lc stostest1.o
$ gdb -q stostest1

输出结果:

9)convert.s

该程序演示利用LODS指令遍历字符串,再用STOS指令把新的字符加载回字符串的原理,将ASCⅡ字符串都转换为大写字母的情况。

在终端中输入命令行:

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

输出结果:

10)cmpstest1.s

该程序演示使用CMPS指令的简单例子。

在终端中输入命令行:

$ as -gstabs --32 -o cmpstest1.o cmpstest1.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o cmpstest1 -lc cmpstest1.o
$ ./cmpstest1
$ echo $?

输出结果:

11)cmpstest2.s

该程序演示使用REP指令系列中的其他指令,与CMPS指令一起使用,进行字符串比较。

在终端中输入命令行:

$ as -gstabs --32 -o cmpstest2.o cmpstest2.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o cmpstest2 -lc cmpstest2.o
$ ./cmpstest2
$ echo $?

输出结果:

 

12)strcomp.s

该程序演示字符串的不等和相等的比较。

在终端中输入命令行:

$ as -gstabs --32 -o strcomp.o strcomp.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o strcomp -lc strcomp.o
$ ./strcomp
$ echo $?

输出结果:

13)scastest1.s

该程序演示使用REPNE和SCAS指令在字符串中搜索一个字符。

在终端中输入命令行:

$ as -gstabs --32 -o scastest1.o scastest1.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o scastest1 -lc scastest1.o
$ ./scastest1
$ echo $?

输出结果:

14)scastest2.s

该程序演示使用SCASW和SCASL指令搜索多个字符序列的情况。

在终端中输入命令行:

$ as -gstabs --32 -o scastest2.o scastest2.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o scastest2 -lc scastest2.o
$ ./scastest2
$ echo $?

输出结果:

 

15)strsize.s

该程序演示计算字符串长度。

在终端中输入命令行:

$ as -gstabs --32 -o strsize.o strsize.s
$ ld -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o strsize -lc strsize.o
$ ./strsize
$ echo $?

输出结果:

 

四、实验总结

通过本次实验,我验证了第八章与第十章中的范例汇编程序,掌握了无符号和带符号整数的加减乘除运算,学习了字符串的传送、比较与匹配等处理的实现方式。在这个过程中,我对汇编语言的理解逐渐加深,更熟悉了linux终端的命令行使用,各寄存器的用处与汇编原理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值