今天测试MM,因为需要用python调用一个用C实现的函数,让我在linux下生成一个动态库文件供她加载。
当时心中有所警觉,linux下使用的gcc编译器,windows下是vc编译器。
当然这也并没有什么,只是名字不同而已,如果遵循同样的规范的话,两平台之间的二进制应该是可以调用的。
然而linux下的二进制文件格式为ELF,windows下的二进制文件格式为PE。
当然结果就是调用失败,识别不了此文件。
先说说为什么会识别不了此文件。
ELF格式的二进制文件是由一个个段(Segment)组成的,首部是一个文件头,文件头的最前面的4个字节被称为魔数,用于确认文件类型。操作系统加载可执行文件时就会判断魔数是否正确,不正确的话当然就会拒绝加载。
此处只是揣测,因为我也不清楚PE格式的文件是如何组成。但是在ELF格式的文件在文件头中还有一个type变量,用于标识此文件的真正类型(不是看文件扩展名啦,这才是真正判断的依据),想必两个平台之间若是有这个变量的话应该也是不同的取值。因此肯定是无法加载的
具体ELF文件格式的介绍这里就不多说了,否则得长篇大论了,网上资料很多,有兴趣的可以网上找找资料。
(为啥不说PE?因为PE我也没怎么去了解 哈哈)
这里就扯到了API与ABI(Application Binary Interface)
API其实是源代码级别的接口,而ABI是二进制层面的接口,因此ABI其实是比API的兼容程度更为严格?
为什么这么说?比如说,POSIX规定printf的原型,那么此函数在遵循POSIX标准的系统下都是一样的。但是无法保证在遵循POSIX标准下的系统下的二进制指令一致。
因为二进制指令是与硬件相关了,基本上不同架构的CPU,完成同一个功能的指令就可能不同。
比如说intel x86架构下调用printf的指令是call指令
而MIPS下是jal指令。
由于各种硬件平台,各种编译器,链接器的ABI不同,自然也导致我们的ABI互不兼容。 这里列举2个我们比较熟悉的影响ABI的因素:
1 内置类型的大小和在存储器的放置方式(大端,小端,对其方式等)
2 符号的命名和解析方式(如编译时函数名的修饰规则)