论坛首页 综合技术论坛

程序64位化带来的问题和思考

浏览 8368 次
该帖已经被评为精华帖
作者 正文
   发表时间:2006-10-19  
公司的一个产品需要转移到了Windows Vista 64上去,由于程序某一部分和Windows的一个AP紧密相连,而这个Windows AP已经64位化了,不得不将自己的程序也转到64位.
我原来不是负责这个产品的,由于项目很赶,所以被零时抽调去帮忙,遇到了一些问题,这里和大家分享下.
1. 指针和long的转换
这是最基本的处理部分,由于32位系统下地址是32位,所以很多代码里都会存在这样的转换:
void* pData;
LONG lData;
lData = (LONG)pData;
现在地址是64位了,所以原来的这种转换就会导致地址高4Byte丢弃的问题.
这种转换向来被认为不安全,但还是大量出现,实际程序员代码的时候只要用一个指针保留就可以,完全没有必要用一个long保留,同样的问题也会出现在函数指针的保留.
思考:
所谓的存在即合理的思维在作怪吧,很多程序员认为这么做程序运行的好好的,所以不管是否有风险还照样这么写,实际上改成安全写法代码多不了多少.
当然不排除很多程序员对16位、32位、64位完全没有概念的.
还有一点可能是微软的windows消息给人以误导,消息的WPARAM和LPARAM中常会夹带数据指针,然后强制类型转换,但是看一下它们的定义,其中隔了一层,虽然只是语法上的小小手脚,但是绝对是有先见之明, 而很多人只会依样画葫芦而未明白期间的巧妙.

2. PE Import和Export Table的变化
程序中用到了PE hack,由于之前有人发现vista 32下原来所需要替换的一个import table中的函数找不到了,结果竟然去修改了export table, 姑且不谈修改export table的危险吧,结果vista 64的时候发现PE格式有了小小的变更.
MS将Import table中的地址转成了64bit,但是export table却还是32bit,估计其认为代码不可能大于4GB吧,这样就会发现更改export table变得很难,因为不同的dll会被load在不同的地址段,其间差距会大于4GB,所以只有将自己的dll强制定义在和目标dll相同的4GB范围内.
回头来说这种更改是极其危险的,因为对于export table OS会尽量保持全局唯一,所以一旦你的dll退出未能正确恢复原有的值,会造成其他所有使用到这个dll的程序crash.
最终我发现需要hack的那个函数放在了delayload import table中,简单的修改就解决了问题.
如果这个问题最终找不到而还是采用修改export table的方法,那么就会很惨,测试部门已经发现了经常性的系统crash.
思考:
这里出现了弯路,这个弯路项目的时间压迫难辞其咎,但是程序员未能自己去分析问题是更大的问题,vista在很多方面都保留了很好的兼容性,去分析下windows的目录就会发现基本和xp区别不大,所以很多基础dll的功能也没有变化(这一点让我感觉到vista并未如其发表的那样70%代码重写),在分析dll的时候只要稍微仔细点就会找到问题很简单.
另一个问题就是MS在定义PE格式的时候的确有很高的前瞻性,很好的保持了松耦合的能力,其实PE格式在2001年后就基本没有什么大的更改,那时大家还基本没有64位的概念,这一点是需要学习的,但是同样对于export table没有扩展到64bit我还是保留意见,难道真的认为4GB不会超过?当年盖茨大叔不是宣称640KB就够了吗^.^

