请问:为什么加入__volatile__还是被优化?
请看:#include <stdio.h>
int main()
{
char input={"This is a test message.\n"};
char output;
int length=25;
__asm__ __volatile__("cld\n\t"
"rep movsb"
:
:"S"(input),"D"(output),"c"(length)
);
printf("%s\n",output);
return 0;
}
我是这样编译的:gcc -O asm1.c -o asm1,
可是我运行时,没有输出字符串;
如果我这样编译gcc asm1.c -o asm1
可以输出This is a test message.。
书上说加__volatile__,编译时不会被优化,
可是为什么我加了__volatile__,还是被优化,
请问为什么?怎么办?
本帖最后由 nswcfd 于 2016-07-13 20:51 编辑
比较一下汇编,并没有被优化掉
未优化的
0x00000000004004c4 <+0>: push %rbp
0x00000000004004c5 <+1>: mov %rsp,%rbp
0x00000000004004c8 <+4>: sub $0x50,%rsp
0x00000000004004cc <+8>: movl $0x73696854,-0x30(%rbp)
0x00000000004004d3 <+15>: movl $0x20736920,-0x2c(%rbp)
0x00000000004004da <+22>: movl $0x65742061,-0x28(%rbp)
0x00000000004004e1 <+29>: movl $0x6d207473,-0x24(%rbp)
0x00000000004004e8 <+36>: movl $0x61737365,-0x20(%rbp)
0x00000000004004ef <+43>: movl $0xa2e6567,-0x1c(%rbp)
0x00000000004004f6 <+50>: movl $0x0,-0x18(%rbp)
0x00000000004004fd <+57>: movw $0x0,-0x14(%rbp)
0x0000000000400503 <+63>: movl $0x19,-0x4(%rbp)
0x000000000040050a <+70>: lea -0x30(%rbp),%rax
0x000000000040050e <+74>: lea -0x50(%rbp),%rdx
0x0000000000400512 <+78>: mov -0x4(%rbp),%ecx
0x0000000000400515 <+81>: mov %rax,%rsi
0x0000000000400518 <+84>: mov %rdx,%rdi
0x000000000040051b <+87>: cld
0x000000000040051c <+88>: rep movsb %ds:(%rsi),%es:(%rdi)
0x000000000040051e <+90>: lea -0x50(%rbp),%rax
0x0000000000400522 <+94>: mov %rax,%rdi
0x0000000000400525 <+97>: callq0x4003b8 <puts@plt>
优化之后的
0x00000000004004c4 <+0>: sub $0x48,%rsp
0x00000000004004c8 <+4>: movl $0x73696854,0x20(%rsp)
0x00000000004004d0 <+12>:movl $0x20736920,0x24(%rsp)
0x00000000004004d8 <+20>:movl $0x65742061,0x28(%rsp)
0x00000000004004e0 <+28>:movl $0x6d207473,0x2c(%rsp)
0x00000000004004e8 <+36>:movl $0x61737365,0x30(%rsp)
0x00000000004004f0 <+44>:movl $0xa2e6567,0x34(%rsp)
0x00000000004004f8 <+52>:movl $0x0,0x38(%rsp)
0x0000000000400500 <+60>:movw $0x0,0x3c(%rsp)
0x0000000000400507 <+67>:lea 0x20(%rsp),%rsi
0x000000000040050c <+72>:mov %rsp,%rdi
0x000000000040050f <+75>:mov $0x19,%ecx
0x0000000000400514 <+80>:cld
0x0000000000400515 <+81>:rep movsb %ds:(%rsi),%es:(%rdi)
0x0000000000400517 <+83>:callq0x4003b8 <puts@plt>
rep movsb都在,只是执行完毕之后,rdi指向字符串的末尾。
未优化的场景,重新从栈上把目的地址找出来了。
而在优化的场景下,rdi原封不动的送给puts做参数了,所以打印的是outputs后面的随机内容。 两个办法,一个引入中间寄存器,并声明rdi可变
__asm__ __volatile__("cld\n\t"
"mov %1,%%rdi;"
"rep movsb"
:
:"S"(input),"r"(output),"c"(length)
:"rdi");
另一个方法是使用&修饰符,但需要引入一个临时变量
int di;
__asm__ __volatile__("cld; rep movsb": "=&D"(di) : "S"(input), "0"(output), "c"(length));
按照http://ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html#s7的例子,貌似把%edi放入clobber list就可以,但貌似不行,不知道为什么?
#define mov_blk(src, dest, numwords) \
__asm__ __volatile__ ( \
"cld\n\t" \
"rep\n\t" \
"movsl" \
: \
: "S" (src), "D" (dest), "c" (numwords)\
: "%ecx", "%esi", "%edi" \
) 按照 https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html 第 6.44.2.5 Input Operands 节的说法
When the compiler selects the registers to use to represent the input operands, it does not use any of the clobbered registers (see Clobbers).
那么,void test() { asm("nop"::"D"(1):"di"); } 出现如下错误也是合情合理的
<stdin>:1: error: can't find a register in class 'DIREG' while reloading 'asm'
<stdin>:1: error: 'asm' operand has impossible constraints
因为D类只有di一个寄存器,clobber又把它排除了,自然就没得选了。
不知道为什么楼上的帖子会那么用,估计是老版本的行为?
-----------------------------------------------------------------------------
PS,关于volatile的语义,上面链接的第 6.44.2.1 Volatile 节有几个很好的例子。
感觉extend asm不关心asm template里面的汇编语句是怎么写的? 完全按照input operand/output operand/clobber的约束声明来决定是否可以优化?
欢迎cpp编译大神归来
页:
[1]