1.现象
在ulp程序增加了一些逻辑之后,编译报错。编译器打印故障信息(rel too far)如下:
上网搜索之后,发现是编译器bug(编译器会差label 到引用直接打的文件地址偏移, 如果隔太远就会抛异常, 事实上这个机制并不合理)。官网给出的解决方案是将程序分成多文件,或者将引用的label声明为全局(global),或者直接注释掉编译器检查偏移相关部分代码(开源的好处,随便让你折腾)。
参考地址:
https://esp32.com/viewtopic.php?t=326
https://github.com/espressif/binutils-esp32ulp/issues/4
权衡之下决定使用分文件的方法。于是参考例程将逻辑分为多个汇编文件进行编译。顺利完成编译。开开心心的烧录测试,发现ulp程序起不来了。
2.漫漫调试路
2.1瞎子过河
刚开始以为是程序逻辑问题。于是一遍又一遍检查代码,分析逻辑(ulp下面运行汇编代码,没有打印,不抛异常,出了问题完全是盲调)。最终没有结果。只能回滚代码到可以运行版本,然后小心翼翼一点一点分逻辑。发现只要一分开就不能运行(程序逻辑没有变动,BTW,这个时候有撞墙的冲动)。
2.2无心插柳
来来回回折腾了几遍之后,手贱打印了程序符号表。发现无法运行的程序入口地址不为零(零地址处是引用的label)。猜想可能是入口地址不为零,或者跳转地址为零导致异常。
于是,打印可以运行的程序符号表进行对比,发现可以运行程序入口(entry)地址为零。
2.3柳暗花明
进一步研究发现,编译器按照源文件编译顺序保存符号表。于是调整源文件编译顺序进行验证。结果与预期一致,将程序入口所在文件顺序调整到第一个进行编译之后,程序入口地址为零,同时程序恢复正常运行,反之,无法正常运行。
3.总结
为避免不必要的问题。ulp下面程序入口函数一点要是对应文件的第一个函数。并且程序入口函数所在文件需要第一个编译。
编程不易,且行且珍惜!