当您使用 C++ 中的 asm 代码操作寄存器时,会发生什么情况?

2023-12-23

一些代码:

int x = 1;
for(int i = 1; i < 10; i++)
{
    x *= i;
    __asm {
        mov eax, x 
    };
}

如果这个程序使用eax为了增加价值i,当我操纵时会发生什么eax?

编译器会保存之前的寄存器吗?__asm在执行 asm 代码后调用并使用它们,或者会忽略它eax被操纵并继续产生某种奇怪的行为?

eax 内部发生了什么?

EDIT:即使我的代码仅适用于 Visual C++,我也想知道一般会发生什么以及不同的编译器将如何处理此问题。


eax 内部发生了什么?

内联汇编并不神奇或特殊。 C++ 编译器已经将 C++ 翻译成 asm。

您的内联 asm 刚刚包含在编译器生成的 asm 中。如果您想了解到底发生了什么,请查看编译器的 asm 输出,看看您的代码如何适应。

也就是说,这部分问题的答案是它取决于编译器、上下文和优化选项,因此您应该只查看生成的 asm 来亲自查看。


您的问题使用 MSVC 风格的内联 asm,它保存/恢复内联 asm 周围的寄存器(除了ebp, 而且当然esp)。所以我认为你的例子可能永远没有效果。 MSVC 风格没有任何语法可以向编译器传达有关寄存器使用情况的任何信息,或者在寄存器(而不是内存)中输入/输出值。

有时您会看到 MSVC 内联汇编在其中留下一个值eax在一个结束时int函数没有return语句,在有限的情况下做出最安全的假设,即编译器不会在内联汇编末尾和函数末尾之间对 eax 执行任何操作。


您在评论中说您想要 g++ 的答案,它甚至无法编译您的示例,但无论如何,我会为您写一个。

GNU C 内联汇编 https://gcc.gnu.org/onlinedocs/gcc/Using-Assembly-Language-with-C.html使用不同的语法,这需要您告诉编译器哪些寄存器是输入(并且未修改),哪些寄存器是读写或只写的。还有哪些寄存器是被破坏的暂存寄存器。

程序员有责任使用约束向编译器正确描述汇编,否则你就会踩到它的脚趾。使用 GNU C 内联汇编就像一场舞蹈,你可以在其中can可能会取得好的结果,但只有当你不小心时,你才会踩到编译器的脚趾。 (此外,通常编译器可以自己生成良好的 asm,而内联 asm 是一种非常脆弱的优化方式;许多主要问题之一是内联后的常量传播不可能通过内联 asm 实现。)


无论如何,让我们尝试一下 GNU C 内联汇编的工作示例:

int foo_badasm(int n) {
  int factorial = 1;
  for (int i=1 ; i < n ; i++ ) {
    // compile with -masm=intel, since I'm using Intel syntax here
    asm volatile ("mov   eax, %[x]   # THIS LINE FROM INLINE ASM\n"
                  "# more lines\n"
                  // "xor  eax,eax\n"
        : // no outputs, making the volatile implicit even if we didn't specify it
        : [x] "rmi" (factorial)   // input can be reg, memory, or immediate
        : // "eax"   // uncomment this to tell the compiler we clobber eax, so our asm doesn't break step on the compiler's toes.
    );
    factorial *= i;
  }
  return factorial;
}

请参阅带有 asm 输出的代码Godbolt 编译器浏览器 http://gcc.godbolt.org/#compilers:!((compiler:g6,options:'-xc+-fverbose-asm+-Wall+-Wextra+-O3+-march%3Dhaswell+-masm%3Dintel+-fno-tree-vectorize',source:'//+function+with+an+input+and+an+output,+so+it+doesn!'t+optimize+away+to+returning+a+constant%0Aint+foo(int+n)+%7B%0A++int+factorial+%3D+1%3B%0A++for+(int+i%3D1+%3B+i+%3C+n+%3B+i%2B%2B+)%0A++++factorial+*%3D+i%3B%0A++return+factorial%3B%0A%7D%0A%0A%0Aint+foo_badasm(int+n)+%7B%0A++int+factorial+%3D+1%3B%0A++for+(int+i%3D1+%3B+i+%3C+n+%3B+i%2B%2B+)+%7B%0A++++//+compile+with+-masm%3Dintel,+since+I!'m+using+Intel+syntax+here%0A++++asm+volatile+(%22mov+++eax,+%25%5Bx%5D+++%23+THIS+LINE+FROM+INLINE+ASM%5Cn%22%0A++++++++++++++++++%22%23+more+lines%5Cn%22%0A++++++++++++++++++//+%22xor++eax,eax%5Cn%22%0A++++++++:+//+no+outputs,+making+the+volatile+implicit+even+if+we+didn!'t+specify+it%0A++++++++:+%5Bx%5D+%22rmi%22+(factorial)%0A++++++++:+//+%22eax%22++//+uncomment+the+eax+clobber+to+make+this+function+work%0A++++)%3B%0A++++factorial+*%3D+i%3B%0A++%7D%0A++return+factorial%3B%0A%7D%0A')),filterAsm:(commentOnly:!t,directives:!t,intel:!t,labels:!t),version:3,并且对于相同的函数,没有asm陈述。

