windows动态库的问题调试

windows的动态库有几个需要注意的地方,因为相比较linux的动态库而言,需要设置的地方实在太多了。

1、首先需要注意的是运行时库的模式的选择一定要一致的!

原因在于每个dll库的堆管理器都是建立在运行时库crt的副本的基础之上,而每一个库必然有一个运行时库的副本。这里涉及到几个选择问题。

第一,选择mt还是md的问题,

1)mt表示的是mutilt-thread single,表示的多线程的静态运行时库。如果选择这种模式,需要注意的是每个动态库在程序运行时使用的数据以及堆都是建立在各自的运行时库的副本的基础之上的,换句话说,就是各自使用各自的堆内存,因此每个库使用自己的内存都是老死不相往来的,只有在使用非动态库分配的内存(也即程序主体分配的内存)时才能真正做到通信和访问。如果谁要是越界,就可能存在这样一个风险,例如如果存在这样一种用法:动态库A提供的接口不仅给动态库B使用,还直接给程序主体使用;而此时若动态库A提供的接口中返回一个在其堆中分配的内存块的地址,然后是传给动态库B使用的,但是释放时则是在动态库B传给程序主体的main函数中去释放的,这是由于main使用的动态库A的运行时库的副本是与动态库B所依赖的动态库A的运行时库的副本是不一致的,因此就会出现指针的非法使用,释放了不正确的内存块地址,造成堆损坏。---这种用法的一种更隐蔽的错误用法是:并没有将动态库A的指针返回出去,而是提供了一系列可以操作内部内存堆块的函数接口;但是仍然会出现这样一种错误,即在上述动态库B中使用调用动态库A的接口分配内存去完成某些操作并存储数据,而在程序主体的main函数中去调用动态库A的接口去读取认为已经存储的数据然后操作该数据改写,但是此时由于两个接口调用的副本不一致!!!所以预期认为是一致的数据,其实是不一致的!!!最终造成的就是内存访问越界,野指针造成的错误简直可以是千奇百怪!!!

2)md表示multi-thread dll,表示的是多线程的动态运行时库。如果选用的是这种模式,那么同样的一个动态库,使用的都将是同一个运行时库的副本。上述例子中的动态库B和程序主体main函数调用动态库A中的接口时,使用的即同一个堆内存,这样就不会存在这种问题了。

第二、mdd还是md?或者mtd还是mt?

这里的mdd和mtd多出来的d就是debug。因为mdd和md的两个不同的功能库是可以正常编译链接的,和上述的mt和md一样,但是这样有什么风险?关键在于选定了不同的运行时库debug版本和release版本,可以看到不同模式下的运行时库的lib文件的都以及已经不同了,按照微软MSDN上提供的说明,这些lib文件会在运行时库链接到obj文件中去指示程序如何去解析查找外部的函数符号,既然是debug的,那么显然有很多保护措施,除了上述的解析符号相关,还有内存操作和分配方面的保护在每次分配内存的时候会多分配一些字节用来存储当前分配的信息,这些都会造成运行时的差异。在stackoverflow上也有人问这样混用有什么风险,没有具体说明明确的风险,但是这种内存操作检查和内存泄漏检查显然是有可能造成内存不一致的。另外这里值得怀疑的是,如果使用不同模式的运行时库,是不是也说明可能出现之前说的mt和md之间那种区别,因为他们映射到内存中的显然不是同一个dll!!!

所以最好的办法是:如果是mdd的就全用mdd的吧,或者全部md的,调试?谁告诉你md的这种release版本就不能添加生成调试信息,是的,一样可以然后继续苦逼的调试,坑爹的微软啊,搞这么多事干什么。

2、编译器版本一定要是一致的。vs2005 or vs2008 or vs2010 or vs2013编译出来的动态库?

就是说所有的库都要是一致的编译器编出来的,为什么?因为每个编译器的运行时库的版本都不一致,那么就会出现一个问题,不同编译器版本编译出来的运行时库其实共享的是不同的运行时库版本。如果运行时起来,很有可能接口是兼容的,在程序最终生成打包时是一样能正常编译链接运行的。但是运行时,不同库是使用的不同的运行时库的lib导致的兼容性问题,一样会让你的库出现莫名其妙的兼容问题,是的,就是这么坑爹。之前看过一篇英文文档说是可以将每次编译时的运行时库保存下来随库一起发布,让后续每个使用该库的都使用这个运行时库来进行编译链接,但是这样会不会太胡闹了一些,库多的时候,涉及到第三方巨多的时候,估计你就哭了,反正我觉得管理起来应该还是很有难度的。不过,这个方法我也没有找到哪里可以把IDE中的运行时库固定下来的地方,我们还是老老实实的在程序编译时对号口令一致用某个编译器就好了!!!

3、各个库的位数要一致。32位还是64位的库?

没错,现在内存一多,大家都开始向大家64迁移了,这似乎不差钱的内存啊,反正是客户的,哼哼。但是这样32位和64位很有可能会被大家忽略,一个不小心就变成了32位库和64位库齐飞。由于各种偏差可能会编译链接仍然可以顺利通过,但是跑起来之后你就等着哭吧。如何查看?有一个命令,同linux上可以通过file命令查看dll是否为32位的,如果是32位的库会有提示80x86 32-bit的显示字样。但是lib文件暂时没找到可以查看的地方。

4、函数符号表的lib文件和动态库dll文件是否一致(不仅外面名字一致,内部也要一致,要表里如一)

