草庐IT

windows - x86 32 位汇编代码是否有效 x86 64 位汇编代码?

coder 2024-06-07 原文

Is all x86 32-bit assembly code valid x86 64-bit assembly code?



我想知道 32 位汇编代码是否是 64 位汇编代码的子集,即每个 32 位汇编代码都可以在 64 位环境中运行?

我想答案是肯定的,因为 64 位 Windows 能够执行 32 位程序,但后来我看到 64 位处理器支持 32 位兼容模式?

如果不是,请提供一个不是有效 64 位汇编代码的 32 位汇编代码的小例子,并解释 64 位处理器如何执行 32 位汇编代码。

最佳答案

现代 x86 CPU 具有三种主要操作模式(此描述已简化):

  • 在实模式下,CPU 在禁用分页和分段的情况下执行 16 位代码。代码中的内存地址是指物理地址,段寄存器的内容被移位并添加到地址中以形成有效地址。
  • 在保护模式下,CPU 根据 CS(代码段)寄存器中的段选择器执行 16 位或 32 位代码。启用分段,可以(通常是)启用分页。程序可以通过跳转到适当的段来在 16 位和 32 位代码之间切换。 CPU 可以进入子模式虚拟 8086 模式以从 protected 模式操作系统内部模拟单个进程的实模式。
  • 在长模式下,CPU 执行 64 位代码。大多数情况下禁用分段,启用分页。 CPU 可以进入子模式兼容模式以从为长模式编写的操作系统内执行 16 位和 32 位保护模式代码。兼容模式是通过远跳转到具有适当位设置的 CS 选择器来进入的。虚拟 8086 模式不可用。

  • 维基百科有一个不错的表 x86-64 operating modes包括传统模式和实模式,以及长模式的所有 3 个子模式。在主流的 x86-64 操作系统下,启动后 CPU 内核将始终处于长模式,根据 32 位或 64 位用户空间在不同的子模式之间切换。 (不包括系统管理模式中断......)

    现在 16 位、32 位和 64 位模式有什么区别?
    16 位和 32 位模式基本上是一样的,除了以下区别:
  • 在 16 位模式下,默认地址和操作数宽度为 16 位。您可以分别使用 0x67 和 0x66 前缀将这些更改为单个指令的 32 位。在 32 位模式下,情况正好相反。
  • 在 16 位模式下,指令指针被截断为 16 位,跳转到高于 65536 的地址会导致奇怪的结果。
  • VEX/EVEX 编码指令(包括 AVX、AVX2、BMI、BMI2 和 AVX512 指令集的指令)不会在真实或虚拟 8086 模式下解码(尽管它们在 16 位保护模式下可用)。
  • 16 位模式比 32 位模式具有更少的寻址模式,但如果需要,可以在每条指令的基础上覆盖到 32 位寻址模式。

  • 现在,64 位模式有些不同。大多数指令的行为就像在 32 位模式下一样,但有以下区别:
  • 还有八个名为 r8、r9、...、r15 的附加寄存器。每个寄存器都可以用作字节、字、双字或 qword 寄存器。 REX 前缀系列(0x40 到 0x4f)对操作数是指旧寄存器还是新寄存器进行编码。八个额外的 SSE/AVX 寄存器 xmm8、xmm9、...、xmm15 也可用。
  • 您只能推送/弹出 64 位和 16 位数量(尽管您不应该执行后者),不能推送/弹出 32 位数量。
  • 单字节 inc regdec reg指令不可用,它们的指令空间已重新用于 REX 前缀。两字节 inc r/mdec r/m仍然可用,所以 inc regdec reg仍然可以编码。
  • 存在一种新的指令指针相对寻址模式,使用 32 位模式必须使用的 2 种冗余方式中较短的一种来编码 [disp32]绝对地址。
  • 默认地址宽度为 64 位,可以通过 0x67 前缀选择 32 位地址宽度。 16 位寻址不可用。
  • 默认操作数宽度为 32 位。可以通过 0x66 前缀选择 16 位宽度,可以通过适当的 REX 前缀选择 64 位宽度,而与您使用的寄存器无关。
  • 无法使用 ah , bh , ch , 和 dh在需要 REX 前缀的指令中。 REX 前缀导致这些寄存器编号改为表示寄存器的低 8 位 si , di , sp , 和 bp .
  • 写入 64 位寄存器的低 32 位会清除高 32 位,避免乱序 exec 的错误依赖。 (写入 8 位或 16 位部分寄存器仍然与 64 位旧值合并。)
  • 由于分段不起作用,除 fs 外,分段覆盖是无意义的无操作和 gs覆盖 (0x64, 0x65) 用于支持线程本地存储 (TLS)。
  • 此外,许多专门处理分段的指令不可用。它们是:push/pop seg (除了 push/pop fs/gs ),arpl , call far (只有 0xff 编码有效),les , lds , jmp far (只有 0xff 编码有效),
  • 处理十进制算术的指令不可用,它们是:daa , das , aaa , aas , aam , aad ,
  • 此外,以下说明不可用:bound (很少使用),pusha/popa (不适用于附加寄存器),salc (未记录),
  • 0x80 的 0x82 指令别名无效。
  • 在早期的 amd64 CPU 上,lahfsahf不可用。

  • 这基本上就是全部!

    关于windows - x86 32 位汇编代码是否有效 x86 64 位汇编代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44089163/

    有关windows - x86 32 位汇编代码是否有效 x86 64 位汇编代码?的更多相关文章

    1. ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态 - 2

      我需要在客户计算机上运行Ruby应用程序。通常需要几天才能完成(复制大备份文件)。问题是如果启用sleep,它会中断应用程序。否则,计算机将持续运行数周,直到我下次访问为止。有什么方法可以防止执行期间休眠并让Windows在执行后休眠吗?欢迎任何疯狂的想法;-) 最佳答案 Here建议使用SetThreadExecutionStateWinAPI函数,使应用程序能够通知系统它正在使用中,从而防止系统在应用程序运行时进入休眠状态或关闭显示。像这样的东西:require'Win32API'ES_AWAYMODE_REQUIRED=0x0

    2. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

      如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

    3. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

      在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

    4. ruby-on-rails - 浏览 Ruby 源代码 - 2

      我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru

    5. ruby - 模块嵌套代码风格偏好 - 2

      我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

    6. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

      几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

    7. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

      这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

    8. ruby - Net::HTTP 获取源代码和状态 - 2

      我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

    9. 程序员如何提高代码能力? - 2

      前言作为一名程序员,自己的本质工作就是做程序开发,那么程序开发的时候最直接的体现就是代码,检验一个程序员技术水平的一个核心环节就是开发时候的代码能力。众所周知,程序开发的水平提升是一个循序渐进的过程,每一位程序员都是从“菜鸟”变成“大神”的,所以程序员在程序开发过程中的代码能力也是根据平时开发中的业务实践来积累和提升的。提高代码能力核心要素程序员要想提高自身代码能力,尤其是新晋程序员的代码能力有很大的提升空间的时候,需要针对性的去提高自己的代码能力。提高代码能力其实有几个比较关键的点,只要把握住这些方面,就能很好的、快速的提高自己的一部分代码能力。1、多去阅读开源项目,如有机会可以亲自参与开源

    10. Vscode+Cmake配置并运行opencv环境(Windows和Ubuntu大同小异) - 2

      之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m

    随机推荐