[LLVMdev] optimizer clobbering EFLAGS
Michael Hordijk
hoffbrinkle at hotmail.com
Wed Jul 29 07:54:10 PDT 2015
Using Clang/LLVM 3.6.0 we are observing a case where the optimizations
are clobbering EFLAGS on x86_64. This is inconvenient when the status
of bit 9 (IF), which controls interrupts, changes.
Here's a simple test program. Assume that the external function foo()
modifies the IF bit in EFLAGS.
#include <stdlib.h>
#include <stdbool.h>
void foo(void);
int a;
int bar(void)
{
foo();
bool const zero = a -= 1;
asm volatile ("" : : : "cc");
foo();
if (zero) {
return EXIT_FAILURE;
}
foo();
return EXIT_SUCCESS;
}
And it's compiled using the following command line:
clang -O2 -c -o clang-eflag.o clang-eflag.c
Produces this output:
$ objdump -S clang-eflag.o
clang-eflag.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <bar>:
0: 53 push %rbx
1: e8 00 00 00 00 callq 6 <bar+0x6>
6: ff 0d 00 00 00 00 decl 0x0(%rip) # c <bar+0xc>
c: 9c pushfq
d: 5b pop %rbx
e: e8 00 00 00 00 callq 13 <bar+0x13>
13: b8 01 00 00 00 mov $0x1,%eax
18: 53 push %rbx
19: 9d popfq
1a: 75 07 jne 23 <bar+0x23>
1c: e8 00 00 00 00 callq 21 <bar+0x21>
21: 31 c0 xor %eax,%eax
23: 5b pop %rbx
24: c3 retq
The critical bits here are that at 0xc/0xd, we save the value of EFLAGS
into %rbx. We then call foo() (which changes bit 9 of EFLAGS). We then
0x18/0x19 reload EFLAGS from the stale value in %rbx thus clobbering the
value of bit 9 leaving interrupts in an unexpected state.
You may notice that I've tried the asm volatile ("" : : : "cc")
constraint. The generated output is identical with and without the
constraint. Which is not totally surprising. I'm thinking that the
"cc" constraint tells the optimizer that "EFLAGS has been clobbered".
What we need is a way to tell the optimizer that "EFLAGS has been
clobbered and needs to be preserved."
- michael
More information about the llvm-dev
mailing list