- 浏览: 360089 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
abc08010051:
结果呢?烂尾跑路了?
关于actor模型的优缺点分析(1) -
qinhanlei:
hi, 感谢分享,受益匪浅! 顺便请问一下,您使用的是什么绘图 ...
skynet任务调度分析 -
maxer025:
楼主,github 地址?
WebIM第一版本及下一步工作 -
boyhailong:
博主的分析能力真是强 skynet的很多东西我表示还是看不太懂 ...
skynet任务调度分析 -
ranweizheng:
亲这篇里面没有说当(.class 元素 元素) 与( .cla ...
css样式表中的样式覆盖顺序
为了打印数字,将printf添加进去,结果打印出来乱码,并且是原来正确的、没有用printf打印出来的代码也变成了乱码。
使用readelf -e查看编译出来的kernel文件(kernel.out),发现代码是正确的,打印代码引用的打印字符串的地址处的确放着正确的打印字符串。
需要看到加载到内存后是什么样子,看来应该是读取内核到内存中出错了。不过以前读取内核没有问题啊?查看了以前读取的内核不到一个扇区,而现在内核代码有三个扇区那么大。重新看了一遍bootc.c代码,没有发现问题。
没有调试器真不方便啊,以前记得调试不了,加不了断点。对了,加不了断点是因为找不到symbol,img文件中没有说明symbol文件的位置,而img文件又不是一个合法的elf文件,gdb没法从img文件里拿到symbol信息(包括调试信息)。
好办,在进入gdb后,先执行symbol-file boot/boot.tmp将启动扇区代码的符号信息加载进来,再执行add-symbol-file kernel/kernel.out 0x100000将内核代码的符号信息加载进来。
之后target remote :1234, b start32asm, b main32c,b kstart,哈哈,加载没问题。
但是调试bootc.c的代码时出问题了,编译bootc.c时加了-Os选项,结果很多函数、局部变量为减小空间给优化没了,打印局部变量出来的是错误信息。而去掉-Os后,启动代码变为764字节,超出一个扇区大小。把输出的代码全干掉,还超,把启用A20代码简化,还超,最后把等待硬盘就绪的指令干掉(反正调试时时间足够),才把大小压缩到500字节。
ok,开始调试,呃,没有任何问题,一切正常。。。。
加上-Os,出错,去掉-Os,正常。。。gcc的优化会出错!!!!
gcc的优化都不能相信,还有什么是可以信任的呢?经过几个小时不断地调试和对比,最终找到了原因:
gcc优化绝大多数情况下是正确的,除非你使用了内嵌汇编,并且没有正确告诉gcc内嵌汇编中的汇编代码是怎么影响寄存器的。
出错地方的代码是这样的:
static void readsect(void *va, int sectno) { waitdisk(); outb(1, xxx); outb(xx,xx); outb(xx,xx); outb(xx,xx); outb(xx,xx); waitdisk(); insl(va, len, port); } static void readsegment(void *va, int size, int offset) { .... for (i=beginsect; i<=endsect; i++, va+=SECTSIZE) { readsect(va, i); } }
没有优化的时候没有任何问题,所有调用都是正常的。加上-Os优化后,readsect函数被优化掉了,内容直接放到readsegment的for循环中。很多局部变量都被优化掉,放在内部寄存器中。其中i被放到了ebx,而va被放到了edi:
mov $0x1f0, %edx mov $0x80, %ecx cld rep insl (%dx), %es:(%edi) inc %ebx add $0x200, %edi cmp -0x10(%ebp), %ebx jbe 7c5e pop %eax ....
看起来没什么问题。不过执行起来就完蛋了:
rep insl指令在执行过程中会增加edi的值,而后面仍然有一条add $0x200,%edi语句给edi加值,结果造成了拷贝扇区时,第一个扇区拷贝到0x100000~0x100200地址处,第二个扇区拷贝到0x100400~0x100600处,中间0x100200~0x100400空间被忽略过去了!
gcc为什么会这么傻?犯这种基本错误?难道优化就这么脆弱吗?慢着,ucore自己的代码没有问题啊,忽然想起来,insl是在C代码中的嵌入汇编语句,而这条指令在写的时候图简单,与ucore的相比少了很多东西(当时还为自己写的代码比ucore的简洁很多而偷偷得意来着):
static inline void insl(void *va, int size, int port) { asm("rep insl"::"D"(va),"c"(size),"d"(port)); }
static inline void insl(void *va, uint32_t size, uint32_t port) { asm("rep;insl" : "=D"(va), "=c"(size) : "d"(port), "0"(va), "1"(size) : "memory", "cc"); }
用ucore的代码加了-Os优化后出来的代码如下:
mov %esi, %edi mov $0x1f0, %edx mov $0x80, %ecx cld rep insl (%dx), %es:(%edi) inc %ebx add $0x200, %esi cmp -0x10(%ebp), %ebx jbe 7c5e pop %eax ....
可以看出,ucore生成的代码中,因为指示了edi会变(=D),从而使用esi,而不是edi来存放va,此时就没有任何问题了。对我的insl做如下修改:
static inline void insl(void *va, int size, int port) { asm("rep insl":"=D"(va),"=c"(size):"0"(va),"1"(size),"d"(port)); }
重新编译,这次可以成功运行了。
之后就好办了,printf打印出backspace通过串口传过去的值是127,而ctrl+H的值是8,ctrl+H可以实现退格,当程序收到127或8时,顺序打印8, 空格, 8三个字符,就可以完美实现backspace的效果。
总结一下:
1. gcc的优化逻辑基本不怎么认识嵌入汇编,所以嵌入汇编中一定要详细说明自己的输入输出,分别影响了什么,将这些信息告诉gcc后,gcc在优化时才能更好地与嵌入汇编进行配合。
2. 这个问题一直存在,不过最初内核大小不到一个扇区,不会有问题,而添加printf后,增加到4个扇区,该问题就暴露出来了
3. ld在连接内核时,使用的顺序是kernel/driver/console.o, kernel/start/start.o, kernel/printf/printf.o,其中新添加的printf代码在最后面,按理说即使printf有问题,也不应该影响到前面的代码。但要知道,程序编译后代码在一个section(.text),字符串常量在另一个section(.rodata), 连接时同名段会放在一起。这样,三个.o文件的.text合成一个大的.text section,而他们的.rodata合成一个大的.rodata section,放在.text后面。从而start.o代码中使用了.rodata中的字符串常量,仍然会受到影响。
4. 这次定位仍然严重依赖调试器,虽然搞明白了怎么用gdb调试qemu中的内核,但对自己发现问题的能力没有任何帮助。说白了,使用调试器就不动脑子了,只一步步看代码怎么执行,执行到哪里数据会变成什么样子,变成这个样子后好像不太对。。。这种分析方式实际上效率很低,并且对自己的能力没有任何提高。以前很多人说的很对:“要减少对调试器的使用”。多看代码,多静态分析代码,在脑子里模拟cpu执行汇编指令,时刻敏锐地分析代码执行会有什么问题。多做这种练习,锻炼自己的思维能力,对自己的程序写作、分析能力以及问题定位能力会有很大提升。并且也可以锻炼克服困难、踏踏实实的品质。
发表评论
-
go语言
2012-09-06 01:23 1877从学校里开始,一直是C语言的狂热支持者,刚开始工作的两年也一 ... -
准备承接infoQ的一些翻译的工作
2012-09-05 22:29 1731好好练练英语,看英文资料还是太慢,严重影响计算机的学习。 ... -
jQuery.post获取不到中文数据的问题
2012-05-13 23:10 2280PHP直接返回页面时,可以返回中文数据,但使用jQuery.p ... -
json解析
2012-05-13 20:47 2176哈哈,如果返回http消息 ... -
css样式表中的样式覆盖顺序
2012-05-13 15:42 17196刚才写zenktodo的时候, ... -
后续生活规划
2012-05-11 00:21 1450惭愧,刚浏览了xiaotie的 ... -
Builder模式
2012-01-21 22:17 1368学习rabbitmq,在看其java ... -
ucore-project5: mm(4)
2012-01-09 00:31 1459时隔近20天,终于搞定了一个问题。使用linker scrip ... -
ucore-project5: linker script
2011-12-22 00:00 1445要对内核进行页映射, ... -
ucore-project5:mm(3)
2011-12-21 23:29 1065paging由x86 cpu控制寄存器中的三个bit控制: ... -
ucore-project5: mm(2)
2011-12-20 00:27 1271看内核刚进入时加载临时gdt的代码: lgdt __gdtd ... -
ucore-project5: mm(1)
2011-12-19 01:30 1301project5到project9主要处理内存管理。 ... -
ucore-project4: 内核态和用户态切换(3)
2011-12-18 15:16 1860这是内核态和用户态切换的最后一篇,也是project4的最后一 ... -
ucore-project4: 内核态和用户态切换(2)
2011-12-18 13:14 2068用户态到内核态切换相对比较简单。用户态切换到内核态时,需要切换 ... -
ucore-project4: 内核态和用户态切换(1)
2011-12-18 12:24 3493终于又回来了。内核态 ... -
ucore-project4: interrupt--x86 cpu复习
2011-12-11 20:04 1382离上次更新ucore工程已经过去6天了。这几天工作比较忙,经常 ... -
ucore-project4: interrupt -- 搞定第一个中断:timer
2011-12-05 23:56 1679修改了代码中的一个bug,时钟终端终于正常了。 pro ... -
ucore-project4: interrupt
2011-12-05 07:55 1392中断处理程序总算调进去了,刚才调试主要有两个问题: 1. o ... -
电路图
2011-12-04 00:46 1261刚才在看怎样初始化时钟芯片8253。cpu通过执行out指令, ... -
我的操作系统的方向
2011-12-03 11:14 1175做操作系统到底是为了什么呢? 好玩,当然是一个很重要的 ...
相关推荐
突然看到出错信息中有“alc880”的字样,这是个声卡类型。尝试着将声卡关闭,重启系统。OK,搞定。 总结:安装linux系统经常会遇到安装完成之后,无法启动系统。很多情况是由于板载声卡、网卡、或是cpu 超线程功能...
Open Firmware Recommended Practice: Interrupt Mapping Version 0.9
SILICON IDE的工程文件,原理图,datasheet,工具,例程,等资料完整 This release contains the following components: * USB Interrupt Driver Example * USB Interrupt Firmware ...Project Name: F34x_USB_Interr
2-EXTI--interrupt_stm32f407_setting1l4_stm32f407固件库_源码.zip
including examples and demos for all USB transfer types (control, interrupt, bulk and isochronous). It supports all STM32 microcontroller families. The aim of the STM32 USB-FS-Device development kit ...
matlab由频域变时域的代码睡眠麻痹中断 一种检测睡眠麻痹的机器学习分类器 ...在没有PCA和陀螺仪的情况下针对新数据流优化分类器 完成上述每个步骤后,将Matlab重新编译为C代码 最后将代码加载到Ar
与 Tim Franklin 的工作相比,所有代码都在类定义下进行了封装。 进度条和中止按钮都可以在 uifigure 工作区中自由排列。 取消按钮提前退出积分,同时保留数据直到终止点。 程序 (main.m) 中包含一个示例实现 显然...
Sparrow OS是笔者历时一年半写的小型嵌入式操作系统,现已完成,并分享文档。 本文是系列文档之(十),更多内容请访问 http://blog.csdn.net/michael2012zhao
[ 4.023860] [mmc]: sdc2 set ios: clk 25000000Hz bm PP pm ON vdd 3.3V width 1 timing MMC-HS(SDR20) dt B [ 4.023929] [mmc]: mclk 0xf1c20090 0xc100000b [ 4.040272] VFP support v0.3: implementor 41 ...
详细描述了VXworks下对于中断的处理
stm32 单片机 产生1Mhz方波。可调,输出4路PWM,另加一个中断输出控制
stm32f407用固件库编写中断程序(即按键与LED灯的应用)
一本全面的关于IBM PC基本器件及编程的详细手册(英文)...Interrupt Services DOS/BIOS/EMS/Mouse Uncategorized/Miscellaneous Topics Tables and Formats used by DOS & BIOS Graphical ASCII table from QBasic
基于MSP430G2553控制的按键P1.3中断程序
采用DMA中断的方式收发数据采用DMA中断的方式收发数据
Uart-Intr-Ring-N76E003-S_interrupt_ring_uart_8051_memory_源码.rar
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
- Project/STM32F0xx_StdPeriph_Templates/stm32f0xx_conf.h Library Configuration file - Project/STM32F0xx_StdPeriph_Templates/stm32f0xx_it.c Interrupt handlers - Project/STM32F0xx_StdPeriph_Templates...
OpenLab-中断-示例OpenLab 平台的中断示例 - PIC 微控制器示例 1:示例代码 配置外部中断 INT0 以演示主程序和子程序之间处理器控制的转移。 示例 2:配置 PORTB 更改中断的... 示例 4:配置 UART 接收中断的示例代码。
自己编写的51汇编程序,亲测有效 程序名称:interrupt.asm 程序说明:74HC595驱动数码管动态显示例,通过按键触发外部中断,P3.2进行计数,P3.3清零,实验箱上完成 算法说明:由两片74HC595芯片分别驱动段和位,...