草庐IT

c - 为什么这个内联汇编不能为每条指令使用单独的 asm volatile 语句?

coder 2023-06-17 原文

对于以下代码:

long buf[64];

register long rrax asm ("rax");
register long rrbx asm ("rbx");
register long rrsi asm ("rsi");

rrax = 0x34;
rrbx = 0x39;

__asm__ __volatile__ ("movq $buf,%rsi");
__asm__ __volatile__ ("movq %rax, 0(%rsi);");
__asm__ __volatile__ ("movq %rbx, 8(%rsi);");

printf( "buf[0] = %lx, buf[1] = %lx!\n", buf[0], buf[1] );

我得到以下输出:
buf[0] = 0, buf[1] = 346161cbc0!

虽然它应该是:
buf[0] = 34, buf[1] = 39!

任何想法为什么它不能正常工作,以及如何解决它?

最佳答案

您破坏内存但不告诉 GCC,因此 GCC 可以缓存 buf 中的值跨程序集调用。如果你想使用输入和输出,告诉 GCC 一切。

__asm__ (
    "movq %1, 0(%0)\n\t"
    "movq %2, 8(%0)"
    :                                /* Outputs (none) */
    : "r"(buf), "r"(rrax), "r"(rrbx) /* Inputs */
    : "memory");                     /* Clobbered */
您通常还希望让 GCC 处理大部分 mov ,寄存器选择等——即使你明确限制寄存器(rrax 仍然是 %rax )让信息流过 GCC,否则你会得到意想不到的结果。__volatile__是错的。
原因__volatile__存在是这样你就可以保证编译器将你的代码准确地放置在它所在的位置......这对这段代码来说是完全不必要的保证。它对于实现诸如内存屏障之类的高级功能是必要的,但如果您只是修改内存和寄存器,则几乎完全没有值(value)。
GCC 已经知道在 printf 之后它不能移动这个程序集因为printf调用接入buf , 和 buf可能会被议会破坏。 GCC在rrax=0x39;之前已经知道它不能移动程序集因为 rax是汇编代码的输入。那么__volatile__有什么用明白?没有什么。
如果您的代码在没有 __volatile__ 的情况下不起作用那么代码中有错误应该是固定 而不是仅仅添加 __volatile__并希望这能让一切变得更好。 __volatile__关键字不是魔术,不应被视为魔术。
替代修复:
__volatile__您的原始代码需要吗?不。只需正确标记输入和破坏值。
/* The "S" constraint means %rsi, "b" means %rbx, and "a" means %rax
   The inputs and clobbered values are specified.  There is no output
   so that section is blank.  */
rsi = (long) buf;
__asm__ ("movq %%rax, 0(%%rsi)" : : "a"(rrax), "S"(rssi) : "memory");
__asm__ ("movq %%rbx, 0(%%rsi)" : : "b"(rrbx), "S"(rrsi) : "memory");
为什么__volatile__在这里对您没有帮助:
rrax = 0x34; /* Dead code */
GCC 完全有权完全删除上述行,因为上述问题中的代码声称它从不使用 rrax .
一个更清晰的例子
long global;
void store_5(void)
{
    register long rax asm ("rax");
    rax = 5;
    __asm__ __volatile__ ("movq %%rax, (global)");
}
拆卸或多或少如您所料-O0 ,
movl $5, %rax
movq %rax, (global)
但是在关闭优化的情况下,您可能对 assembly 相当草率。让我们试试 -O2 :
movq %rax, (global)
哎呀!哪里去了rax = 5;去?这是死代码,因为 %rax从未在函数中使用——至少就 GCC 而言是这样。 GCC 不会查看程序集内部。当我们删除 __volatile__ 时会发生什么?
; empty
好吧,你可能会想 __volatile__通过防止 GCC 丢弃您宝贵的程序集来为您提供服务,但这只是掩盖了 GCC 认为您的程序集没有做任何事情的事实。 GCC 认为你的程序集不接受输入,不产生输出,并且不破坏内存。你最好把它弄直:
long global;
void store_5(void)
{
    register long rax asm ("rax");
    rax = 5;
    __asm__ __volatile__ ("movq %%rax, (global)" : : : "memory");
}
现在我们得到以下输出:
movq %rax, (global)
更好的。但是如果你告诉 GCC 有关输入的信息,它会确保 %rax首先正确初始化:
long global;
void store_5(void)
{
    register long rax asm ("rax");
    rax = 5;
    __asm__ ("movq %%rax, (global)" : : "a"(rax) : "memory");
}
输出,经过优化:
movl $5, %eax
movq %rax, (global)
正确的!我们甚至不需要使用 __volatile__ .
为什么__volatile__存在?__volatile__ 的主要正确用法是如果您的汇编代码除了输入、输出或破坏内存之外还执行其他操作。也许它会混淆 GCC 不知道的特殊寄存器,或者影响 IO。您在 Linux 内核中经常看到它,但它在用户空间中经常被误用。__volatile__关键字非常诱人,因为我们 C 程序员常常认为我们几乎已经在用汇编语言编程了。不是。 C 编译器会进行大量数据流分析——因此您需要向编译器解释汇编代码的数据流。这样,编译器就可以安全地操作您的程序集 block ,就像它操作它生成的程序集一样。
如果您发现自己在使用 __volatile__很多,作为替代方案,您可以在程序集文件中编写整个函数或模块。

关于c - 为什么这个内联汇编不能为每条指令使用单独的 asm volatile 语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8891139/

有关c - 为什么这个内联汇编不能为每条指令使用单独的 asm volatile 语句?的更多相关文章

  1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

    我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

    很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

  5. ruby - 在 Ruby 中使用匿名模块 - 2

    假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

  6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

    我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

  7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  8. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  9. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  10. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

随机推荐