内部循环编译为此(gcc 6.1-O3 -fverbose-asm -masm=intel, with -fno-tree-vectorize为了简单起见)。你也可以用 clang 尝试一下。

.L10:
    mov   eax, eax   # THIS LINE FROM INLINE ASM    # <retval>

    imul    eax, edx        # <retval>, i
    add     edx, 1    # i,
    cmp     edi, edx  # n, i
    jne     .L10      #,
    ret

正如您所看到的,在这种情况下,内联 asm 语句产生了一个无操作。 (mov eax,eax截断rax到 32 位,将高 32 位清零,但在此函数中它们已经为零。)

如果我们不做任何其他事情,比如将寄存器归零,或者mov如果来自不同的来源,我们就会破坏该功能。编译器生成的asm取决于only中列出的约束条件asm声明,而不是代码文本(与 MSVC 不同)。


See the 内联汇编 /questions/tagged/inline-assembly标记维基以获取更多信息,特别是这个关于 MSVC 和 GNU C 内联汇编之间差异的答案 https://stackoverflow.com/questions/3323445/what-is-the-difference-between-asm-and-asm/35959859#35959859.

更重要的是,阅读https://gcc.gnu.org/wiki/DontUseInlineAsm https://gcc.gnu.org/wiki/DontUseInlineAsm在实际使用内联汇编之前。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当您使用 C++ 中的 asm 代码操作寄存器时,会发生什么情况? 的相关文章

  • 使用 TCP 套接字在本地代理视频

    我一直对向媒体浏览器添加对视频播客的支持非常感兴趣 我希望用户能够浏览可用的视频播客并从互联网上流式传输它们 这真的很容易 因为媒体播放器等将愉快地播放存在于云中的文件 问题是我想在本地缓存这些文件 因此同一集的后续观看将不涉及流式传输 而
  • 如何转发声明要在 unique_ptr 的标准容器中使用的类

    在智能指针的标准容器中使用它时 是否可以避免完整的类定义可见 例如 我无法编译以下内容 include
  • 错误:“运行所选代码生成器时出错:包恢复失败”

    我正在尝试将控制器添加到 ASP NET Core 项目中的解决方案中 当我尝试这样做时 我收到此错误 我收到相同的消息 为控制器添加最小依赖项和完整依赖项 我也有这个问题 使用实体框架添加控制器 gt 带有操作的 API 控制器 将给出
  • 等待运算符错误

    我的代码有问题 我怎么解决这个问题 这个问题出现在await操作符中 public MyModel HttpClient client new HttpClient HttpResponseMessage response await cl
  • Monitor.Pulse & Wait - 意外行为

    http www codeproject com Articles 28785 Thread synchronization Wait and Pulse demystified http www codeproject com Artic
  • C 中的 '\0' 和 printf()

    在 C 入门课程中 我了解到在存储字符串时存储空字符 0在它的最后 但是如果我想打印一个字符串怎么办 printf hello 虽然我发现它并没有结束 0通过以下声明 printf d printf hello Output 5 但这似乎不
  • 析构函数与成员函数竞赛

    当我在析构函数内时 其他线程是否可能开始执行对象的成员函数 遇到这种情况该如何处理呢 C 没有内在的保护来防止在删除对象后使用它 忘记竞争条件 另一个线程可以在完全删除你的对象后使用你的对象 Either 确保只有一个位置 代码拥有该对象
  • C 链表销毁函数

    我正在尝试学习 C 和很多人一样 我对指针有点困惑 无论如何 我创建了一个递归函数来销毁我的链表 但是正如我调试的那样 当我从函数返回时 列表的头部不应该为空 所以我猜这是对指针的一些基本误解 这是函数 void destroy struc
  • 用 OpenCL C 编写快速线性系统求解器

    我正在编写一个 OpenCL 内核 它将涉及求解线性系统 目前我的内核太慢了 提高线性系统部分的性能似乎是一个不错的起点 我还应该注意 我并没有尝试使我的线性求解器并行 我正在研究的问题在宏观层面上已经是令人尴尬的并行 以下是我编写的 C
  • 将 std::pair const 转换为 std::pair const 安全吗?

    理论上或实践上 安全吗reinterpret cast a std pair
  • 编译器消息“警告:格式‘%s’需要类型‘char *’,但参数 2 具有类型‘char (*)’”

    我正在尝试运行一个简单的 C 程序 但收到此错误 警告 格式 s 需要类型 char 但参数 2 的类型为 char 20 我在跑步Mac OS X v10 8 https en wikipedia org wiki OS X Mounta
  • 使用左连接获得不适当的输出

    我正在尝试获取变体列表 并且对于每个变体都获取所有subvariants list无论子变体属于何处 特别的Test say 100 这是示例数据 Id TestId SourceSubVariantId TargetSubVariantI
  • 如何解析多态 JSON 数组?

    我有一个 JSON 格式的文件 其中包含个人用户的记录 一些用户的记录中间有一个评论字段 我只想解析顶级项目 全名 贡献者姓名 电子邮件 使用 Newtonsoft JSON 解析器 但我似乎无法让它识别单个对象 当我将整个字符串解析为一个
  • 如何将输出重定向到 boost 日志?

    我有一个使用boost log的C 程序 我加载了用户提供的动态链接库 我想将 stderr 重定向到 boost 日志 以便用户的库随时执行以下操作 std cerr lt lt Some stuff 它产生相同的结果 BOOST LOG
  • ef core 在更新数据库期间不使用 ASPNETCORE_ENVIRONMENT

    我使用 Visual Studio 通过一定的迁移来更新我的所有环境 使用下面的命令效果很好 update database Migration initMigrationProduct c ProductContext Environme
  • 当分配返回 0 时,具有空异常规范的运算符 new 调用构造函数

    我有以下声明 void operator new size t s PersistentMemory m throw return m gt allocatePersistentMemory s 我正在测试启动时的内存耗尽 这会导致m gt
  • 如何解决 boost::multi precision::cpp_dec_float 除法错误

    除以boost multiprecision cpp dec float有某种舍入误差 如下 include
  • 如何在realm-dotnet中存储System.Collections.Generic.Dictionary

    我正在尝试将 Realm NET 集成到我的 uwp 项目中 我想知道是否有任何方法可以在 Realm dotnet 库中存储 System Collections Generic Dictionary 我试过这个 public class
  • 从数据库配置中的连接字符串中删除 SSIS 密码

    我有一个 SSIS 包 它使用 SQL 服务器中的 SSIS 配置表来检索 OLE DB 连接管理器的连接字符串属性 问题是我还需要相同的连接字符串来调用使用实体框架的程序集 我尝试访问连接管理器连接字符串属性 但 SSIS 总是删除密码
  • 打印任何类型的数组和列表的通用方法[重复]

    这个问题在这里已经有答案了 每当我调试一段涉及整数 双精度 字符串等数组或列表的代码时 有时我更喜欢打印它们 我为此所做的是为不同类型编写重载的 printArray printList 方法 for e g 我可能有这 3 种方法来打印各

