`
spartan1
  • 浏览: 365889 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

ucore-project4: interrupt -- 内嵌汇编在-Os优化时出错分析

 
阅读更多

为了打印数字,将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执行汇编指令,时刻敏锐地分析代码执行会有什么问题。多做这种练习,锻炼自己的思维能力,对自己的程序写作、分析能力以及问题定位能力会有很大提升。并且也可以锻炼克服困难、踏踏实实的品质。

分享到:
评论

相关推荐

    离散数学课后题答案+sdut往年试卷+复习提纲资料

    离散数学课后题答案+sdut往年试卷+复习提纲资料

    智能点阵笔项目源代码全套技术资料.zip

    智能点阵笔项目源代码全套技术资料.zip

    英文字母手语图像分类数据集【已标注,约26,000张数据】

    英文字母手语图像分类数据集【已标注,约26,000张数据】 分类个数【28】:a、b、c等【具体查看json文件】 划分了训练集、测试集。存放各自的同一类数据图片。如果想可视化数据集,可以运行资源中的show脚本。 CNN分类网络改进:https://blog.csdn.net/qq_44886601/category_12858320.html 【更多图像分类、图像分割(医学)、目标检测(yolo)的项目以及相应网络的改进,可以参考本人主页:https://blog.csdn.net/qq_44886601/category_12803200.html】

    (31687028)PID控制器matlab仿真.zip

    标题中的“PID控制器matlab仿真.zip”指的是一个包含PID控制器在MATLAB环境下进行仿真的资源包。PID(比例-积分-微分)控制器是一种广泛应用的自动控制算法,它通过结合当前误差、过去误差的积分和误差变化率的微分来调整系统输出,以达到期望的控制效果。MATLAB是一款强大的数学计算软件,而Simulink是MATLAB的一个扩展模块,专门用于建模和仿真复杂的动态系统。 描述中提到,“PID控制器——MATLAB/Simulink仿真以及性能比较与分析”表明这个资源包不仅提供了PID控制器的模型,还可能包括对不同参数配置下的性能比较和分析。博主分享的是“最新升级版框架的Simulink文件”,意味着这些文件基于最新的MATLAB版本进行了优化,确保了与不同版本的MATLAB(从2015a到2020a共11个版本)的兼容性,这为用户提供了广泛的应用范围。 标签中的“PID”、“matlab”、“simulink”、“博文附件”和“多版本适用”进一步细化了内容的关键点。这表示该资源包是博客文章的附加材料,专门针对PID控制器在MATLAB的Simulink环境中进行仿真实验。多

    MATLAB代码:考虑P2G和碳捕集设备的热电联供综合能源系统优化调度模型 关键词:碳捕集 综合能源系统 电转气P2G 热电联产 低碳调度 参考文档:Modeling and Optimiza

    MATLAB代码:考虑P2G和碳捕集设备的热电联供综合能源系统优化调度模型 关键词:碳捕集 综合能源系统 电转气P2G 热电联产 低碳调度 参考文档:《Modeling and Optimization of Combined Heat and Power with Power-to-Gas and Carbon Capture System in Integrated Energy System》完美复现 仿真平台:MATLAB yalmip+gurobi 主要内容:代码主要做的是一个考虑电转气P2G和碳捕集设备的热电联供综合能源系统优化调度模型,模型耦合CHP热电联产单元、电转气单元以及碳捕集单元,并重点考虑了碳交易机制,建立了综合能源系统运行优化模型,模型为非线性模型,采用yalmip加ipopt对其进行高效求解,该模型还考虑了碳排放和碳交易,是学习低碳经济调度必备程序 代码非常精品,注释保姆级 这段代码是一个用于能源系统中的综合能源系统(Integrated Energy System)建模和优化的程序。它使用了MATLAB的优化工具箱和SDP(半定规划)变量来定义决策变

    中国飞行器设计大赛圆筒权重文件

    中国飞行器设计大赛圆筒权重文件

    java毕设项目之ssm社区文化宣传网站+jsp(完整前后端+说明文档+mysql+lw).zip

    项目包含完整前后端源码和数据库文件 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/idea Maven包:Maven3.3 服务器:tomcat7

    风光储、风光储并网直流微电网simulink仿真模型 系统由光伏发电系统、风力发电系统、混合储能系统(可单独储能系统)、逆变器VSR+大电网构成 光伏系统采用扰动观察法实现mppt控

    风光储、风光储并网直流微电网simulink仿真模型。 系统由光伏发电系统、风力发电系统、混合储能系统(可单独储能系统)、逆变器VSR+大电网构成。 光伏系统采用扰动观察法实现mppt控制,经过boost电路并入母线; 风机采用最佳叶尖速比实现mppt控制,风力发电系统中pmsg采用零d轴控制实现功率输出,通过三相电压型pwm变器整流并入母线; 混合储能由蓄电池和超级电容构成,通过双向DCDC变器并入母线,并采用低通滤波器实现功率分配,超级电容响应高频功率分量,蓄电池响应低频功率分量,有限抑制系统中功率波动,且符合储能的各自特性。 并网逆变器VSR采用PQ控制实现功率入网 以下是视频讲解文案: 接下来我来介绍一下 就是这个风光储直流微电网 整个仿真系统的一些架构啊 然后按照需求呢正常的讲一些 多讲一些 就是储能的这块的 还有这个并网的 三相两电瓶调的这个 并网继变器的这个模块 首先就是来介绍一下呃 整个系统的一个架构 你可以看到这个系统的架构 分别有四大部分组成 最左边的这块就是混合储能啊 这边这个是蓄电池 这个超级电容 他们都是

    ajax发请求示例.txt

    ajax发请求示例.txt

    深圳建筑安装公司“电工安全技术操作规程”.docx

    深圳建筑安装公司“电工安全技术操作规程”

    220) Vinkmag - 多概念创意报纸新闻杂志 WordPress v5.0.zip

    220) Vinkmag - 多概念创意报纸新闻杂志 WordPress v5.0.zip

    智力残疾评定标准一览表.docx

    智力残疾评定标准一览表.docx

    MDIN380 SDI转VGA 转LVDS VGA转SDI 高清视频处理 MDIN380芯片 PCB代码方案资料 3G-SDI转VGA ?3G-SDI转LVDS ?高清视频 MDIN380、GV76

    MDIN380 SDI转VGA 转LVDS VGA转SDI 高清视频处理 MDIN380芯片 PCB代码方案资料 3G-SDI转VGA ?3G-SDI转LVDS ?高清视频 MDIN380、GV7601 芯片方案(PCB图和源码)。 此方案是韩国视频处理芯片MDIN380的整合应用方案。 3G-SDI转VGA或3G-SDI转LVDS。 方案共有两块电路板(一块底板,一块MDIN380核心板 四层板)。 MDIN380和GV7601 都是BGA封装,最好有焊接BGA经验才拿。 另外有视频处理方面其它需要可联系我定制开发。 其它视频格式转,视频图像分割、拼接等可定制开发。 方案资料含有源码、PCB图。 方案已有成熟产品在应用。 注意该资料没有原理图,只有PCB图。 代码环境编译KEIL4。 画图软件Protel99、AD10。 电子文档资料

    YOLO算法-锡罐-牙罐-盖子打开数据集-179张图像带标签-锡罐-牙罐-盖子打开.zip

    YOLO系列算法目标检测数据集,包含标签,可以直接训练模型和验证测试,数据集已经划分好,包含数据集配置文件data.yaml,适用yolov5,yolov8,yolov9,yolov7,yolov10,yolo11算法; 包含两种标签格:yolo格式(txt文件)和voc格式(xml文件),分别保存在两个文件夹中,文件名末尾是部分类别名称; yolo格式:<class> <x_center> <y_center> <width> <height>, 其中: <class> 是目标的类别索引(从0开始)。 <x_center> 和 <y_center> 是目标框中心点的x和y坐标,这些坐标是相对于图像宽度和高度的比例值,范围在0到1之间。 <width> 和 <height> 是目标框的宽度和高度,也是相对于图像宽度和高度的比例值; 【注】可以下拉页面,在资源详情处查看标签具体内容;

    G120 EPOS基本定位功能关键点系列-堆垛机报F7452追踪原因.mp4

    G120 EPOS基本定位功能关键点系列_堆垛机报F7452追踪原因.mp4

    java毕设项目之ssm亚盛汽车配件销售业绩管理统+jsp(完整前后端+说明文档+mysql+lw).zip

    项目包含完整前后端源码和数据库文件 环境说明: 开发语言:Java 框架:ssm,mybatis JDK版本:JDK1.8 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/idea Maven包:Maven3.3 服务器:tomcat7

    zigbee CC2530无线自组网协议栈系统代码实现协调器与终端基于GenericApp的无线收发例程.zip

    1、嵌入式物联网单片机项目开发例程,简单、方便、好用,节省开发时间。 2、代码使用IAR软件开发,当前在CC2530上运行,如果是其他型号芯片,请自行移植。 3、软件下载时,请注意接上硬件,并确认烧录器连接正常。 4、有偿指导v:wulianjishu666; 5、如果接入其他传感器,请查看账号发布的其他资料。 6、单片机与模块的接线,在代码当中均有定义,请自行对照。 7、若硬件有差异,请根据自身情况调整代码,程序仅供参考学习。 8、代码有注释说明,请耐心阅读。 9、例程具有一定专业性,非专业人士请谨慎操作。

    基于小程序的小区物业新冠疫情物资管理平台小程序源代码(java+小程序+mysql+LW).zip

    系统可以提供信息显示和相应服务,其管理小区物业新冠疫情物资管理平台信息,查看小区物业新冠疫情物资管理平台信息,管理小区物业新冠疫情物资管理平台。 项目包含完整前后端源码和数据库文件 环境说明: 开发语言:Java JDK版本:JDK1.8 数据库:mysql 5.7 数据库工具:Navicat11 开发软件:eclipse/idea Maven包:Maven3.3 部署容器:tomcat7 小程序开发工具:hbuildx/微信开发者工具

    亲测源码云赏V7.0微信视频打赏系统源码已测试完整无错版

    云赏V7.0包括V6的所有功能外,全新UI设计,代理可以选择8种风格,添加后台统计等多种功能。 1基本设置(网站基础信息配置、包括主域名、防封尾缀、url.cnt.cn短连接接口可切换); 2转跳域名(10层防守转跳,都输入的话,都会转跳到对应的地方在跳回来,在随机取用落地); 3落地域名(添加落地域名及设置默认落地域名); 4视频列表(添加视频批量添加外链视频给代理们获取); 5代理推广:代理使用推广链接发展下级代理,后台设置提成); 6代理列表(生成邀请码注册,手动添加代理); 7提现记录(用于结算代理们的提现); 8余额记录(记录代理的余额变动); 9订单记录(记录打赏数,今日收入)。 测试环境: Nginx 1.18+PHP56+MySQL5.6,详细教程见文件内文字教程。 后台账号:admin 密码:admin888

    深圳建设施工项目易燃、易爆、有毒、有害物品管理制度.docx

    深圳建设施工项目易燃、易爆、有毒、有害物品管理制度

Global site tag (gtag.js) - Google Analytics