V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
x97bgt
V2EX  ›  程序员

不懂就问,为啥同一个软件不能用在 x86 和 amd 的 CPU 上?

  •  
  •   x97bgt · 2020-06-26 21:00:28 +08:00 via iPhone · 3868 次点击
    这是一个创建于 1391 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我的理解是,这两种架构的指令集不一样,但只要操作系统做好封装,那么软件就不用去关心用的是哪种 CPU 架构。用何种架构只要操作系统感知到就可以了。

    难道软件需会直接去执行汇编语言吗?

    求解惑。

    28 条回复    2020-06-27 22:02:01 +08:00
    murmur
        1
    murmur  
       2020-06-26 21:06:27 +08:00
    这种观点都是 A 黑才说的出来,amd 和 intel 专利交叉授权,没有说啥杀手锏你有我没有,硬说 avx512 算一个,但是不足以作为杀手锏,还有 matlab 这种故意不给 amd 用指令集恶心人的

    如果你找到这样的“常用”软件,可以找出来说一下
    across
        2
    across  
       2020-06-26 21:08:28 +08:00 via iPhone
    你说的那个叫虚拟机,java c#这种带了“封装”。
    c++这种编译器可没有中间层,会翻译成指令的。
    uechris
        3
    uechris  
       2020-06-26 21:09:22 +08:00
    我猜你是在说 ARM 而不是 AMD?
    如果不是的话,当我没说(
    hahasong
        4
    hahasong  
       2020-06-26 21:10:20 +08:00
    amd 的架构叫 amd64, 也就是 intel 的 x86_64 。运行 x86 软件不是很合情合理
    anguiao
        5
    anguiao  
       2020-06-26 21:10:51 +08:00
    你是想说 ARM ? AMD 也是 x86 啊。
    然后你说的这个应该叫虚拟机,操作系统不负责这个。
    janxin
        6
    janxin  
       2020-06-26 21:11:00 +08:00
    如果没有特殊指定处理,确实是牙膏厂农企会通用

    但是为了某些厂商提供的特性,比如 1L 说的高级矢量扩展 AVX,牙膏厂硬件加速 HAXM 等等不包含在这个范围内的
    opiviqo
        7
    opiviqo  
       2020-06-26 21:11:22 +08:00
    某指令集 没有你咋写汇编? 你觉得是现有程序 还是 现有编译器?
    wdlth
        8
    wdlth  
       2020-06-26 21:11:58 +08:00
    编译型的会生成汇编语言,是平台相关的。
    reus
        9
    reus  
       2020-06-26 21:12:40 +08:00
    AMD 就是 x86 / x86_64 指令集啊
    “同一个软件不能用在 x86 和 amd 的 CPU 上”,这是假命题
    有些指令是 AMD 或者 intel 独有的,一般由基础库做探测,并选择不同的分支,很少有应用程序只兼容 intel cpu 的
    例如虚拟化的指令,amd 和 intel 的就不同,但虚拟机软件都会让你选择用哪一种,或者自动选择
    总之,指令集可以认为一样,操作系统也不会管
    汇编语言也要经过汇编器,变成二进制文件,并没有“执行汇编语言”这种说法

    以上所有知识都是计算机基础知识,找一本书学习最好,问网友是学不了成体系的知识的。
    VDimos
        10
    VDimos  
       2020-06-26 21:12:53 +08:00 via Android
    比如?
    libook
        11
    libook  
       2020-06-26 21:18:35 +08:00 via Android   ❤️ 1
    是想问 x86 和 arm 吧,现在 AMD Ryzen 也是 x86 的。

    除了虚拟机、解释器类的程序以外,基本上都是要编译成机器码的,操作系统只是提供资源管理的 API,比如创建进程、申请内存、访问文件系统等等。

    由于不同 CPU 指令集的中断地址有差异,所以需要不停的编译器来将源代码按照相应的指令集进行编译,而且有的指令 x86 有、arm 没有,相同的源代码可能可以直接编译为调用 x86 的对应指令,但是在 arm 上只能编译成对应的软解方案。

    不是系统开发专业人士,可能说得不准确,请大佬斧正。
    hoyixi
        12
    hoyixi  
       2020-06-26 21:18:57 +08:00   ❤️ 1
    大多数软件都通用,因为大部分应用软件就是调用操作系统封装好的通用 API 。

    个别软件(或者某软件的个别功能)需要使用 CPU 的特有技术 or 功能,而操作系统没有做适配,那就无法通用
    charlie21
        13
    charlie21  
       2020-06-26 21:25:24 +08:00
    你是不是以为罗永浩都可以成立一家公司在做个人电脑 CPU 的领域打败 Intel ?
    做好封装就可以了嘛
    x97bgt
        14
    x97bgt  
    OP
       2020-06-26 22:03:19 +08:00 via iPhone
    对的,是 arm,写错了
    jinliming2
        15
    jinliming2  
       2020-06-27 02:22:57 +08:00
    操作系统只封装资源的管理调度,具体的程序指令还是会直接交给 CPU 去跑的。
    SingeeKing
        16
    SingeeKing  
       2020-06-27 02:40:16 +08:00   ❤️ 1
    根据我的大概理解,应用程序执行的指令大体上分为两类,一部分是普通的指令,这些确确实实是直接操作 CPU 的,CPU 收到后发现指令没问题就会执行,这种情况操作系统不会介入;而另一类指令是特权指令,这些指令如果直接交由 CPU 执行是会被拒绝的(有一个标志着特权级的标志寄存器),这时如果想要执行这些指令就必须通过系统调用,这时才会引入操作系统介入。

    根据上面的描述,如果操作系统不做特殊处理,上面说的第一类指令是直接交由 CPU 执行而 CPU 会直接发现指令无法识别触发异常而不能执行于是这个程序就崩溃了。

    不过,根据苹果在 WWDC 上说的,初期苹果肯定会引入一个系统级的「虚拟机」,当监测到程序是 Intel CPU 时代的程序时就会将指令进行「翻译」,转换成 CPU 可以理解的就没问题了,因此就是网上说的会降低一定速度但是不会无法运行。

    另外你的「难道软件需会直接去执行汇编语言吗」,答案可以说是肯定的。编译的过程可以简单理解为就是吧写的代码转换成计算机能读懂的指令二进制,而这个二进制指令其实就是汇编(一一对应翻译的关系),所以可以说执行编译好的软件的过程其实就是执行编译后的「汇编代码」
    chiu
        17
    chiu  
       2020-06-27 07:38:59 +08:00 via Android
    好像是说 ARM ?
    编译型软件最后是编译成执行的指令集,运行在芯片层级上。如果按你说的方式,应该编译出来的结果是对封装好的接口层的调用,运行在统一 API 层之上。
    delectate
        18
    delectate  
       2020-06-27 09:15:32 +08:00   ❤️ 1
    举个例子就行了。

    电动汽车、柴油车、汽油车。
    都是能跑起来的车,载货能力、动力、舒适性都近似(上层应用,如车载电器),但是底层不同(能源、动力源),故此不能把柴油加到汽油车里(江河老师,你可长点心吧)。

    对于上层应用,根本不需要知道是汽油机还是柴油机,或者动力锂电,只要知道点烟器是 12/24v 就可以了。而对于底层,则是巨大的不同,需要工程师费劲心机写一大堆代码( ECU ),进行各种精心调教(汽车讲究“平台”,几十万几百万的奥迪,也许和十几万的斯柯达是同一个平台)。

    那么,如果这个上层应用是针对底层的,那么完全没可能做到通用、兼容(汽车的 ECU 怎么可能互换呢?);如果这个应用是无关紧要的,也许可以互换(比如行车记录仪),但是也要考虑兼容。
    flynaj
        19
    flynaj  
       2020-06-27 10:28:18 +08:00 via Android
    软件依赖于操作系统更 CPU,不同的操作系统有不同的文件格式,不同的 CPU 有不同的指令集, 你可以看看这个全平台软件 10 多个包 https://syncthing.net/downloads/
    qakito
        20
    qakito  
       2020-06-27 10:29:54 +08:00
    1. 如果是可执行的二进制文件,本身就是机器码;不同架构机器码不同;函数出入栈规范不同;寄存器使用规范不同
    2. 如果是可执行的脚本文件,没差
    3. 即便是相同的 API,不同架构上也有部分差异,比如部分信号值在不同架构上是不同的(详见 man 7 signal)
    nightwitch
        21
    nightwitch  
       2020-06-27 10:30:21 +08:00   ❤️ 1
    "但只要操作系统做好封装,那么软件就不用去关心用的是哪种 CPU 架构"

    确实存在,果子和微软都做过类似的。操作系统接手指令翻译,把 x86 的指令就翻译成 arm 的指令,这样软件是不需要关心 CPU 架构的,由操作系统来对应翻译到目标平台,就像托管型语言不需要关心目标平台,由虚拟机来翻译成 native 语言。 当然,现实是骨感的,绝大多数这种翻译都会拖慢性能,并且带来兼容性问题。
    x97bgt
        22
    x97bgt  
    OP
       2020-06-27 12:19:32 +08:00 via iPhone
    @SingeeKing @chiu @delectate @qakito @nightwitch @libook
    感谢大佬回答,尝试写一下我的总结。

    软件最后都是可执行文件,里面都是机器码,这个对于不同 CPU 架构是平台各异的。所以对不同的 CPU 架构,软件要有不同的发行版,毕竟机器码都不同了。

    我对 arm 和 x86 的 CPU 架构的指令集不熟悉,但我想两家能做东西差不多,一家能做的另一家也应该有对应的替代指令。如果有一个基础库将两种架构都整合得很好,那使用这个基础库的软件,应该一份代码就可以编译出不同平台的发行版。

    但如果软件需要深度地直接操作 CPU 的指令,那么就针对不同平台就需要有一份不同代码。

    不知道理解得对不对,轻拍~
    msg7086
        23
    msg7086  
       2020-06-27 13:22:50 +08:00   ❤️ 1
    > 一家能做的另一家也应该有对应的替代指令
    没错,大家都是 CPU,运算当然都能做。

    > 如果有一个基础库将两种架构都整合得很好
    编译器本身就能把 C 或者高级语言代码编译到目标平台,一般不需要基础库。

    > 但如果软件需要深度地直接操作 CPU 的指令
    是的,问题就在这里。
    比如说很多软件是想当然地「默认」自己会运行在 x86 平台上,所以很多假设都是基于 x86 的。
    (甚至有很多软件都是默认自己运行在 Windows 或 Linux 上,导致移植到另一个平台时需要大改代码。)

    比如说我现在用的一个软件,2002 年写的,源代码里到处充斥着 MSVC 格式的内联 MMX 汇编。
    这意味着什么呢?
    首先 MSVC 格式的内联汇编只被 VC 支持,而且只能运行在 32 位上。
    所以 Linux 就不能用了,GCC 也没法编译。
    其次内联汇编和 MMX 只能运行在 32 位上,所以没办法编译到 64 位。
    而且很显然,x86 汇编不能运行在 ARM 上。

    那么怎么办呢?

    很简单 —— 重 写。

    之所以会出现这个问题,就是因为代码编写的时候,一来没有这个技术,二来没有想到以后要移植,所以用了当时的技术和方法去写的代码。将近 20 年过去了,C++也从 1989 版变成了 2017 版,CPU 指令集也从奔腾 3 时代的 ISSE 变成了现在的主流 AVX2,Linux 服务器也开始进入普通人的生活,很多以前都没想过的技术,现在都已经变成了理所当然。但是源代码不会自己进化,还是需要时间精力的投入。这就是为什么小众平台软件支持更差的原因。

    另外,就算是能在 ARM 上编译运行,也会因为缺少 SIMD 优化而变得非常缓慢。现代处理器重度依赖 SIMD 并行运算指令,而 ARM 上用的则是 Neon,不仅机器指令不同,上层的 Intrinsics 设计得也完全不一样。没有了 SIMD 优化,运行速度会直接下降一个数量级。所以就算能用,也不一定用得舒服。
    gosas
        24
    gosas  
       2020-06-27 13:52:25 +08:00
    您是指 cisc 和 risc 的区别吗?
    wanguorui123
        25
    wanguorui123  
       2020-06-27 17:48:24 +08:00
    x86 的是复杂指令集,程序发起一条指令可能完成许多个动作,比如:把大象放到冰箱里,一条指令可以完成,对程序来说不用关心具体细节,这一点就像数据库中存储过程一样,调用时候不用关心具体细节,这样可以提高特定任务的执行效率,但是指令集会越来越庞大,以及难以维护
    ARM 的是精简指令集,程序发起一条指令只能完成一个具体动作,同样一个任务可能需要编写更多指令去完成,理论上在执行某些特定任务的效率低于 x85 平台,但是可以通过优化 CPU 的指令的执行吞吐量,以及集成专用处理器单元来弥补缺陷
    理论上 x86 的复杂指令可以提前转换为多条 ARM 的精简指令来执行,这就是 MacOS 11 中 Rosetta2 的作用


    但是要想彻底发挥出处理器的性能,可以将源代码编译成特定平台的程序,这样就省略运行时转换为特定平台的指令这个步骤,同时在源代码层面编译优化应该可以比 Rosetta2 这种在指令上兼容的模式更加优化和高效,C/C++的代码一般用这种模式

    另外像 JAVA/C#这种语言就有点不同了,先将源代码打包编译成中间代码的程序包,这个中间代码的程序包发布到不同 CPU 平台,由 JVM/运行时环境根据平台再次将中间代码编译优化成特定平台能识别的程序指令
    zjsxwc
        26
    zjsxwc  
       2020-06-27 19:01:43 +08:00 via Android
    js 啊,js 无所不能
    jim9606
        27
    jim9606  
       2020-06-27 20:09:48 +08:00   ❤️ 1
    可能你对用户程序的理解有点问题。

    通常用户程序里的二进制码是**直接在 CPU 硬件上执行**的,所以是 arch 相关的。这部分跟 OS 无关。

    但是用户程序必然要用到一些 OS 提供的功能,例如访问网络(需要 OS 网络栈+网卡驱动负责具体实现)、访问文件系统(需要文件系统驱动+磁盘控制器驱动负责实现),需要通过 OS 及 OS 提供的一些用户库进行。这部分是有办法做到 arch 无关的。例如 windows 使用 WOW64 提供 ABI 兼容的 dll 供 32 位程序使用,这些 WOW64 dll 负责将 32 位 ABI 的调用翻译 OS 64 位 ABI 的 dll 上。

    Java Bytecode 这种需要 runtime 的二进制码才是楼主所说的与 arch 无关,因为这种二进制码需要 arch 相关的 VM 将其转换为对应的 OS 系统调用和在 CPU 硬件上执行的二进制码。

    事实上功能简单的程序是可以轻松跨平台的,但目前大部分复杂点的软件都没法做到。
    classyk
        28
    classyk  
       2020-06-27 22:02:01 +08:00
    Android 如果存用 java 开发,开发出来的软件,一套就可以在 android x86,也可以在 android arm 上运行。
    如果涉及到 jni,那就要为不同的系统编译不同的 so 了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5381 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 108ms · UTC 08:05 · PVG 16:05 · LAX 01:05 · JFK 04:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.