前言
我们知道写的代码中,函数、变量名在编译过后都是以地址的形式存在内存中,变量名、函数地址是具体内存地址的一个名字罢了,想个问题
- 工程编译完成,最后烧写到mcu中都是以S19的文件格式,变量名–>map文件–>hex–>S19之间的映射关系是什么样子的?
本笔记纯理论学习,待实战检验。
环境
编译器: ghs
硬件平台:RH850
以实际工程RH850 flash驱动为例子进行讲解
目的
学习S19文件如何把代码组织起来,烧到MCU中的过程。
map文件
工程中所有变量或函数的定义都能在map文件中找到对应的物理地址。cpu执行指令时就是在这些地址上。
flash库生成的代码都在特定的段内,其中的代码都是以如下声明,将代码放入特定的段中:
#pragma ghs section text=".R_EEL_Text"
其中R_EEL_TEXT段在ld文件中有定义
.R_FDL_Text : > .
.R_FDL_Const : > .
.R_EEL_Text : > .
.R_EEL_Const : > .
有了这2个定义后,编译出来的代码通过MAP文件查看代码所在的物理地址:
50 .R_FDL_Text 0009ac78 00001dce 7630 0063078
51 .R_FDL_Const 0009ca46 00000013 19 0064e46
52 .R_EEL_Text 0009ca5a 0000439a 17306 0064e5a
53 .R_EEL_Const 000a0df4 00000019 25 00691f4
附加知识:
FDL是针对data flash操作的函数库。
EEL是针对eeprom操作的函数库,EEL也是基于FDL实现的。
FCL是针对code flash操作的函数库,主要用于bootloader中给系统升级
以上三个库瑞萨官方都有提供。
0x0009ac78为R_FDL_Text段的其实地址,大小为7630字节。
继续查看其实地址存放的内容:
2863 .R_FDL_Text 0009ac78+00001a _R_FDL_Init
2864 .R_FDL_Text 0009ac92+0000f2 _R_FDL_InitVariables
2865 .R_FDL_Text 0009ad84+00012c _R_FDL_Execute
其实地址存放的为R_FDL_Init.
现在已经知道编译出来的代码最后存放rom中的物理地址。
那如何从hex文件或者S19文件里找出这些文件内容
S19文件
基本格式:
5个部分具体内容如下:
记录类型 记录长度 存储地址 代码/数据 校验和
记录类型:2个字符(即1个字节),用来描述记录的类型。
一共有8种类型:
S0:S格式文件的第一个记录,表示文件名(含路径),存储地址部分没有使用,以0000置位。此记录表示记录的开始,无需下载到MCU。
S1: 地址为2字节(4个字符)的记录。
S2: 地址为3字节的记录。
S3: 地址为4字节的记录。
网上有很多资料。
实际项目中截图:
S3 21 0009AC18 9F999FAB9F00BD9FCF9FE19FF39F05AF17AF29AF3BAF004DAF5FAF71 5D
S3 21 0009AC34 AF83AF95AFA7AFB9AFCBAF00DDAFEFAF01BF13BF25BF37BF49BF5BBF E0
S3 21 0009AC50 7D015CB08CEBDEFE9073B07F474D54002020206DB0FD145CB2067F09 B8
S3 21 0009AC6C 00E8660F0900E680F86096BC8207210063E7010003E080FF10000A08 CE
S3 21 0009AC88 015023E7010042063F008207217063E7010003E006C83A06100E0A00 40
S3 21 0009ACA4 00DAF5051A30003A80FF9C1041D241DA1B06ACFF89FD2B06600E0A00 D9
S3 21 0009ACC0 6B070100000AE0C9E24D2B06100E0A006BCF01002C06340E0A006C07 8F
S3 21 0009ACDC 01002D06380E0A006D0701002E06580E0A004E0700002F06590E0A00 B5
S3 21 0009ACF8 4F07000030065A0E0A00500700003106540E0A007107000032063C0E 3F
S3 21 0009AD14 0A00520700003306100E0A0033F701007198E099C21D2B06100E0A00 6B
实际没有空格,这里为了好区分
每个格式为
类型 余下字节数(2字符一个字节) 地址 数据 校验和
S3类型 后面有33个字节。
FDL的物理地址为 0x0009ac78, 那地址空间内容应该包含在这句中:
S3 21 0009AC6C 00E8660F0900E680F86096BC8207210063E7010003E080FF10000A08
0x0009ac78 – 0x0009ac6c = c (12) 所以9AC6C地址移动12个字节就,也就是0x0009AC78对应的内容:
8207210063E7010003E080FF10000A08
这些才是具体代码对应的二进制文内容,换言之,拿到这些就可以拿到读写删除flash了。
可以通过GHS调试工具查验上述地址上存的内容是否与这一致。
0x0009ac78地址的8个字节:
00 21 07 82 00 01 e7 63,
小端模式(高字节放在高地址)正好与上面对应,8207210063
所以从S19中,9ac78后截取7630个字节就是所有FDL 函数库的二进制文件。
这样可以单独升级使用。
在最终生成S19文件之间有个中间文件HEX,通过对应的HEX文件也可以拿到。
校验和
s19中每一样的最后2个字符(一个字节)为校验和,在发送的过程中,对端接收后可以通过校验和确保数据有没有问题
14451 S3 21 0009AC34 AF83AF95AFA7AFB9AFCBAF00DDAFEFAF01BF13BF25BF37BF49BF5BBF E0
14452 S3 21 0009AC50 7D015CB08CEBDEFE9073B07F474D54002020206DB0FD145CB2067F09 B8
14453 S3 21 0009AC6C 00E8660F0900E680F86096BC8207210063E7010003E080FF10000A08 CE
14454 S3 21 0009AC88 015023E7010042063F008207217063E7010003E006C83A06100E0A00 40
14455 S3 21 0009ACA4 00DAF5051A30003A80FF9C1041D241DA1B06ACFF89FD2B06600E0A00 D9
14456 S3 21 0009ACC0 6B070100000AE0C9E24D2B06100E0A006BCF01002C06340E0A006C07 8F
14457 S3 21 0009ACDC 01002D06380E0A006D0701002E06580E0A004E0700002F06590E0A00 B5
14458 S3 21 0009ACF8 4F07000030065A0E0A00500700003106540E0A007107000032063C0E 3F
14459 S3 21 0009AD14 0A00520700003306100E0A0033F701007198E099C21D2B06100E0A00 6B
hecksum(校验和):2个字符。这些字符当被配对并换算成16进制数据的时候形成了一个最低有效字符节,该字符节用来表达作为补充数据,地址和数据库的字符对所代表的(字节的)补码的byte总和。即计数值、地址场和数据场的若干字符以两个字符为一对,将它们相加求和,和的溢 出部分不计,只保留最低两位字符NN,checksum =0xFF-0xNN。(引用网络)
校验和: 2个字符(即1字节),校验数据,计算方法:
校验和 = 0Xff – (记录长度 + 存储地址 + 代码/数据)
第一行为例:
校验和0xE0 = 0xFF – (21+00+09+AC+34+AF+83+AF+95+AF+A7+AF+B9+AF+CB+AF+00+DD+AF+EF+AF+01+BF+13+BF+25+BF+37+BF+49+BF+5B+BF)
校验和0x6B = 0xFF – (21+00+09+AD+14+0A+00+52+07+00+00+33+06+10+0E+0A+00+33+F7+01+00+71+98+E0+99+C2+1D+2B+06+10+0E+0A+00)