调试过程中出现了这样一个问题lib和dll文件名是一模一样的,除了文件后缀名。但是程序撒欢开跑的时候,每次都在加载动态库的时候说找不到对应的动态库。例如,libdependmd.lib和libdependmd.dll运行时,总是说找不到libdepend.dll。最后发现的原因是,由于加载的是 libdependmd.lib,而生成时编译输出的文件其实是 libdepend.lib但是给库时候某个小伙伴听说要区分md和mt就把库名改了,但是库名改了不是就没问题了,其实lib库文件里会把dll的名字也带在里面,链接时使用的lib就是这样告诉其他要使用的库,它所对应的库名的。具体查看方法是,可以用ultra工具打开lib文件,查看文件尾部其对应的asscii码中会有对应的dll的名称,再也不用担心lib和dll名称不一致了!!!

上述五个步骤基本可以把动态库中各种模式不匹配造成的问题排除了,后续工作就看你自己了!

时间: 2024-10-16 22:42:32

windows动态库的问题调试的相关文章

【转】分析Linux和windows动态库

原文地址:http://www.cnblogs.com/chio/archive/2008/11/13/1333119.html 摘要:动态链接库技术实现和设计程序常用的技术,在Windows和Linux系 统中都有动态库的概念,采用动态库可以有效的减少程序大小,节省空间,提高效率,增加程序的可扩展性,便于模块化管理.但不同操作系统的动态库由 于格式不同,在需要不同操作系统调用时需要进行动态库程序移植.本文分析和比较了两种操作系统动态库技术,并给出了将Visual C++编制的动态库移植到Lin

Linux和windows动态库

转载:http://www.cnblogs.com/chio/archive/2008/11/13/1333119.html 态链接库技术实现和设计程序常用的技术,在Windows和Linux系 统中都有动态库的概念,采用动态库可以有效的减少程序大小,节省空间,提高效率,增加程序的可扩展性,便于模块化管理.但不同操作系统的动态库由 于格式不同,在需要不同操作系统调用时需要进行动态库程序移植.本文分析和比较了两种操作系统动态库技术,并给出了将Visual C++编制的动态库移植到Linux上的方法

windows动态库与Linux动态库

Linux动态库和windows动态库的目的是基本一致的,但由于操作系统的不同,他们在许多方面还是不尽相同.但是尽管有差异Linux动态库的windows动态库还是可以移植的,有一些规则以及经验是必须的知道的. 两种系统动态库比较分析 Windows和Linux采用动态链接库技术 (1)动态库程序编写,在Windows系统下的执行文件格式是PE格式,动态库需要一个DllMain函数作为初始化的人口,通常在导出函数的声明时需要有_declspec(dllexport)关键字.Linux下的gcc编

linux和windows动态库加载路径区别

# linux和windows动态库加载路径区别 ### 简介------------------------------ linux加载动态库的路径是系统目录/lib和/usr/lib.- windows加载动态库的路径是本地目录下,然后再搜索windows/system和windows/system32目录 ### 备注------------------------------ linux加载动态库的路径方式,对于习惯windows开发的开发者是不太方便的.- 其实linux下可以设置从当

android 动态库死机调试方法 .

原地址:http://blog.csdn.net/andyhuabing/article/details/7074979 这两种方法都不是我发明了,都是网上一些高手公共出来的调试方法,无奈找不到出处的地方了,所以就在此总结一下,以方便android下的调试: 简要说明: android系统中调试Java非常容易,一般遇到错误都在logcat中打印出错时函数的调用关系,而C库中出错时只看到一些二进制信息,使用gdbserver调试环境搭建又比较复杂. 方法一:下在介绍一个简单的调试库的方法,当然需

Linux 生成可以调试的动态库(单步调试)

我们经常需要调试自己的动态库,但是不能跟踪到库的函数内部,按照下面的方法可以解决这个问题. 1.gcc -c -fPIC   src.c -g -rdynamic 2.gcc -shared -o libtest.so  src.o 这样其它工程在调用时库 libtest.so就可以在单步调试时,跟踪到库内部. 见下面例子: =======================生成动态库====================== =====================测试生成的库========

SQLite第四课 创建windows动态库

下载源码包两个: sqlite-dll-win32-x86-3081101.zip,里面提供了导出sqlite3的函数的文件sqlite3.def 主要用于生成LIB文件,确定链接使用 sqlite-preprocessed-3081101.zip,提供了源码文件,但是删除shell.c和tclsqlite3.c文件 1.新建win32控制台程序,名称sqlite3 2.选择生成DLL 3.解压压缩包,将sqlite-preprocessed-3081101的文件复制到工程文件夹下(除了shel

用Vs2013+VELT进行Linux开发:动态库

快乐虾 http://blog.csdn.net/lights_joy/ 欢迎转载,但请保留作者信息 本文适用于vs2013 + Visual EmbedLinux Tools 0.1.1 1.1    什么是VELT VELT的全称是Visual EmbedLinuxTools,它是一个与visual gdb类似的visual studio插件,用以辅助完成Linux开发.利用这个插件,将可以在visual studio的IDE中进行Linux应用程序的开发(包括编译和调试),也可以进行ubo

iOS 中的静态库与动态库,区别、制作和使用

如果我们有些功能要给别人用,但是又不想公开代码实现,比如高德地图.第三方登录分享等等,这时候我们就要打包成库了.库分静态库和动态库两种: 静态库:以.a 和 .framework为文件后缀名.动态库:以.tbd(之前叫.dylib) 和 .framework 为文件后缀名. 静态库与动态库的区别 静态库:链接时会被完整的复制到可执行文件中,被多次使用就有多份拷贝.动态库:链接时不复制,程序运行时由系统动态加载到内存,系统只加载一次,多个程序共用(如系统的UIKit.framework等),节省内