系统编程LAB7学习笔记(含实验13的第一题)

(未完)

一、知识储备(汇编语言12~15章)

1.debug中的 t命令在执行修改寄存器ss的指令时,下一条指令也会被紧接着被执行,不需要再用t指令去单步执行
2.int 7ch引发中断进程后,进入7ch中断例程,在中断过程中,当前的标志寄存器、cs和IP都要压栈,此时压入的cs和IP中的内容,分别是调用程序的段地址和int 7ch后一条指令的偏移地址。
3.iret指令的功能为: pop ip pop cs popf
4.jcxz是有条件跳转指令,对指令jcxz ex1来说,若计数寄存器cx=0,则跳到标号ex1处继续执行;若程序计数器不为0,则不跳转。
5.对于书中用7ch中断例程来完成loop指令的功能那里,有个点一开始不是很明白:为什么要用bp?为什么访问了栈就要使用bp?

在这里插入图片描述
我看了参考博客以后才知道这是由bp寄存器的特殊性决定的:bp一般与ss联用,bp可作为堆栈区中的一个基地址,用以确定在堆栈中的操作数地址。而此时s的段地址、int 7ch下一条指令的地址已经入栈了,要想访问这两个地址,就需要访问栈,所以也就需要用到bp寄存器。
6.这里复习一下立即寻址和直接寻址:
1)立即寻址:操作数就包含在指令中,作为指令的一部分,跟在操作码后存放在代码段,如:mov ax,1234h
2)直接寻址:操作数在寄存器中,指令直接包含有操作数的有效地址。如:
mov ax,[8054]




二、题目及解答

1.请分析为什么说“中断技术出现后,多道程序的概念才变得有意义”。(提示:可额外了解并发、通道技术等辅助说明)

这个题我完全是东搬西抄过来的,哈哈:

哈哈多道程序并发执行指的是有的程序正在CPU上执行,而另一些程序正在I/O设备上进行传输,即通过CPU操作与外设传输在时间上的重叠减少CPU时间的浪费,从而提高系统效率。而中断和通道技术实现CPU操作与外设传输在时间上的重叠的原理如下:
哈哈1) 通道是一种通过执行通道程序管理输入输出操作的控制器,它使CPU与I/O操作之间达到更高的并行程度。CPU把数据传输功能下放给通道,然后通道与CPU分时使用内存,从而实现CPU与外设的并行工作。需要进行I/O操作时,CPU发出一条通道命令,然后由通道和外设交换数据,之后CPU就做其它的事情,通道处理完数据后再向CPU汇报,CPU再接着处理这些数据。但是早期CPU与通道的联络方法是由CPU向通道发出询问指令来了解通道工作是否完成。若未完成,则主机就循环询问直到通道工作结束为止。因此,这种询问方式是无法真正做到CPU与I/O设备并行工作的。
哈哈2) 中断就能很好地解决上述问题。中断就是在输入输出结束时,或硬件发生某种故障时,由相应硬件向CPU发出信号,然后CPU马上停下手头的工作而转向处理中断请求,处理完中断后再继续原来的工作。中断技术出现后,通道才能在处理完数据后主动向CPU发送中断信号,而不需要多次与CPU进行交互。发送中断信号后,CPU便可放下手头的工作处理中断,处理完后再继续原来的工作。这样,就真正做到了CPU与I/O设备并行工作,从而使多道程序的概念变为现实。


2.补全注释的部分,将数据段打印到屏幕(提示:即将内容写入显存,这里可以写一个通用的显示字符串的中断例程,下一题也用得到)

在这里插入图片描述
先提一下思路:
1)(把ah设置为2)用int 10h的2号子例程设置光标位置,并设置dh,dl的值(设置光标位置),设置bh的值(设置显示的页号)
2)(把ah设置为9)用int 21h 的9号子例程设置在光标处显示字符串,字符串的首地址存储在ds:dx中
3)记住,存储子例程序号的是ah,ah,ah,ah,ah!!!!!!!!!!!!!!!!!
补全后的代码如下:

;补全注释的部分,将数据段打印到屏幕
assume cs:code
code segment
	s1:db 'A MAN IS NOT DRUNK,','$'
	s2:db 'WHEN UP FROM THE FLOOR,','$'
	s3:db 'HE CAN RAISE HIS HEAD,','$'
	s4:db 'AND ASK FOR MORE.','$'
	s:dw offset s1,offset s2,offset s3,offset s4
	row:db 2,4,6,8
	start:
		mov ax,cs
		mov ds,ax
		mov bx,offset s;bx存的是s的偏移地址,步长为2
		mov si,offset row;si存的是row的偏移地址,步长为1
		mov cx,4
		
		

	ok:
	mov ah,2
	mov bh,0
	mov dh,[si];dh是行号
	mov dl,28;dl是列号
	int 10h
	
	
	;开始显示字符串,调用21h例程,9号子程序
	
	mov dx,[bx];每次循环dx获得的是4个字符串的偏移地址
	mov ah,9;int 21h的9号子例程显示的字符串的首地址在ds:dx处
	add bx,2
	inc si
	int 21h
	
	loop ok
	
	mov ax,4c00h
	int 21h