3. DelayLoad的问题
DelayLoad这个特性在VC6开始出现,一般大家不会去接触,包括我自己,要不是这次机会也不会去看.
推荐一篇文章
http://www.microsoft.com/msj/0200/hood/hood0200.aspx
有详细的阐述,有兴趣可以自己看一下,其实其原理很简单,主要是在使用到某个dll的接口的时候再去load这个dll,这样可以节约空间,因为有些dll中的接口可能在程序周期中永远不会用到, 而且如果某个dll没有,如果没有用到,那么整个程序也能继续执行.
这真的是一个巧妙的设定, 虽然在第一次呼叫的时候会有小小的性能损失,并且代码也会稍微大一点,但是可能会带来更大的空间节省.
但是随即带来的思考, 为什么这么好的一个东西会那么生疏呢?个人考虑有以下原因:
  1. 这种技术显然对于很多人来说过于底层了,有多少人在意编译出来的程序是怎么样存放,又是如何被加载运行的呢?
  2. DelayLoad带来的好处对很多人不可见,只要我的程序编译通过,并且可以正确执行就可以了,节省了那么些空间或者扩展兼容有必要考虑吗?
  3. 现在的硬件太好了,何必要去做这种优化呢?内存消耗多了,没什么嘛去买1GB内存插上不久解决了?
  4. 编译系统不够智能,可能Visual Studio做的更加智能些,自动去分析然后产生delay load会更好吧?
如此这样一个不错的技术可能慢慢被人们淡忘.

引申一个问题就是我们现在硬件越来越好,但是大家还是觉得不够用,为什么?这几天我在写另一篇文章,可惜一直很忙还未能完成,就是自己在反思分析这个问题.
   发表时间:2006-10-19  
DelayLoad的问题:
  大部分需要拥到delayload 不是出于设计上,基本上是被迫的时候多,我曾经就遇到过一个需要延时load dll的。实在找不到办法了才拥到delay load。
  不过从性能上考虑,delay load用的多了,程序启动速度会快。运行速度稍微会降下来不少。不过也是一次性。这种就看设计需要来决定是否要用了
0 请登录后投票
   发表时间:2006-10-19  
还好,java不需要考虑这些问题。JVM帮我们搞定一切。:)
0 请登录后投票
   发表时间:2006-10-19  
指针转成整形本来就是错误的方法,指针也不是很难看。

不过如果我没记错的话,几个基本的C整数类型的大小应该是平台相关的,不多于一次总线传输,这样32位系统上就不大于4字节,64位系统上不大于8字节。在这个前提下,long不大于8字节;int不大于4字节,short不大于2字节。微软的编译器我没测试过,在gcc下编译出来的64位程序,long的大小是8字节。没找到64位windows测试,你说的这个大写的LONG类型是Win SDK里面定义的吧,我查看的是mingw里面的附带的一份,直接用long typedef出来的。如果VC不是把long强制处理成32位的话,理论上讲把指针转成long型并没有截断,可能截断的是在128位机器上,现在好像还没造出来。。。我没有找到可用的64位windows和64位的VC编译器来测试,但猜想微软会照顾到这个标准的吧。
0 请登录后投票
   发表时间:2006-10-20  
MS的编译器定义如下
int和long 依然是32bit,所以相关的所有衍生定义也都是32bit,比如DWORD, LONG, INT等
64位的数据将沿用__int64来衍生定义,比如LONGLONG,DWORD_PTR等.
这样的好处就是原来的程序大部分无需更改
否则按照c原来的规范int需要跟着硬件位数而变的话造成的问题会更大.

还有楼上说long不大于8字节...我怎么记得long是强制4字节的呢 ...
0 请登录后投票
   发表时间:2006-10-20  
搞错了,C/C++标准没有对整数类型大小作强制性规定,其大小依赖于实现。ms编译器的确是把int和long都作4字节,gcc则取4和8。

http://www.microsoft.com/china/MSDN/library/Windev/64bit/MW6TWPchapter5.mspx?mfr=true

引用

由于数据类型 Int 和 Long 的长度保持不变(仍为 32 位),因此需要修改的代码数量非常少。通常,所涉及的代码行数应该不到总代码基的 1%。这与 Unix 不同,其中 Long 要迁移到 64 位
0 请登录后投票
   发表时间:2006-10-20  
A ‘plain’ int object has the natural size suggested by the architecture of the execution environment.
我的理解这里“natural size suggested by the architecture of the execution environment”应该是指操作系统或者说硬件的环境,而非编译器的实现
当然针对特殊应用修改int的大小也不是没有.
long的认识我是错了
0 请登录后投票
论坛首页 综合技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics