/* * The below program demonstrates a defeciency with gcc's constraint * syntax for 64-bit code: it's not possible to directly constrain an * operand to a register in the range r8 through r15. * * Furthermore, it is not possible to use '%rbp' in a constraint. * * It has been shown that gcc can assign a local variable to a * particular register * (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16331) but that does * not properly work when %rbp is being used. * * The code below executes a 'vmrun' instruction. The intent of the * inline assembly is to indicate that all the named registers can be * clobbered by the 'vmrun' instruction. * * For simplicity, I've only set '_rbp' to zero to show that this * local variable is assigned to '%rbp'. * * Here is a snippet of the code that is generated: * * * 32: 48 8b 2d 00 00 00 00 mov 0(%rip),%rbp # origRSP * 39: 48 8b 05 00 00 00 00 mov 0(%rip),%rax # &guestVMCB * 40: 31 ed xor %ebp,%ebp # zero _rbp * 42: 0f 01 d8 vmrun * 45: 48 8b 3d 00 00 00 00 mov 0(%rip),%rdi # 4c <test_function+0x3c> * 4c: 48 8d 75 f8 lea 0xfffffffffffffff8(%rbp),%rsi # origRSP - 8 * * * origRSP is allocated to '%rbp', and '_rsp' is allocated to the same * register. Even though '_rsp' is set to zero and 'vmrun' can * clobber all the named registers, the compiler still uses '%rbp' as * if it were not modified at address 0x4c. * * Also, to add to the unusual behavior, removing the function * 'SetupVMCB' causes the issue to vanish. SetupVMCB is unused. * * Using built-in specs. * Target: x86_64-redhat-linux * Configured with: ../configure --prefix=/usr \ * --mandir=/usr/share/man \ * --infodir=/usr/share/info \ * --enable-shared --enable-threads=posix \ * --enable-checking=release \ * --with-system-zlib --enable-__cxa_atexit \ * --disable-libunwind-exceptions --enable-libgcj-multifile \ * --enable-languages=c,c++,objc,obj-c++,java,fortran,ada \ * --enable-java-awt=gtk --disable-dssi --enable-plugin \ * --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre \ * --with-cpu=generic --host=x86_64-redhat-linux * Thread model: posix * gcc version 4.1.2 20071124 (Red Hat 4.1.2-42) * * * To build: * * gcc -O2 -c -o main.o main.c * objdump --disassemble main.o * */
typedef unsigned long uint64; typedef struct { unsigned char pad[256]; uint64 rsp; } VMCB; void failure(uint64 a, uint64 b); void SetupVMCB(uint64 rip, unsigned cpl); uint64 guestVMCB; volatile VMCB mappedGuestVMCB; static __attribute__((always_inline)) void VMRUN(uint64 vmcb) { register unsigned long _rbx asm("rbx"); register unsigned long _rcx asm("rcx"); register unsigned long _rdx asm("rdx"); register unsigned long _rbp asm("rbp") = 0; register unsigned long _rsi asm("rsi"); register unsigned long _rdi asm("rdi"); register unsigned long _r8 asm("r8"); register unsigned long _r9 asm("r9"); register unsigned long _r10 asm("r10"); register unsigned long _r11 asm("r11"); register unsigned long _r12 asm("r12"); register unsigned long _r13 asm("r13"); register unsigned long _r14 asm("r14"); register unsigned long _r15 asm("r15"); __asm__ __volatile__("vmrun" : "+c" (_rcx), "+d" (_rdx), "+b" (_rbx), "+r" (_rbp), "+S" (_rsi), "+D" (_rdi), "+r" (_r8), "+r" (_r9), "+r" (_r10), "+r" (_r11), "+r" (_r12), "+r" (_r13), "+r" (_r14), "+r" (_r15) : "a" (vmcb) : "memory"); } int test_function(void) { uint64 origRSP; origRSP = mappedGuestVMCB.rsp; VMRUN(guestVMCB); { uint64 _act = (mappedGuestVMCB.rsp); uint64 _exp = (origRSP - sizeof(unsigned long)); if (_exp != _act) { failure(_act, _exp); } } return 0; } void SetupVMCB(uint64 rip, unsigned cpl) { } -- Summary: gcc ignores use of %rbp via assembly, generates bad code Product: gcc Version: 4.1.2 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: thutt at vmware dot com http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38925