本文共 1534 字,大约阅读时间需要 5 分钟。
在阅读本文之前,请阅读gcc的相关文档,以确保您基本了解如何在C中使用汇编语言.
文档地址为:
以下示例说明了相关概念:
#include
#include
#include
void do_check(uint32_t dwSomeValue) {
uint32_t dwRes;
asm("bsfl %1,%0" : "=r"(dwRes) : "r"(dwSomeValue) : "cc");
assert(dwRes == 3);
}
int main(int argc, char *argv[]) { do_check(8); }
编译后,以汇编形式检查do_check方法:
$ gcc -O3 main.c && objdump --disassemble=do_check a.out
0000000000001190 :
1190: 0f bc ff bsf %edi,%edi
1193: 83 ff 03 cmp $0x3,%edi
1196: 75 01 jne 1199
1198: c3 retq
1199: 50 push %rax
119a: e8 c1 ff ff ff callq 1160
由于在assert宏中使用了asm语句中的输出参数dwRes,即使asm语句未指定volatile,do_check方法也会正常执行.
在删除assert方法之后,让我们看一下do_check汇编代码:
$ gcc -O3 -D NDEBUG main.c && objdump --disassemble=do_check a.out
0000000000001130 :
1130: c3 retq
从上面可以看出,因为我们在执行gcc时添加了-D NDEBUG参数,并定义了NDEBUG宏,因此上述assert宏最终将变为空指令.
也就是说c语言对应汇编语句,do_check方法中的任何地方都没有在asm语句中使用输出参数dwRes,因此gcc会在优化的代码中删除asm语句,因此上述do_check方法最终成为空方法.
然后将上面的asm语句添加到volatile中,然后重试:
void do_check(uint32_t dwSomeValue) {
uint32_t dwRes;
asm volatile("bsfl %1,%0" : "=r"(dwRes) : "r"(dwSomeValue) : "cc");
assert(dwRes == 3);
}
编译后,以汇编形式检查do_check方法:
$ gcc -O3 -D NDEBUG main.c && objdump --disassemble=do_check a.out
0000000000001130 :
1130: 0f bc ff bsf %edi,%edi
1133: c3 retq
从上面可以看到,这一次即使指定了-D NDEBUG参数,assert宏也变成了no-op,导致在do_check方法中的任何地方都没有使用dwRes变量,但是由于volatile的存在c语言对应汇编语句,仍然对asm语句进行了优化.
通过上面的示例,我们可以看到volatile如何阻止gcc优化代码,但是在上面的示例中,该优化是正确的优化,因此不应添加volatile.
如果还有其他asm语句,尽管未使用其输出参数,但不应对其进行优化. 此时,应使用volatile.
希望对您有帮助.
结束.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-200715-1.html