为什么不同系统不能兼容同一个已编译的可执行二进制文件?

一个可执行的二进制文件包含的不仅仅是机器指令,还包括各种数据、程序运行资源,机器指令只是其中的一部分。

一个可执行文件要被执行的时候,操作系统需要为其分配资源,这些资源包括:内存空间(物理的和虚拟的),进程、线程资源等等,其中可执行文件的机器指令一般都放在代码段(汇编语言里称之为text段),其它资源可能放到数据段以及其它段里,这里“段”(segment)可以大致的理解为一段内存范围。操作系统(Windows/Linux)需要知道这个可执行文件需要多大的内存,有多少个段,分别载入到哪些内存地址上。可执行文件需要告诉操作系统,要为可执行文件准备哪些东西它才能运行。

可执行文件在执行之前,操作系统要有一些准备工作,因为不同的操作系统,准备工作是不同的,所以可执行文件的格式不完全相同。Windows上大部分可执行文件为PE格式,Linux里大部分可执行文件为ELF格式。格式不同导致了不同的可执行文件无法跨平台直接使用。这是原因之一。

当然了,我见过网上有大神解决了一些格式不同的问题,但跨平台运行还需要解决另一个障碍,就是操作系统API不同。一个可执行文件所执行的绝大多数操作(比如:文件操作、输入输出、内存申请释放、任务调度等等)都需要与操作系统交互才能完成,而不同的操作系统使用这些操作的方法完全不同,所以这个障碍更难跨越。这是原因之二。

如果能解决以上两个原因,那么有些可执行文件理论上是可以跨Windows和Linux在x86平台上运行的,因为Intel和AMD的CPU里,主要的硬件指令(机器指令)是相同的,也就是说0101这种二进制数,是一样的。但是如果切换到ARM平台,会有更大的麻烦就是硬件指令也不同,那么就完全没办法了。

有没有可能有跨平台运行的可执行文件呢,理论上是存在的,过去的时候也有一些办法,但限制极多,比如Windows过去是支持COM格式的文件的,这个文件就没有文件头,大小不能超过64K,只能在一个16位环境里(真实的或者虚拟的)运行,是真正的裸二进制文件。Linux里某些BIN文件恰好也是裸二进制文件(有些BIN文件没有ELF头,但不是所有的BIN都是这样的)。经过一些配置以后BIN文件也是可以在Linux上运行的。于是某些精巧设计的COM/BIN文件可以在限制极多的情况下跨平台运行,但也许只能做计算,无法做输出,大小也只有64K大,并且如果要做稍微复杂点的操作,就需要两套机器代码实现。另外,很不幸的是64位环境里COM文件已经不再支持了。

主要的原因是格式不同API不同,前者更重要一些。

时间: 2024-10-05 13:29:51

为什么不同系统不能兼容同一个已编译的可执行二进制文件?的相关文章

hi3531 SDK已编译文件系统制作jffs2文件系统镜像并解决问题 .

一, 安装SDK 1.Hi3531 SDK包位置 在"Hi3531_V100R001***/01.software/board"目录下,您可以看到一个 Hi3531_SDK_Vx.x.x.x.tgz 的文件, 该文件就是Hi3531的软件开发包. 2.解压缩SDK包 在linux服务器上(或者一台装有linux的PC上,主流的linux发行版本均可以),使用命令:tar -zxf Hi3531_SDK_Vx.x.x.x.tgz , 解压缩该文件,可以得到一个Hi3531_SDK_Vx.

windows10下安装Microsoft Visual Studio 2013.4 Community enu中文语言包出错,提示“”程序兼容模式已打开.请将其关闭”的解决方法

原来win8系统用着有点慢,就选择重新安装系统,安装了win10预览版,感觉确实很不一样,呵呵.在安装了vs2013社区版后,默认是英文版的,因为英文不太好,需要安装简体中文语言包,但是安装时一直报“程序兼容模式已打开,请将其关闭然后重新运行安装程序”, 在使用兼容win8模式安装后仍然提示这个,郁闷了好几天,后来在网上找到一个解决办法,记录如下: 使用命令提示符打开vs_langpack.exe,在后面添加 /Uninstall,类似这样D:\tools\vslang>vs_langpack.

MIB Browser如何导入已编译的mib

开发过程中,如果需要来回在几套mib之间来回切换,每次都进行编译工作那将是一件很繁琐的事情,我们可以直接导入已经编译好的mib文件,避免重复的编译工作. 第一步,备份已经编译好的mib文件.    将当前已经编译好的SMIDB文件夹进行备份,如果有多套mib,就备份多套. 第二步,有冲突的可能时,我们要先删除旧的mib文件. 在mib tab页中点击unload all mib modules按钮.         点击“Run MG-SOFT MIB Compiler”按钮.        全

Error is 10055 由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作

今天上午,一个同事反映:某系统的某个通过socket来进行通信的服务无法连接上数据库里,在操作系统上用数据库的客户端测试数据库连接也出现这样的错误信息:Error is 10055 由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作. 经过检查,发现该程序是部署在一个前置机上,上边有一个通过SOCKET提供服务的程序,由于网络方面及程序设计本身存在一定缺陷,导致该程序需要通过一个小脚本来定时触发一次交易,以保障会话不会被超时断开.就这样,服务器上就会不断的有新的产生,由于程序或操作系统本身

Android系统源码下载与编译、刷机--Nexus6实测

前言 此博文记录一下Android从系统源码下载到刷机的全过程. (https://source.android.com/source/build-numbers.html 页面中列表信息找到自己设备对应的Android版本进行选择,博文中选择MOB301) 硬件:Google 亲儿子 Nexus6("shamu") Android系统:选择了Android官网上的MOB301对应的android-6.0.1_r42 驱动:自然就是MOB301_Nexus6对应的驱动了 编译系统:Ub

使用jd-gui+javassist修改已编译好的class文件

1.原因:因为公司代码管理不当导致源码丢失,只好已编译好的class文件进行修改 2.首先先在myeclipse中新建java项目并导入javassist 3.将需要修改的文件放到指定文件夹下 4..在项目中添加以下代码 package dtj; import javassist.ClassPool; import javassist.CtClass; import javassist.CtMethod; import javassist.NotFoundException; public cl

由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作--解决方法(CSDN手动迁移)

异常信息: System.Net.Sockets.SocketException (0x80004005): 由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作. 192.168.0.187:22 at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)   at System.Net.Sockets.Socket.Connect(EndPoint remot

no buffer space available、由于系统缓冲空间不足或队列已满,不能执行套接字上的操作

netstat -nat | find " " /c   查看连接数才2千多,怎么就报下面的错了 报以下错:(IE打开网站也打不开) no buffer space available(curl 报错). 由于系统缓冲空间不足或队列已满,不能执行套接字上的操作. 超出本地计算机网络适配器卡的名称限制 重启workstation服务.修改MaxUserPort值.修改TcpTimedWaitDelay值这些都不启作用 https://support.microsoft.com/zh-cn

Linux下已编译PHP增加扩展so的方法,关键phpize 和config.m4

LINUX下PHP已经编译,如何新增so扩展. 用到的一个sh:/usr/local/php5/bin/phpize 原理:用phpize在压缩包里面找到对应的对应的扩展文件夹,在里面执行phpize,具体步骤: PHP安装路径:/usr/local/php5 PHP源码路径:/home/default7/lamp/php-5.5.13 扩展假设zlib:/home/default7/lamp/php-5.5.13/ext/zlib 执行代码: ln -s /usr/local/php5/bin