当前位置: 首页 > news >正文

预学习

表达式生成器

如何生成成表达式, 同时不会使buf溢出?

如何过滤求值过程中有除0行为的表达式?
我们在表达式求值中约定, 所有运算都是无符号运算. 你知道为什么要这样约定吗? 如果进行有符号运算, 有可能会发生什么问题?

有符号运算的风险:

●未定义行为导致不可预测的结果
●编译器优化可能产生意外行为
●平台依赖性导致可移植性问题
●增加代码复杂性和测试难度

解决方法

使用snprintf而不是sprintf防止写缓冲区溢出导致程序崩溃
过滤除0表达式的方式就是粗暴地开启-Wall -Werror参数,因为生成的表达式属于字面量(literal constant),编译时就会计算表达式,如果含有除0的情况gcc就会执行失败,所以可以通过system返回值检测编译是否含有除0的情况
image

优美的退出

make run启动nemu后直接输入q退出,得到如下最后一行的错误:

Welcome to riscv32-NEMU!
For help, type "help"
(nemu) q
make: *** [/home/ics2024/nemu/scripts/native.mk:38: run] Error 1

是由于is_exit_status_bad函数返回了-1,main函数直接返回了此函数返回的结果,make检测到该可执行文件返回了-1,因此报错。

#include <utils.h>
NEMUState nemu_state = { .state = NEMU_STOP };
int is_exit_status_bad() {int good = (nemu_state.state == NEMU_END && nemu_state.halt_ret == 0) ||(nemu_state.state == NEMU_QUIT);return !good;
}

模拟器上程序的执行流程

当运行nemu的时候,是通过SDB这个“窗口”去运行和窥探客户程序的运行的:当键入c或si时的原理是一样的,都是调用cpu_exec(n),执行n条指令,n是一个无符号整数,传入-1的话变成无符号整数的最大值,可视为把指令不停地执行下去无停顿,否则执行完n条指令后程序会回到sdb_mainloop中等待下一条用户的sdb命令。
流程集中在调用execute(n)执行n条指令,因此来到execute函数中:

static void execute(uint64_t n) {Decode s;for (;n > 0; n --) {exec_once(&s, cpu.pc);g_nr_guest_inst ++;trace_and_difftest(&s, cpu.pc);if (nemu_state.state != NEMU_RUNNING) break;IFDEF(CONFIG_DEVICE, device_update());}
}

execute循环n次如下的流程:
●调用exec_once执行每条指令
●调用trace_and_difftest记录trace、执行difftest和检查watchpoint
●检查是否程序应该退出(运行到了最后一条指令或者别的原因退出)
●更新设备状态
现在只关注指令执行流程,因此接下来看exec_once的流程:
●调用isa_exec_once取指并执行,指令与架构相关
●将cpu.pc置为下一条应该执行的指令的地址,这个地址在s->dnpc中
●根据是否开启了itrace,将第一步执行的指令记录到s->logbuf中,然后会在trace_and_difftest中输出
关注isa_exec_once函数,这个函数传入一个Decode结构体,保存待取指令的地址pc、下一条指令的静态地址snpc=pc+4、下一条指令的动态地址dnpc,还有一个字段isa目前只保存待取指令的内容

int isa_exec_once(Decode *s) {s->isa.inst = inst_fetch(&s->snpc, 4);return decode_exec(s);
}

isa_exec_once执行流程如下:
●inst_fetch取指
●decode_exec译码并执行

int isa_exec_once(Decode *s) {s->isa.inst = inst_fetch(&s->snpc, 4);return decode_exec(s);
}

重点关注decode_exec,在这个函数中定义了一些宏比如INSTPAT_INST、INSTPAT_MATCH,还有其他一些函数比如decoce_operand,其他的文件decode.h等,这些都是为了译码服务的,集中在INSTPAT这个宏上:

#define INSTPAT(pattern, ...) do { \uint64_t key, mask, shift; \pattern_decode(pattern, STRLEN(pattern), &key, &mask, &shift); \if ((((uint64_t)INSTPAT_INST(s) >> shift) & mask) == key) { \INSTPAT_MATCH(s, ##__VA_ARGS__); \goto *(__instpat_end); \} \
} while (0)

INSTPAT这个宏流程如下:
●调用pattern_decode解析传入的第一个参数pattern
●检查指令是否匹配pattern
●如果匹配的话,使用INSTPAT_MATCH宏,其中调用decode_operand根据指令类型提取操作数、立即数等,并执行指令相应的运算(INSTPAT宏的最后一个参数),最后跳过下面的pattern,因为已经匹配成功,不用再检查别的pattern
最后decode_exec再做些收尾工作,比如将$0寄存器置0

token十六进制和十进制

(nemu) p 0x80000000
[src/monitor/sdb/expr.c:89 make_token] match rules[11] = "[0-9]+" at position 0 with len 1: 0
no match at position 1
0x80000000^
error: wrong expression 0x80000000

