V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
Gav1nw
V2EX  ›  程序员

二进制文件和操作系统有联系吗?

  •  
  •   Gav1nw · 2023-01-19 22:41:45 +08:00 · 4548 次点击
    这是一个创建于 705 天前的主题,其中的信息可能已经有所发展或是发生改变。
    二进制文件和处理器架构有关,和操作系统呢?排除调用到特定操作系统运行库的情况,一个二进制文件可以同时在特定架构如 arm x86 等 的所有操作系统运行吗?
    38 条回复    2023-01-22 20:36:04 +08:00
    JingKeWu
        1
    JingKeWu  
       2023-01-19 22:43:48 +08:00
    应该不能 操作系统可运行程序 都是特定数据结构的二进制,不同操作系统 数据结构不一样
    SAGAN
        2
    SAGAN  
       2023-01-19 22:46:58 +08:00   ❤️ 1
    koast
        3
    koast  
       2023-01-19 22:47:28 +08:00   ❤️ 3
    这和系统的装载器有关系,它会根据文件头把对应位置的东西摆成特定的内存布局,修复外部连接的符号之类的,再跳转到入口执行。一般来说不可以,毕竟不同系统的 API 都不一样,但是再不用系统 API 的情况下,可以通过特殊方式修改 PE 文件头让 windows 和 linux 的加载器都能识别,然后就能运行了,但是可以实现的功能很有限。
    Gav1nw
        4
    Gav1nw  
    OP
       2023-01-19 22:48:35 +08:00 via iPhone
    比如 Java 常用的包管理器 maven macOS 和 windows 下只是启动文件不一样,但最终都指向同一个二进制文件
    0o0O0o0O0o
        5
    0o0O0o0O0o  
       2023-01-19 22:48:43 +08:00 via iPhone
    1. 有关联
    2. 有一些魔法 https://justine.lol/ape.html
    msg7086
        6
    msg7086  
       2023-01-19 22:53:49 +08:00
    @Gav1nw #4 Windows 的 java.exe 和 macOS 的 java 不是同一个二进制文件。
    adoal
        7
    adoal  
       2023-01-19 23:01:37 +08:00   ❤️ 1
    如果多花点心思精心去构造,可以得到一个在同架构 CPU 的好几个操作系统里都能跑的可执行文件。

    但是这是一种极端情况。构造出来的程序只能做简单的 PoC ,对于实际使用价值的程序来说,几乎不可能做到,因为一个实际使用价值的程序至少要依赖系统的动态链接库去干实际的活。
    loken2020
        8
    loken2020  
       2023-01-19 23:11:59 +08:00
    不行,二进制可执行文件里面都是机器码,不同 CPU 架构的机器码是不一样的。x86 跟 arm 的不一样。
    loken2020
        9
    loken2020  
       2023-01-19 23:12:52 +08:00
    操作系统本身也是一个可执行的二进制文件。操作系统也是由多条机器码(汇编指令)堆叠起来的。
    wtsamuel
        10
    wtsamuel  
       2023-01-19 23:20:04 +08:00
    不一定,万一程序用了 win 或者 linux 内核函数
    agagega
        11
    agagega  
       2023-01-19 23:26:28 +08:00 via iPhone
    同一个指令集架构,不同操作系统之间的 ABI 可能完全不一样。
    misaka19000
        12
    misaka19000  
       2023-01-19 23:39:10 +08:00
    不可以哦

    CPU 决定的是指令,不同 CPU 对应的程序的指令(也就是汇编语言或者机器语言机器码)是不一样
    同时,不同的操作系统的系统调用( systemcall ,例如 int 0x80 中断)是不一样的;不同操作系统的程序封装格式也是不一样的,例如 Windows 程序的封装格式是 PE ,Linux 是 ELF 格式,不同操作系统解析程序的方式不一样
    misaka19000
        13
    misaka19000  
       2023-01-19 23:40:27 +08:00   ❤️ 1
    jim9606
        14
    jim9606  
       2023-01-19 23:40:53 +08:00
    一般是不能,无法避免与操作系统打交道的。
    裸机程序倒是可以,参考裸机 hello world

    https://zhuanlan.zhihu.com/p/420610342

    好像还有一种混合二进制,将 bsd 和 linux 的代码段混合在一个 ELF 里面,但做不到任意 OS ,至少 Windows 这种不使用 ELF 格式的就不好搞。
    AzadCypress
        15
    AzadCypress  
       2023-01-19 23:45:59 +08:00 via Android
    linux 可执行文件文件是 elf 格式 windows 是 pe 格式
    详细的可以看 [程序员的自我修养:链接、装载与库]这本书
    levelworm
        16
    levelworm  
       2023-01-20 00:01:59 +08:00
    如果设计的比较精巧,那么某种情况下,同一个二进制文件的确可以在多个架构下运行。参加这篇文章:
    https://www.robertxiao.ca/hacking/defcon2018-assembly-polyglot/
    CEBBCAT
        17
    CEBBCAT  
       2023-01-20 00:14:27 +08:00 via iPhone   ❤️ 1
    发帖前 Google 了吗?
    Tink
        18
    Tink  
       2023-01-20 01:06:07 +08:00
    二楼发的那个有点意思啊
    dcsuibian
        19
    dcsuibian  
       2023-01-20 04:56:07 +08:00
    Maven 本身就是用 Java 写的,和.class 程序或可执行.jar 没啥区别,所以要先装 Java 且设定好 JAVA_HOME

    虽然.class 是跨平台的,但它是要运行在 Java 虚拟机上的,而提供 Java 虚拟机的 JDK/JRE 程序不是跨平台的

    所以你在下载 JDK/JRE 的时候要指定操作系统、架构,下载 Maven 、ZooKeepr 、JMeter 等的时候不会区分什么系统
    fzdwx
        20
    fzdwx  
       2023-01-20 08:04:28 +08:00 via Android
    可以了解下指令集?
    yehoshua
        21
    yehoshua  
       2023-01-20 09:48:35 +08:00 via Android
    不同 CPU 平台不行,指令集都不同。二进制代码,汇编这东西,和硬件关系很大。操作系统反而影响没有硬件强。
    yuezk
        22
    yuezk  
       2023-01-20 10:29:09 +08:00   ❤️ 2
    这个帖子让我想到了前段时间看到的一篇关于 Wine 的文章([How Wine works 101]( https://werat.dev/blog/how-wine-works-101/),[中文译文]( https://www.freebuf.com/articles/system/346955.html))。

    实际上无论是什么操作系统,最终运行二进制文件都是 CPU 的工作,操作系统只是负责把二进制文件加载到 CPU 上去执行。而相同架构的 CPU 的指令又是一样的,所以理论上是可以把在 Windows 的编译的二进制文件移植到 Linux 上去的,

    再看二进制文件,它其实是有结构的,可以简单理解成由 header 和 body 组成。header 部分是给操作系统来读取进行加载的,这部分不同的操作系统之间是有差别的。body 部分是 CPU 的指令,是真正要运行的部分,这部分的内容是和操作系统无关的。

    所以可以这样理解,Wine 的主要工作是读取了二进制文件中的 body 部分,并加载到 CPU 运行。另外,它还 hook 了一些 Windows 上的系统函数,转成在的 Linux 里面的实现。

    所以,理论上来说,用 Wine 运行 Windows 的程序,其性能并不会比在 Windows 中差,甚至有的时候还会更快。
    yuezk
        23
    yuezk  
       2023-01-20 10:30:23 +08:00
    更新链接:How Wine works 101: https://werat.dev/blog/how-wine-works-101/
    bashbot
        24
    bashbot  
       2023-01-20 11:05:08 +08:00   ❤️ 1
    可执行二进制文件,排除 jar 和 pyc 这种解释执行,单说已经汇编成为机器指令的二进制文件,其中操作系统相关的有:
    操作系统内核提供的系统调用
    操作系统其他库提供的函数调用
    操作系统 ABI ,包括:二进制文件容器格式,二进制程序加载方式,函数参数和返回方式,等

    通过精巧的设计,可以实现很多兼容性。比如
    在 windows 上执行 linux 程序的 colinu
    在 linux 系统执行 windows 程序的 Longene

    甚至可以自定义 ABI ,然后实现各个平台的加载器,基础库,以及系统调用转发库。达到一次编译多平台运行的目的。

    另外,汇编成机器指令的二进制文件直接执行是 CPU 架构相关的,如果需要跨 CPU 架构,需要考虑解释执行。
    Gav1nw
        25
    Gav1nw  
    OP
       2023-01-20 12:01:05 +08:00 via iPhone
    我之前的理解只知道二进制文件和 CPU 架构的相容性,并没想过系统调用等和特定系统接口绑定的情况。之上一直做 JAVA Web 对于真正底层的工作只能说是一知半解,最近研究 ESP32 所以发出次疑惑🤔总之谢谢朋友们的解答了
    Gav1nw
        26
    Gav1nw  
    OP
       2023-01-20 12:01:49 +08:00 via iPhone
    @misaka19000 谢谢🙏写的好详细
    yuezk
        27
    yuezk  
       2023-01-20 12:03:25 +08:00
    @Gav1nw #4 .class 文件不是直接运行在 CPU 上的,它是运行在 JVM 上的,而 JVM 在不同的系统和 CPU 架构上有不同的实现,这对 .class 文件来说是透明的,Java 也正是靠不同平台的 JVM 实现了跨平台。
    Gav1nw
        28
    Gav1nw  
    OP
       2023-01-20 12:05:17 +08:00 via iPhone
    @dcsuibian 我刚看了一下发现确实底层包的.jar 下次研究透再问
    Gav1nw
        29
    Gav1nw  
    OP
       2023-01-20 12:07:22 +08:00 via iPhone
    @yuezk java 这块我还算了解,只是对 c 代码这块,我原来一直想的是编译后应该是结合 CPU 指令集的代码,没想到还有系统调用等
    leimao
        30
    leimao  
       2023-01-20 15:27:09 +08:00
    给个最简单的例子,操作系统 A 和 B ,均使用 ARM64 处理器。在操作系统 A 把程序 main.cpp build 成一个 binary C ,在操作系统 B 把同样的程序 main.cpp build 成一个 binary D 。想要运行 binary ,需要有对应的 runtime ,runtime 会读取 binary ,然后执行 binary 里面的指令。这两个程序的执行的指令是一样的,意味着 runtime 解读 binary 之后执行的指令需要一样,而不是 binary 需要一样。不同的 runtime 解读不同的 binary 也可以运行相同的指令。比方说 binary C 是 010101 ,binary D 是 101010 ,操作系统 A 的 runtime 是正着读,操作系统 B 的 runtime 是反着读,那么最终他们读的都是相同的。这也说明,理论上,通过特殊设计,是可以让同一个 binary 在同一个 CPU 的不同操作系统里运行的。
    mejee
        31
    mejee  
       2023-01-20 15:35:14 +08:00
    1 、有关系
    2 、不能
    n18255447846
        32
    n18255447846  
       2023-01-20 16:33:06 +08:00
    参考大部分项目的编译产物,都是以[文件名]-[系统]-[架构].xxx 命名
    macha
        33
    macha  
       2023-01-20 16:58:29 +08:00
    对于 CPU 来说都一样,但是应用程序和 CPU 之间还隔着一个操作系统。所以二进制文件和操作系统是密切相关的。
    你没发现现在流行的几个操作系统都有一个对应的编译器么。
    zinwalin
        34
    zinwalin  
       2023-01-20 18:42:00 +08:00
    @Gav1nw 不是同一文件。
    iOCZ
        35
    iOCZ  
       2023-01-20 19:04:11 +08:00
    @Gav1nw Java 虚拟机敉平了平台差异,可以用相同的字节码文件
    Gav1nw
        36
    Gav1nw  
    OP
       2023-01-20 20:50:05 +08:00
    @leimao 我对现代操作系统的理解是,负责进程调度、系统资源分配等,操作系统通过虚拟地址等,让每个进程都以为自己独占整个系统资源,所以程序不是应该对系统是无感知的吗?
    irytu
        37
    irytu  
       2023-01-21 07:30:41 +08:00 via iPhone
    lingling47
        38
    lingling47  
       2023-01-22 20:36:04 +08:00 via Android
    java 这不就是我嘛
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4157 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 10:14 · PVG 18:14 · LAX 02:14 · JFK 05:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.