Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does clang behave weirdly with register variables compared to gcc?

Tags:

c

assembly

clang

Backgrounds:

I need to get the register value in the c code, so I found this in gcc usage. I get the ebp value using the following code.

   register int ebp asm("ebp");
   printf("currently ebp is %08x\n", ebp);
   // then some code use the value

Everything seems okay until I changed my program's compiler to clang. In gcc, it usually print something similar as 0x7f1284978, definitely a pointer like value.

But when use clang, output became weird, it print out a value like 0x9. Ebp must can't have a value like this.

Qs:

  • Does clang didn't support this register variable usage?
  • Why it didn't complain warning or error if it doesn't support this feature(using the following code to compile)?

    #include <stdio.h>
    
    static size_t vfp = 0x233;
    
    int main(void) {
        register int ebp asm("ebp");
        vfp = (size_t) ebp;
        printf("vfp value is 0x%lx\n", vfp);
        return 0;
    }
    
like image 703
occia Avatar asked Apr 12 '19 09:04

occia


People also ask

Does Clang optimize better than GCC?

Clang reduces the single-thread compilation time by 5% to 10% compared with GCC. Therefore, Clang offers more advantages for the construction of large projects.

Is Clang slower than GCC?

GCC is slower to compile than clang, so I spend a lot of time compiling, but my final system is (usually) faster with GCC, so I have set GCC as my system compiler.

Is Clang compatible with GCC?

GCC and C99 allow an array's size to be determined at run time. This extension is not permitted in standard C++. However, Clang supports such variable length arrays for compatibility with GNU C and C99 programs. If you would prefer not to use this extension, you can disable it with -Werror=vla.

Does Clang use Libstdc ++?

Clang supports use of either LLVM's libc++ or GCC's libstdc++ implementation of the C++ standard library.


1 Answers

TL;DR:

Clang does not support explicit register variable as for now.

Details:

See clang documentation

clang only supports global register variables when the register specified is non-allocatable (e.g. the stack pointer). Support for general global register variables is unlikely to be implemented soon because it requires additional LLVM backend support.

On my machine (x86_64 ubuntu 16.04), if I compile with Clang-5.0, the assembly I get is:

 08048410 <main>:
 8048410:       55                      push   %ebp
 8048411:       89 e5                   mov    %esp,%ebp
 8048413:       83 ec 18                sub    $0x18,%esp
 8048416:       8d 05 c0 84 04 08       lea    0x80484c0,%eax
 804841c:       8b 4d fc                mov    -0x4(%ebp),%ecx ;this line is wrong, the behavior is meaningless
 804841f:       89 0d 1c a0 04 08       mov    %ecx,0x804a01c
 8048425:       8b 0d 1c a0 04 08       mov    0x804a01c,%ecx
 804842b:       89 04 24                mov    %eax,(%esp)
 804842e:       89 4c 24 04             mov    %ecx,0x4(%esp)
 8048432:       e8 89 fe ff ff          call   80482c0 <printf@plt>
 8048437:       89 45 f8                mov    %eax,-0x8(%ebp)
 804843a:       83 c4 18                add    $0x18,%esp
 804843d:       5d                      pop    %ebp
 804843e:       c3                      ret
 804843f:       90                      nop

If I compile with GCC-5.5.0, this is the assembly I got:

0000051d <main>:


 51d:   8d 4c 24 04             lea    0x4(%esp),%ecx
 521:   83 e4 f0                and    $0xfffffff0,%esp
 524:   ff 71 fc                pushl  -0x4(%ecx)
 527:   55                      push   %ebp
 528:   89 e5                   mov    %esp,%ebp
 52a:   53                      push   %ebx
 52b:   51                      push   %ecx
 52c:   e8 33 00 00 00          call   564 <__x86.get_pc_thunk.ax>
 531:   05 a7 1a 00 00          add    $0x1aa7,%eax
 536:   89 ea                   mov    %ebp,%edx ; this is the correct location to get the value of ebp
 538:   89 90 30 00 00 00       mov    %edx,0x30(%eax)
 53e:   8b 90 30 00 00 00       mov    0x30(%eax),%edx
 544:   83 ec 08                sub    $0x8,%esp
 547:   52                      push   %edx
 548:   8d 90 18 e6 ff ff       lea    -0x19e8(%eax),%edx
 54e:   52                      push   %edx
 54f:   89 c3                   mov    %eax,%ebx
 551:   e8 5a fe ff ff          call   3b0 <printf@plt>
 556:   83 c4 10                add    $0x10,%esp
 559:   90                      nop
 55a:   8d 65 f8                lea    -0x8(%ebp),%esp
 55d:   59                      pop    %ecx
 55e:   5b                      pop    %ebx
 55f:   5d                      pop    %ebp
 560:   8d 61 fc                lea    -0x4(%ecx),%esp
 563:   c3                      ret

We can see that GCC generally supports explicit register value access while Clang does not.

Solution:

If you wish to use Clang to access ebp value, you can use inline assembly, like this: asm("\t movl %%ebp,%0" : "=r"(vfp));

like image 160
ThePatrickStar Avatar answered Sep 21 '22 01:09

ThePatrickStar