《操作系统真象还原》第七章(2)——中断

《操作系统真象还原》第七章(2)——中断

前言

这篇博客分为三部分:完成第6章put_int函数,完成第7章中断函数并改进,前7章知识点拾遗。

上一篇博客连接:《操作系统真象还原》第七章(1)——中断-优快云博客


整数打印函数put_int

jg:有符号大于则跳转

jl:有符号小于泽跳转

section .data
put_int_buffer dq 0 ;8字节

global put_int
put_int:
	pushad
	mov ebp,esp
	mov eax,[ebp+4*9]
	mov edx,eax		;待处理的16进制整数
	mov edi,7		;初始在缓冲区的偏移量,逆向存储,正向读取
	mov ecx,8		;8字节循环8次
	mov ebx,put_int_buffer
	
.16based_4bits:		;按位处理16进制数字并逆序
	and edx,0x0000000f
	cmp edx,9
	jg .is_A_F		;大于9,是16进制a-f,转化成相应的字符
	
	add edx,'0'		;如果小于9,是数字,转化成字符0-9
	jmp .store
	
.is_A_F:
	sub edx,10
	add edx,'A'
	
.store:
	mov [ebx+edi],al
	dec edi			;缓冲区指针自减
	shr eax,4		;右移4位相当于16进制右移一位,最低位变成下一个要处理的数字
	mov edx,eax		;转移给edx
    loop .16based_4bits
    
.ready_to_print:
	inc edi			;目前是-1,经过这一步变成0
.skip_prefix_0:		;去除前导零
	cmp edi,8
	je .full0		;全0
	
.go_on_skip:
	mov cl,[put_int_buffer+edi]
	inc edi
	cmp cl,0
	je .skip_prefix_0	;如果本位是0,返回,检查下一位是不是0
	dec edi			;本位不是0,需要把指针回溯
	jmp .put_each_num
	
.full0:
	mov cl,'0'		;全0只需要打印一个0
.put_each_num:
	push ecx
	call put_char
	
	add esp,4
	inc edi
	mov cl,[put_int_buffer+edi]
	cmp edi,8
	jl .put_each_num
	
	popad
	ret

内联汇编

c语言只支持at&a语法。

intel和at&a汇编风格对比

基本内联汇编

模板:asm [volatile] ("assembly code")

说明:

  • asm用于声明是内联汇编表达式。
  • volatile可选写不写,作用是声明不要进行O优化,原样保留我的代码。
  • 整个代码体必须被括号括起来。
  • 指令必须被双引号括起来。
  • 除了最后一个指令,每个指令结束必须要用;\n\n\t间隔。
  • 一对双引号不能跨行,如果跨行用反斜杠\转义。
  • 如果汇编代码要引用c语言变量,c语言变量必须定义为全局变量

扩展内联汇编

扩展内联汇编解决两个问题:

  1. 在内联汇编代码插入点之前的 C 代码,其编译后也要被分配寄存器等资源,插入的汇编代码也要使用寄存器,这是否会造成资源冲突?
  2. 汇编语言如何访问 C 代码中的变量?

模板:asm [volatile] (“assembly code” :output :input :clobber/modify)

新增部分说明:

  • 圆括号里4部分均可省略,省略要保留:占位,但是如果省略了后面一部分或者连续的多部分,可以不保留:。

  • output: output用来指定汇编代码的数据如何输出给 C 代码使用。内嵌的汇编指令运行结束后,如果想将运行结果存储到 c 变量中,就用此项指定输出的位置。output 中每个操作数的格式为:

    “操作数修饰符约束名”(C 变量名)

    其中的引号和圆括号不能少,操作数修饰符通常为等号’=‘。多个操作数之间用逗号’,'分隔。

  • input:input 用来指定 C 中数据如何输入给汇编使用。要想让汇编使用 C 中的变量作为参数,就要在此指定。input 中每个操作数的格式为:

    “[操作数修饰符] 约束名”(C 变量名)

    其中的引号和圆括号不能少,操作数修饰符为可选项。多个操作数之间用逗号’,'分隔。

  • 单独强调一下,以上的 output()和 input()括号中的是 C 代码中的变量,output(c 变量)和 input(c 变量)就像 C 语言中的函数,将 C 变量(值或变量地址)转换成汇编代码的操作数。

  • clobber/modify:汇编代码执行后会破坏一些内存或寄存器资源,通过此项通知编译器,可能造成寄存器或内存数据的破坏,这样 gcc 就知道哪些寄存器或内存需要提前保护起来

  • assembly code 中引用的所有操作数其实是经过 gcc 转换后的复本,“原件”都是在 output 和 input 括号中的 c 变量

操作数:寄存器名、内存地址、立即数等

约束:用来描述c语言操作数如何变为汇编语言操作数,分为寄存器约束、内存约束、立即数约束、通用约束四类,具体看p285页。

占位符:用来引用汇编操作数,分为序号占位符和名称占位符。(个人感觉可以类比c语言prinf、scanf里面的占位符)

序号占位符:%1、%2等,对应后面input里面的操作数

名称占位符:相当于“引用”,格式是[名称]"约束名"(C 变量),使用时直接%[名称]。

操作数修饰符:这部分请看P290页。

clobber/modify:声明汇编代码修改内存/寄存器等,P293页。


实现中断程序

先贴一下刚弄完没调试时的情况吧。idt表没问题,但是系统打印部分有问题。

有几个问题:1.滚屏出错,看不到int vector 0x20 2.光标位置出错

最后完善好的中断程序截图,完善了IDT和时钟相关。

顺带写一下编译相关代码

gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -o build/timer.o device/timer.c
gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/main.o kernel/main.c
gcc -m32 -I lib/k ernel/ -m32 -I lib/ -m32 -I kernel/ -c -fno-builtin -o build/interrupt.o kernel/interrupt.c
gcc -m32 -I lib/kernel/ -m32 -I lib/ -m32 -I kernel/ -I device/ -c -fno-builtin -o build/init.o kernel/init.c
nasm -f elf -o build/print.o lib/kernel/print.S
nasm -f elf -o build/kernel.o kernel/kernel.S

ld -m elf_i386 -Ttext 0xc0001500 -e main -o build/kernel.bin build/main.o build/init.o build/interrupt.o  \
build/print.o build/kernel.o build/timer.o


dd if=/home/hongbai/bochs/build/kernel.bin of=/home/hongbai/bochs/bin/c.img bs=512 count=200 seek=10 conv=notrunc

cd bin
./bochs -f bochsrc.disk

结语

第七章cv的代码不少,大家可以参考love6的博客。

等第八章学完会写一下上周的周报总结。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值