如何将输入传递到扩展汇编中?

2024-05-13

考虑这段代码,来自我的先前的问题 https://stackoverflow.com/questions/37955538/segfault-on-movq-instruction.

int main(){
    asm("movq $100000000, %rcx;"
            "startofloop: ; "
            "sub $0x1, %rcx; "
            "jne startofloop; ");
}

我想让循环的迭代次数成为一个 C 变量,所以我在阅读后尝试了以下操作这个文件 http://asm.sourceforge.net/articles/rmiyagi-inline-asm.txt.

int main(){                                      
    int count = 100000000;                       
    asm("movq %0, %rcx;"                         
            "startofloop: ; "                    
            "sub $0x1, %rcx; "                   
            "jne startofloop; ":: "r"(count));   
}                                                

不幸的是,这无法编译,并因以下错误而中断。

asm_fail.c: In function ‘main’:
asm_fail.c:3:5: error: invalid 'asm': operand number missing after %-letter
     asm("movq %0, %rcx;"
     ^
asm_fail.c:3:5: error: invalid 'asm': operand number missing after %-letter

将 C 变量的值传递到程序集中的正确方法是什么?


如果使用扩展的汇编器模板(带有输入、输出、破坏等的模板),那么您需要预先添加一个额外的%在模板内的寄存器名称上。%%rcx在这种情况下。这将解决与此错误相关的问题:

错误:'asm' 无效:% 字母后缺少操作数

这将带来一个新的问题。您将收到类似以下内容的错误:

“movq”的操作数类型不匹配

问题是"r"(count)输入约束告诉编译器应该选择一个包含以下值的寄存器count。由于计数被定义为inttype,它会选择一个32位寄存器。为了论证,假设它选择EAX。替换后,它会尝试生成以下指令:

movq %eax, %rcx

你不能使用movq将 32 位寄存器的内容移动到 64 位寄存器,从而出现错误。更好的选择是使用ECX作为目标,以便两者属于同一类型。修改后的代码如下所示:

asm("mov %0, %%ecx;"                         
    "startofloop: ; "                    
    "sub $0x1, %%ecx; "                   
    "jne startofloop; ":: "r"(count));

或者,您可以选择使用输入操作数"ri"(count)。这将允许编译器选择寄存器或立即值。在更高的优化级别上(-O1, -O2)在这种情况下可能会确定count保持不变(100000000)并生成如下代码:

mov $100000000, %ecx                         
startofloop:
sub $0x1, %ecx
jne startofloop

而不是被迫将 100000000 放入寄存器并将其复制到ECX它可以使用立即数来代替。


您的模板中的一个严重问题是您破坏了ECX but GCC对此一无所知。GCC实际上并没有解析模板内的指令来确定代码的作用。它不知道你已经被打败了ECX。编译器可能依赖ECX模板前后具有相同的值。如果销毁输出操作数中未引用的寄存器,则必须在破坏列表中显式列出它。像这样的事情会起作用:

asm("mov %0, %%ecx;"                         
    "startofloop: ; "                    
    "sub $0x1, %%ecx; "                   
    "jne startofloop; ":: "ri"(count) : "rcx");

Now GCC知道它不能依赖于中的值RCX模板执行前后的值相同。

您可以得到以下结果,而不是使用固定寄存器作为内部计数器:GCC选择可用的东西。这样做意味着我们不再需要破坏者了。您可以创建一个可用于计数的虚拟变量(临时变量)。为了避免这段代码被完全优化,我们可以使用volatile汇编器模板上的属性。当汇编器模板没有输出操作数时,不需要这样做。像这样的代码可以工作:

int count=100000000
int dummy;
asm volatile("mov %1, %0;"                         
    "startofloop: ; "                    
    "sub $0x1, %0; "                   
    "jne startofloop; ":"=rm"(dummy): "ri"(count));

The =rm输出约束表示该操作数可以使用内存位置或寄存器。将选择权交给编译器可以生成更好的代码。在优化级别-O1您可能会发现生成的代码如下所示:

mov    $0x5f5e100,%ebx
startofloop:
sub    $0x1,%ebx
jne    startofloop

在本例中,编译器选择使用立即操作数进行计数 ($0x5f5e100 = $100000000)。这dummy变量被优化到寄存器EBX.

您还可以使用其他技巧来改进模板。人们可以阅读有关扩展汇编器模板的更多信息GNU 文档 https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/Extended-Asm.html#Extended-Asm


您的代码似乎保留了变量中的值count。如果这不是要求count要在执行模板之前具有相同的值,您可以使用count对于输入和输出。该代码可能如下所示:

asm volatile("startofloop: ; "
    "sub $0x1, %0; "
    "jne startofloop; ":"+rm"(count): );

+rm意味着输出操作数也被用作输入操作数。在这种情况下count完成后应始终为零。


如果您使用GCC -S选项来输出生成的汇编代码,那么您可能希望更改模板以使输出看起来更干净。而不是使用;(分号)使用\n\t反而。这会将汇编器模板分解为多行并添加缩进。一个例子:

asm volatile("mov %1, %0\n\t"                         
    "startofloop:\n\t"                    
    "sub $0x1, %0\n\t"                   
    "jne startofloop\n\t":"=rm"(dummy): "ri"(count));

一般来说,除非别无选择,否则不应使用内联汇编器模板。将其编码为C并引导编译器输出您想要的汇编程序,或者在需要时使用编译器内在函数。内联汇编器应该作为最后的手段,或者如果你的家庭作业需要它。大卫·沃尔弗德写了一篇维基文章 https://gcc.gnu.org/wiki/DontUseInlineAsm就此主题而言。

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

如何将输入传递到扩展汇编中? 的相关文章

随机推荐

  • Android 无法查找支持版本 27.0.0 的窗口

    更新后supportVersion to 27 0 0仅在 Android 5 0 2 上 应用程序会因以下堆栈跟踪而崩溃 W WindowManager Failed looking up window java lang Illegal
  • 如何从android中的webview获取选定的文本?

    我需要从网络视图中获取选定的文本 为此 我这样说 webView loadUrl javascript Android getHtml window getSelection toString 在我的触摸事件中 触摸事件效果很好 Andro
  • 如何使用scrapy抓取xml url

    你好 我正在使用 scrapy 来抓取 xml url 假设下面是我的 Spider py 代码 class TestSpider BaseSpider name test allowed domains www example com s
  • Iexpress 用于大文件(损坏的 Cabinet 文件)

    我希望结合许多安装程序并使用 Iexpress 制作一个 exe 安装程序的总大小为 750MB 我尝试使用 Iexpress 合并并生成 但创建的 exe 文件大小只有 80MB 当我双击并尝试运行该 exe 时 它 指出其内阁文件已损坏
  • 从when语句内的函数返回

    我想做的就是使用 when 语句返回一个值 我想要以下功能 if x return y 我正在尝试使用 when x y 但是when语句并没有以退出函数并返回y的方式进行计算 它只是愉快地继续下一行 有没有办法做到这一点而不需要制作一个看
  • 如何在运行“go test”时排除或跳过特定目录[重复]

    这个问题在这里已经有答案了 go test go list grep v vendor coverprofile testCoverage txt 我正在使用上述命令来测试文件 但有 1 个名为 Store 的文件夹我想从测试中排除 怎样才
  • 传单圆圈绘制/编辑问题

    我第一次制作传单 并面临绘制圆圈和编辑 更改圆圈位置 的问题 我面临的问题是 编辑 移动 圆从一个位置到另一位置会改变其半径 Note 请尝试在给定的小提琴中在地图顶部创建圆圈 然后通过单击编辑按钮将其移动到底部 如果我在地图的顶部创建圆圈
  • 如何在 JavaScript 中检查未定义的变量

    我想检查变量是否已定义 例如 以下内容会引发未定义的错误 alert x 我怎样才能捕获这个错误 在 JavaScript 中 null是一个对象 不存在的事物还有另一种价值 undefined DOM 返回null对于几乎所有无法在文档中
  • 如何收集 Sphinx 中的所有外部链接?

    我必须在手册中放入一些外部链接 并且希望在 部分甚至整本书的末尾 不重要 列出所有链接 而无需手动重复它们 我怎样才能做到这一点 这是带有参考书目的文档的摘录 呈现的版本是here http packages python org pyte
  • 在嵌入式 Jetty 上使用 DefaultServlet 提供静态 html 文件

    我正在开发一个需要独立的项目 因此我决定将 Jetty 嵌入到我的应用程序中 我将提供静态 HTML 页面 一些 JSP 页面 并且还将使用一些自定义 servlet 我找到了一个完美的示例 说明如何设置嵌入式 Jetty 来完成所有这一切
  • 通过 clang++ 的 -finstrument-functions 进行 C++ 函数检测:如何忽略内部 std 库调用?

    假设我有一个类似的函数 template
  • 捕获动态表中 HTML 元素的值

    我有从数据库生成的以下动态表
  • iPhone表情插入MySQL却变成空值

    我们正在开发一个 iPhone 应用程序 它将表情符号从 iPhone 发送到服务器端 PHP 并插入到 MySQL 表中 我正在做服务器端的工作 但是insert语句执行成功后 插入的值变成空了 我可以正确插入字段 varchar 的是文
  • GOPATH值设置

    我用go1 3 1 windows amd64 msi安装go 安装后GOROOT是默认设置 我发现 D Programs Go bin 在 PATH 中 然后我创建一个 GOPATH 环境变量 使用 go get 命令时 出现错误 软件包
  • Twython - 如何使用媒体 url 更新状态

    在我的应用程序中 我允许用户在 Twitter 上发帖 现在我想让他们通过媒体更新他们的状态 In twython py我看到一个方法update status with media从文件系统读取图像并上传到 Twitter 我的图像不在文
  • Vaadin 23 重新部署后无法完全重新加载应用程序

    现在 我正在准备 Vaadin 23 2 5 应用程序进行生产 并且经常在重新部署应用程序后无法完全重新加载自身 并在顶部挂有蓝色的进度条 我可能看到的唯一问题是浏览器控制台中的以下 JS 问题 FireFox Chrome 另外 根据我之
  • 如何获取 iTunes 选择的文件路径

    我正在尝试使用 AppleScript 确定在 iTunes 中选择的曲目的路径 貌似不是该公司的财产track班级 谁能告诉我如何获取文件路径 尝试这个 gets file path of selected song tell appli
  • 在 SCSS 中使用 HSLA 中的 CSS 变量

    所以我一直在尝试在HSLA中使用CSS变量 我需要保持相同的颜色 但只需更改不透明度 div content here div SCSS root color 332 61 78 div background hsla var color
  • 并行模拟写入同一文件

    我的目标是在集群上并行运行 10 000 个左右的 Julia 编码模拟 每个模拟独立于所有其他模拟 每个模拟都有一个要输出的数字 以及有关哪个模拟产生该数字的 3 列信息 因此 强制每个模拟打印在单独的文件上对我来说听起来有点愚蠢 我可以
  • 如何将输入传递到扩展汇编中?

    考虑这段代码 来自我的先前的问题 https stackoverflow com questions 37955538 segfault on movq instruction int main asm movq 100000000 rcx