code ends
end start

运行结果为:
在这里插入图片描述
这里有几个点是困扰了我很久的,主要原因是我太菜了,哭死:


1)mov bx,offset s既然bx存的是s段的偏移地址,而s段的第一个就是offset s1,那是不是bx存的也是字符串s1的偏移地址?事实证明:当然不是。存储地址和这个地址存的数据是完全不同的概念,s段的偏移地址,即cs:offset s是字符串s1的偏移地址这个数据的存储位置而已,要想获得这个数据,还得通过方括号+寄存器读取该数据,也就是:mov dx,[bx],这样操作后,dx便能获取字符串s1的偏移地址(我们称这个地址为address1)。如果是直接mov dx,bx,那dx得到的只是存放数据address1的偏移地址而已。


2)那么,能不能直接用[offset s1]直接获得字符串s1的偏移地址呢?理论上是可以的,但是在DOSBOX中,我发现立即寻址和直接寻址是一样的,所以这样做实际是不可行的(待进一步的考证)。后来查了查,据说是masm5.0编译器的bug。但我觉得不太应该呀?


3)row段的数据是用来安排诗句的行号的,不是用来遍历s段的。


3.完成实验13的第一小题(汇编语言第二版):
assume cs:code
code segment
start:
	mov ax,cs
	mov ds,ax
	mov si,offset int7c
	
	mov ax,0
	mov es,ax
	mov di,200h
	
	mov cx,offset int7cend - offset int7c
	
	cld
	rep movsb
	
	mov ax,0
	mov es,ax
	mov word ptr es:[7ch*4],200h
	mov word ptr es:[7ch*4+2],0
	
	mov ax,4c00h
	int 21h
	
int7c:
	push ax
	push es
	push bx
	push di
	mov ax,0b800h
	mov es,ax
	
	mov ax,160
	mul dh
	mov bx,ax
	mov ax,2
	mul dl
	add bx,ax
	;以上这一段是用来计算总偏移的
	
	mov di,0
loops:
	cmp byte ptr [si],0
	je return
	mov al,[si]
	mov es:[bx+di],al
	mov es:[bx+di+1],cl
	add di,2
	inc si
	jmp loops
	
return:
	pop di
	pop bx
	pop es
	pop ax
	iret
	
int7cend:
	nop
	
	mov ax,4c00h
	int 21h
code ends
end start

运行截图:
在这里插入图片描述
这个题有几个点是值得我留意的:
1)怎么按照给定的行号、列号把字符写到显存中去,我查到的一个解决办法是先在外部算好总的偏移,存到bx里去,然后再直接存到ss:[bx]里面去:

mov ax,160
		mul dh
		mov bx,ax
		mov ax,2
		mul dl
		add bx,ax

2)涉及到显存时,需要用两个寄存器作为指针,一个寄存器用于遍历字符串,每次循环加1;另一个用于遍历显存,即字符串写入的位置,每次循环加2





思考题

编写一个简单的程序体会它真正的运行过程: 子函数的功能,实现两个整数相加,并返回和。 主程序的功能:从键盘读入两个整数,调用子函数,并将得到的和显示到屏幕上。

可从以下这些方向进行分析:
从计算机硬件的基本组成、汇编程序员眼中的硬件组成、C语言程序员眼中的硬件组成、程序(段)的基本组成、输入的基本流程、运算的基本流程、输出的基本流程;中断处理的基本流程、异常处理的基本流程、函数调用的基本流程等角度,分析上述程序的运行过程。
可充分利用图示的方式,从多种视图的角度分析描绘。

先鸽着吧,目前我在centos虚拟机上的/lab7目录下建了个test.c文件:
在这里插入图片描述
然后用gcc -S test.c命令生成了.s文件,打开后内容长这样:

.file	"test.c"
	.section	.rodata
.LC0:
	.string	"%d%d"
.LC1:
	.string	"%d"
	.text
.globl main
	.type	main, @function
main:
.LFB0:
	.cfi_startproc
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset 6, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register 6
	subq	$16, %rsp
	movl	$0, -8(%rbp)
	movl	$0, -12(%rbp)
	movl	$.LC0, %eax
	leaq	-12(%rbp), %rdx
	leaq	-8(%rbp), %rcx
	movq	%rcx, %rsi
	movq	%rax, %rdi
	movl	$0, %eax
	call	__isoc99_scanf
	movl	-8(%rbp), %edx
	movl	-12(%rbp), %eax
	leal	(%rdx,%rax), %eax
	movl	%eax, -4(%rbp)
	movl	$.LC1, %eax
	movl	-4(%rbp), %edx
	movl	%edx, %esi
	movq	%rax, %rdi
	movl	$0, %eax
	call	printf
	leave
	.cfi_def_cfa 7, 8
	ret
	.cfi_endproc
.LFE0:
	.size	main, .-main
	.ident	"GCC: (GNU) 4.4.7 20120313 (Red Hat 4.4.7-23)"
	.section	.note.GNU-stack,"",@progbits

太长了,先搁着吧…

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值