规则顺序的重要性:
1.词法分析是贪婪的 - 使用第一个匹配成功的规则
2.特异性优先 - 更具体、更长匹配的模式应该放在前面
3.前缀冲突 - 要避免较短模式"截胡"较长模式的匹配机会
4.语义正确性 - 错误的词法分析会导致整个表达式求值失败
在你的表达式中,0x[0-9a-fA-F]+ 必须放在 [0-9]+ 前面,否则所有十六进制数都会被错误地解析为十进制数 0 加上无法识别的后缀,导致表达式求值完全失败。

操作符的问题

在一个token表达式中寻找主运算符了:
●非运算符的token不是主运算符.
●出现在一对括号中的token不是主运算符. 注意到这里不会出现有括号包围整个表达式的情况, 因为这种情况已经在check_parentheses()相应的if块中被处理了.
●主运算符的优先级在表达式中是最低的. 这是因为主运算符是最后一步才进行的运算符.
●当有多个运算符的优先级都是最低时, 根据结合性, 最后被结合的运算符才是主运算符. 一个例子是1 + 2 + 3, 它的主运算符应该是右边的+.
要找出主运算符, 只需要将token表达式全部扫描一遍, 就可以按照上述方法唯一确定主运算符.
找到了正确的主运算符之后, 事情就变得很简单了: 先对分裂出来的两个子表达式进行递归求值, 然后再根据主运算符的类型对两个子表达式的值进行运算即可.

断点异常

image

异常处理机制配置错误

当ebreak指令触发断点异常时,PC跳转到了无效的异常处理程序地址(0x80000010),该地址包含无效指令0xdeadbe00,导致异常。
在RISC-V中,当ebreak异常发生时:
PC跳转到异常处理程序的入口地址
0x80000010处的内容0xdeadbe00 0x6b6b6b6b表明:这可能是初始化的内存区域
根本原因:执行ebreak后,nemu状态变为NEMU_END,后又因为监视点值发生变化使得nemu状态变为NEMU_STOP,所以使得pc到0x80000010,无效指令。

static void execute(uint64_t n) {// 定义解码结构Decode s;// 循环执行n条指令for (;n > 0; n --) {// 执行单条指令exec_once(&s, cpu.pc);// 增加客户机指令计数器g_nr_guest_inst ++;// 进行指令跟踪和差分测试trace_and_difftest(&s, cpu.pc);// 如果模拟器状态不是运行中,跳出循环if (nemu_state.state != NEMU_RUNNING) break;// 如果定义了设备编译选项,更新设备状态IFDEF(CONFIG_DEVICE, device_update());}
}

解决方案:

if (nemu_state.state == NEMU_RUNNING) {if (update_watchpoint() > 0) {nemu_state.state = NEMU_STOP;}}
http://www.jsqmd.com/news/46966/

相关文章:

  • 2025年热门的成都打印机行业内知名租赁公司排行榜
  • 深入解析:深度学习——Logistic回归中的梯度下降法
  • 2025 年知名的成都二手集装箱公司最新 TOP 排行榜
  • 2025-11-20
  • 2025 年热门海运集装箱行业知名厂家排行榜!
  • 完整教程:AtCoder真题及详细题解 ABC427C: Bipartize
  • 面向对象程序设计-前3次作业总结
  • [豪の算法奇妙冒险] 代码随想录算法训练营第三天 | 203-移除链表元素、707-设计链表、206-反转链表
  • 2025年11月北京/东城区/西城区/朝阳区/海淀区/丰台区/石景山区遗产继承律师,遗产咨询律所Top10专业推荐排行权威榜单
  • 2025年11月北京/东城区/西城区/朝阳区/海淀区/丰台区/石景山区遗产继承、遗产纠纷,遗产咨询律师事务所权威排行榜单:专业律所推荐与选择指南
  • hspice 写了一个振幅可变的电压源,并且可以进行直流偏执
  • 南屏晚钟
  • Linux初级命令练习:通过awk、sed如何批量创建用户
  • 详细介绍:压缩与缓存调优实战指南:从0到1根治性能瓶颈(四)
  • sqli-labs 1(Less-1-Less-10)新手解题思路 - 指南
  • PyMAF 2023 单张照片估计参数化人体
  • 实用指南:【设计模式】适配器模式(Adapter)
  • 完整教程:【人工智能】神经网络的优化器optimizer(四):Adam自适应动量优化器
  • 轻松速通:TTS播放、文件播放与录音的核心功能解析!
  • 2025 中国法兰阀门十大品牌推荐:密封升级 + 场景适配,优质厂家护航流体系统安全
  • FPGA专用CLKUSR时钟引脚严重警告——Cyclone 10 GX
  • OPCUA探讨(五)——客户端代码解读:监控变量值与报警
  • 2025 年度中国截止阀十大品牌推荐:绿色智造 + 特种工况突破,引领行业高质量发展
  • 修改DTS适配遥控用户码
  • nginx性能优化之tcp调优
  • 2025年11月安徽聚乙烯瓶、高阻隔瓶、聚酯瓶、农药瓶供应商排行榜:安徽金汇龙包装领跑行业
  • 2025年11月中国/安徽/聚乙烯瓶、高阻隔瓶、聚酯瓶、农药瓶厂家TOP10推荐:安徽金汇龙包装强势登顶
  • rich dataset 3D人体场景数据集
  • ICPC2025沈阳打铁日志
  • UModel 数据治理:运维世界模型构建实践