[求助]FH35板子时间问题

来源:互联网 发布:发论文数据可以造假吗 编辑:程序博客网 时间:2024/05/22 07:01

 调试中发现一个问题:
FH35板子启动后的时候并不是1970-1-1 0:0,而是1969年11月10日

将FH35板子时间设置为正常时间后,出现以下情况:
FH35板子:
调用time()返回time_t值为1245247783
调用gettimeofday()获得的值也是1245247783,并且timezone结构的tz_minuteswest和tz_dsttime都为0
调用localtime解析出来的时间是2009-4-27 12:28:2(其中year+1900,month+1)时间是正常时间

虚拟机linux系统:
调用time()返回time_t值为1240806757
调用gettimeofday()获得的值也是1240806757,并且timezone结构的tz_minuteswest=-480,tz_dsttime=0(与格林威治时间相差8个小时,这是正确的,因为linux使用的是北京时间)
调用localtime解析出来的时间是2009-4-27 12:32:3720(其中year+1900,month+1)时间是正常时间

这里就有问题了,调用time()返回值不一样,而解析出来的时间却是一样的
time(取得目前的时间)  
相关函数  ctime,ftime,gettimeofday
表头文件  #include<time.h>
定义函数  time_t time(time_t *t);
函数说明  此函数会返回从公元1970年1月1日的UTC时间从0时0分0秒算起到现在所经过的秒数。如果t 并非空指针的话,此函数也会将返回值存到t指针所指的内存。
返回值  成功则返回秒数,失败则返回((time_t)-1)值,错误原因存于errno中。

怀疑是时区问题,当时HI3510的板子使用的是格林威治时间,而pc使用的是北京时间,相差8个小时
但是若是时区问题,也不会相差50天如此之多
阿广说有可能与cpu频率有关,这一点我不太明白

 

 

 

 

 

 

 

 

 

 

分析:
busybox里面的date命令打印的时间是1969年11月10日,由此(busybox/coreutils/date.c)入手。

1)time函数是正确的。(在没有实时钟的情况下,time函数返回的是开机以来的秒数)
2)继续跟踪localtime函数
typedef struct {
        long gmt_offset;
        ……
        char tzname[TZNAME_MAX+1];
} rule_struct;
rule_struct _time_tzinfo[2];

问题出在localtime函数,在设置默认时区的时候,本应该把"UTC字"字符串copy到_time_tzinfo结构的tzname元素,结果写到gmt_offset元素了。
U=0x55, T=0x54,C=0x43,所以产生了0x00435455(注:ARC是小端序)=4412501秒=51.0706天的差数。

根源:
此问题的根源在于连接后处理程序elf2flt。
elf2flt在静态重定位的时候,早先的版本把所有访问结构体变量元素的操作都误作访问结构体变量起始地址。
这个bug只作用于未赋初值、也非static的结构体变量。

解决:
elf2flt 4.1.0以上版本已经解决。

附注:
elf2flt是为non-MMU的CPU动态重定位而准备的。它做的工作是:
1)
把elf文件中的文本(text)、数据(data)抽出来后,在末尾附上一张表,形成flt文件。
表中每4个字节代表text中的一个偏移地址,指明该文本地址处引用了一个变量,需要在linux-kernel加载的时候修改(动态重定位)。
因为linux-kernel把text和data加载到不同的内存位置(这和vxworks、OS21等嵌入式OS不一样:嵌入式OS加载的时候,1)text和data是紧挨着连续的存放,2)加载地址在link的时候是确定的,如ld -e -T等参数。所以不用重定位)

2)
原本的elf文件此处的值是0,
elf2flt需要通过解析elf文件找到它要访问的变量地址,
计算得到在flt文件中的偏移作为初值,然后修正text段。
我姑且称之为静态重定位。

4)举一个例子。
extern int var1, var2;
foo()
{
var1 = 5;
……
var2 = 3;
}
假如:
foo函数访问var1变量这条指令在最终binary code中的偏移是0x150,变量var1的偏移是0x6F24
foo函数访问var2变量这条指令在最终binary code中的偏移是0x160,变量var2的偏移是0x6F7C;
整个binary code大小是0x7000。
那么,elf2flt要做的事就是:
在flt文件的0x150处写0x6F24,在0x7000处添加一个32位数0x150
在flt文件的0x160处写0x6F7C,在0x7004处添加一个32位数0x160。

linux加载此程序时,
把text段copy到一个基址(假如是0x40710000),
把data段copy到一个基址(假如是0x40820000),
然后遍历整个表。
对表中的每一个元素(偏移地址),以0x150为例:
找到文本段相应的内存地址(0x40710000+0x150),修改这个地址的内容:
*(ulong *)(0x40710000+0x150)= 0x40820000 + 0x6F24
也即
*(ulong *)(0x40710000+0x150)+= 0x40820000
这样在程序开始运行之前,0x150处的指令就能够访问正确的重定位后的数据地址了。

原创粉丝点击