x86汇编语言之内中断进阶

368 阅读4分钟

「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战」。

内中断进阶

我们利用中断码段可以调用系统的功能,也就是被系统封装好的子程序

中断既然能够引导cpu临时去执行子程序,那么势必是更改了cs:ip的值,也就是在内存中存放了这个子程序的入口指令地址,通过int关键字找出来并跳转。这里有两个先决条件,一个是子程序必须提前编写好存放在内存中,二是将入口地址存放在内存的某个位置

当程序执行到int指令时,根据中断码计算出程序入口所在的物理地址,然后然后取出来赋值给cs:ip

那么怎么通过中断码计算呢?

比如 int 0h 会从0000:0000这个地址开始找出四个字节数据,由高地址往低地址分别为段地址和偏移地址

由于每个中断码需要占用四个字节空间,因此int 2H0000:0004开始找,以此类推

公式为:

IP=中断码*4
CS=中断码*4+2

配合咱们之前学的call指令 int 9h 可以用以下指令替代:

int 9h 

;相当于一下三行代码
mov ax,0000H
mov ds,ax
call dword ptr ds:[9h*4]

编写自定义中断

  1. 编写子程序

    child:
    	mov ax,3322H
    	retf
    
  2. 将子程序入口地址值存放到中断码对应的内存位置

    code segment
    start:
    	call write
    	
    	mov ah,4cH
    	int 21h
    	
    	
        ;=======子程序======
        child:
            mov ax,3322H
            retf
        endd: nop
        ;=======子程序======
    
    
        ;=======将子程序入口地址写入内存======
        write:
        	
        	;子程序所在的段地址
        	mov ax,cs
        	;子程序所在的偏移地址
        	mov bx,child
        
        	mov cx,0000H
        	mov es,cx
        	mov es:[9h*4],bx
        	mov es:[9h*4+2],ax
        	ret
    code ends
    end start
    
    
  3. 使用中断码调用子程序

    code segment
    start:
    	call write
    	
    	;测试中断
    	int 9H
    	
    	mov ah,4cH
    	int 21h
    	
    	
        ;=======子程序======
        child:
            mov ax,3322H
            retf
        endd: nop
        ;=======子程序======
    
    
        ;=======将子程序入口地址写入内存======
        write:
        	
        	;子程序所在的段地址
        	mov ax,cs
        	;子程序所在的偏移地址
        	mov bx,child
        
        	mov cx,0000H
        	mov es,cx
        	mov es:[9h*4],bx
        	mov es:[9h*4+2],ax
        	ret
    code ends
    end start
    
    

音乐播放

声音由震动产生,不同频率对应不同的声音,也就是音高

单个音高的声音不能叫音乐,只能叫音频,

而音乐是由不同时长不同音高组合而成,比如100Hz的声音持续1秒紧接着200Hz的声音持续半秒,如此反复循环,那么在听感上就是一首音乐

在音乐演奏的世界里,为了表示音高,一般采用记谱的方式来代替频率,从而方便音乐家们交流,但是对于计算机而言,计算机不能识别简谱也不能识别五线谱

计算机的发声原理

电信号----->驱动------->扬声器

示例代码

data segment
	;音高
	freq dw 262,262,262,196
		 dw 330,330,330,262
		 dw 262,330,392,392
		 dw 349,330,294
		 dw 294,330,349,349
		 dw 330,294,330,262
		 dw 262,330,294,196
		 dw 247,294,262,-1
	 ;时长
	 time dw 3 dup(12,12,25,25),12,12,50
	      dw 3 dup(12,12,25,25),12,12,50
data ends

stack segment
	db 100H dup(0)
stack ends

code segment
	start:
		;主程序
		mov ax,stack
		mov ss,ax
		mov sp,100H
		mov ax,data
		mov ds,ax
		
		lea si,freq
		lea di,time
		
	play:
		mov dx,[si]
		cmp dx,-1
		je end_play
		call sound
		add si,2
		add di,2
		jmp play
		
	end_play:
		mov ah,4cH
		int 21H
	sound:
    	push ax
    	push dx
    	push cx
    	;定时器的设置
    	mov al,0b6h
    	out 43H,al
    	mov dx,12H
    	mov ax,34dcH
    	div word ptr[si]
    	out 42h,al
    	mov al,ah
    	out 42h,al
    	;设置8255芯片,控制扬声器开关
    	in al,61h
    	mov ah,al
    	or al ,3
    	out 61h,al
    	;延时一定的时长
    	mov dx,[di]
    wait1:
    	mov cx,28000
    delay:
    	nop
    	loop delay
    	dec dx
    	jnz wait1
        ;恢复扬声器端口原值
        mov al,ah
        out 61h,al
        pop cx
        pop dx
        pop ax
        ret
code ends
end start