随机推荐

  • 运算符<<重载隐藏其他

    我有一个奇怪的运算符 include
  • 分步更改 iPad Pro 的字体大小

    我有一个应用程序 仅适用于横向模式下的 iPad 屏幕设计完全在 IB 中通过自动布局完成 现在我想实现以下行为 在 iPad Pro 12 英寸上时 所有标签的字体大小应为 48 对于所有较小的 iPad 尺寸 字体大小应为 32 我在
  • 无法将foreign_key_checks设置为0/关闭

    我有一个小数据库 我刚刚添加了一些表并设置了外键约束 现在我想上传一些数据并阅读了有关使用以下内容暂时关闭检查的信息 SET FOREIGN KEY CHECKS 0 我正在从 SQL 窗口运行此查询 我收到一条 成功 消息 但是当我检查设
  • Flex 3中如何防止组件被拖出舞台

    我认为这个问题有一个简单的解决方案 只是不够简单让我找到它 问题 如何限制 Flex 3 中的 TitleWindow 被拖离屏幕 舞台 有没有办法将TitleWindow限制在查看区域 示例 假设我有一个占据 100 屏幕的应用程序 接下
  • 在 Python 中加载与 Jinja2 嵌套的 YAML

    我有一个 YAML 文件 all yaml 看起来像 var1 val1 var2 val2 var3 var1 var2 txt 如果我像这样在 Python 中加载它 import yaml f open all yaml dataMa
  • 获取导致异常的异常描述和堆栈跟踪,全部作为字符串

    如何转换捕获的Exception 其描述和堆栈跟踪 到str外用 try method that can raise an exception params except Exception as e print complete exce
  • OL3:缩放到地图上的矢量图层

    我有一张带有 openlayers 3 和矢量图层的地图 我想将地图调整为该矢量图层的大小 但到目前为止 我所能得到的只是将地图集中在该矢量的最后一个点上 因为在创建地图时无法访问矢量图层的点 if trackMap null for va
  • GWT RPC - 每个应用程序多个 RPC 服务

    我目前正在使用一个具有大型 RPC 服务的 GWT 应用程序 它有 100 多个方法 所有方法都做不同的事情 如果我将其拆分为多个 RPC 服务 我会获得什么样的性能优势 障碍 我相信我必须为每一个创建一个新的 servlet 所以我的主要
  • iframe onmouseout 捕获

    目前 我的父页面中有一个 iframe 我想知道当用户单击或移动到 iframe 边框之外 即返回父页面 时 是否可以捕获 onmouseout 事件来捕获 您应该能够在 iframe 页面中执行 document body onmouse
  • 圆角桌 LESS

    经过一番挖掘后我发现this https stackoverflow com questions 628301 css3s border radius property and border collapsecollapse dont mi
  • 当我们不需要主外键关系就可以加入时,为什么还需要主外键关系?

    当我们不需要主外键关系就可以加入时 为什么还需要主外键关系 test1 id lname fname dob no primary and foreign key and not unique no constraints test2 id
  • JEP 145 发生了什么(由于编译代码重用,jvm 启动速度更快)?

    在2012年 捷普 145 http hg openjdk java net jep jeps rev a16daa94ba0f创建的目的是 缓存编译后的本机代码在java中用于更快的 jvm 启动 当时 它已被正式宣布 https twi
  • Tensorflow,在 RNN 中保存状态的最佳方式?

    我目前有以下代码 用于张量流中一系列链接在一 起的 RNN 我没有使用 MultiRNN 因为我稍后要对每一层的输出做一些事情 for r in range RNNS with tf variable scope recurent d r
  • 适用于 iOS15 和 iOS16 的 NavigationLink

    我正在开发一个以 iOS 15 作为最低目标的应用程序 这意味着它还需要支持较新版本的 iOS 对于屏幕导航 我使用 NavigationView NavigationLink destination isActive label 我正是需
  • 无法在 Visual Studio 2013 中同步 Git

    我正在与另一位开发人员合作 我们似乎陷入了 GIT 困境 我定期提交代码并定期推送到远程主机 我的同事 虽然是一个很棒的人和开发人员 还没有养成这样做的习惯 当我今天早上去 Pull the Head 修订时 这是我的习惯 我遇到了以下错误
  • Asp.net MVC 核心中 Ajax.BeginForms 的替代方案是什么

    我认为在 asp net MVC 核心中 我们不再可以选择使用 Ajax BeginForms 那么 Ajax BeginForm 的替代方案是什么 您可以使用内联data ajax 属性
  • ASP.NET LINQ 查询用于过滤和循环多个表

    我有两个单独的域模型类 App 和 AgeGroup App 类包含一些基本的整数和字符串属性 AgeGroup 类也是如此 我想要实现的是 AppOrder 及其属性的所有应用程序的 JSON 输出 嵌套在按其 GroupOrder 属性
  • JQuery - 查找任何级别的所有后代,但不查找这些后代的后代

    问题 我正在尝试使用 JQuery find 查找元素内的所有后代在任何级别具有给定属性的后代 但不是具有相同属性的后代的后代 帮助理解 JQuery 下面查询的预期目标是查找元素内的所有后代 some id 在任何级别 有some att
  • 如何在 PHP 中检查域名服务器?

    我需要检查域名服务器正在使用什么 但在 PHP 中找不到正确的解决方案 我努力了checkdnsrr and dns get record 对于某些正在运行的域 它们都不会显示 NS Whois也不是解决办法 我的目的是过滤已设置名称服务器
  • 当您使用 C++ 中的 asm 代码操作寄存器时,会发生什么情况?

    一些代码 int x 1 for int i 1 i lt 10 i x i asm mov eax x 如果这个程序使用eax为了增加价值i 当我操纵时会发生什么eax 编译器会保存之前的寄存器吗 asm在执行 asm 代码后调用并使用它