栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

为什么此内联程序集不能为每个指令使用单独的asm volatile语句?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

为什么此内联程序集不能为每个指令使用单独的asm volatile语句?

您破坏了内存,但是不告诉GCC,因此GCC可以

buf
在程序集调用中缓存值。如果要使用输入和输出,请告知GCC所有相关信息。

__asm__ (    "movq %1, 0(%0)nt"    "movq %2, 8(%0)"    :              : "r"(buf), "r"(rrax), "r"(rrbx)     : "memory");          

通常,您还希望让GCC处理大部分的

mov
,寄存器选择等-即使您明确限制了寄存器(rrax为stil
%rax
),也让信息流经GCC还是会得到意想不到的结果。

__volatile__
是错的。

__volatile__
存在的原因是,您可以保证编译器将您的代码准确地放置在该位置……这对于此代码是 完全不必要的
保证。这是实现内存屏障等高级功能所必需的,但如果仅修改内存和寄存器,则几乎是一文不值。

GCC已经知道它不能在此之后移动该程序集,

printf
因为该
printf
调用访问
buf
,并且
buf
可能被该程序集破坏。GCC已经知道它之前不能移动程序集,
rrax=0x39;
因为它
rax
是程序集代码的输入。那么你
__volatile__
能得到什么呢?没有。

如果您的代码无法正常运行,

__volatile__
那么代码中应该存在一个错误,应该 纠正
该错误,而不仅仅是添加
__volatile__
并希望它会使一切变得更好。该
__volatile__
关键字不是魔术,不应该被如此对待。

替代解决方案:

__volatile__
您的原始代码是否必要?否。只需正确标记输入和缓冲值即可。

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; 

GCC完全有权利完全删除上述行,因为上述问题中的代码声称它从未使用过

rrax

一个更清晰的例子

long global;void store_5(void){    register long rax asm ("rax");    rax = 5;    __asm__ __volatile__ ("movq %%rax, (global)");}

拆卸程度与您预期的差不多

-O0

movl $5, %raxmovq %rax, (global)

但是,关闭优化功能后,您对组装的了解可能会很草率。让我们尝试

-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, %eaxmovq %rax, (global)

正确!而且我们甚至不需要使用

__volatile__

为什么
__volatile__
存在?

主要的正确用法

__volatile__
是,如果汇编代码执行除输入,输出或破坏内存之外的其他操作。也许它与GCC不知道或影响IO的特殊寄存器弄混了。您在Linux内核中经常看到它,但是它在用户空间中经常被滥用。

__volatile__
关键字是非常诱人的,因为我们的C程序员往往喜欢把我们 几乎 在汇编语言编程了。不是。C编译器进行了大量数据流分析-
因此您需要为汇编代码向编译器说明数据流。这样,编译器可以安全地操纵程序集的块,就像操纵其生成的程序集一样。

如果发现自己使用

__volatile__
了很多东西,则可以选择在汇编文件中编写整个函数或模块。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/412541.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号