簡體   English   中英

與gcc相比,為什么clang與寄存器變量表現得很奇怪?

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

背景:

我需要在c代碼中獲取寄存器值,所以我在gcc用法中找到了它。 我使用以下代碼獲取ebp值。

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

在我將程序的編譯器改為clang之前,一切似乎都沒問題。 在gcc中,它通常打印類似於0x7f1284978的東西,絕對是一個像值一樣的指針。

但是當使用clang時,輸出變得怪異,它打印出一個像0x9這樣的值。 Ebp必須不能有這樣的值。

QS:

  • clang是否不支持此寄存器變量用法?
  • 如果不支持此功能,為什么它沒有抱怨警告或錯誤(使用以下代碼編譯)?

     #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; } 

在Gcc中,register關鍵字執行以下操作(如下所述: 使用Gcc - 本地寄存器變量 ):

如果在Inline Assembly中使用變量,gcc將嘗試將其放入您指定的寄存器中。 在任何其他上下文中,register關鍵字沒有效果,並且如第一個鏈接的底部所示,在內聯匯編的輸入中指定變量是沒有其他選擇。

如果與clang一起使用,該關鍵字的作用我不知道,大多數可能只是被忽略(請參閱注冊表關鍵字是否仍在使用?

TL; DR:

Clang現在不支持顯式寄存器變量。

細節:

請參閱clang文檔

當指定的寄存器是不可分配的(例如堆棧指針)時,clang僅支持全局寄存器變量。 對通用全局寄存器變量的支持不太可能很快實現,因為它需要額外的LLVM后端支持。

在我的機器上(x86_64 ubuntu 16.04),如果我用Clang-5.0編譯,我得到的程序集是:

 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

如果我用GCC-5.5.0編譯,這是我得到的程序集:

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

我們可以看到GCC通常支持顯式寄存器值訪問,而Clang則不支持。

解:

如果你想使用Clang訪問ebp值,可以使用內聯匯編,如下所示: asm("\\t movl %%ebp,%0" : "=r"(vfp));

作為@ThePatrickStar和@Boden_Units的答案的補充:在LLVM IR生成期間,Clang Driver會刪除顯式寄存器初始化。 以下是運行clang -emit-llvm -S inline_asm.c -o inline_asm.ll (clang-7)時inline_asm.ll的內容。

; ModuleID = 'inline_asm.c'
source_filename = "inline_asm.c"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"

@vfp = internal global i64 563, align 8
@.str = private unnamed_addr constant [20 x i8] c"vfp value is 0x%lx\0A\00", align 1

; Function Attrs: noinline nounwind optnone uwtable
define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  %3 = load i32, i32* %2, align 4
  %4 = sext i32 %3 to i64
  store i64 %4, i64* @vfp, align 8
  %5 = load i64, i64* @vfp, align 8
  %6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([20 x i8], [20 x i8]* @.str, i32 0, i32 0), i64 %5)
  ret i32 0
}

declare dso_local i32 @printf(i8*, ...) #1

attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{!"clang version 7.0.1-svn348686-1~exp1~20190113235231.54 (branches/release_70)"}

實際上,生成的IR用於register int ebp asm("ebp"); register int ebp;沒有什么不同register int ebp; ,好像ebp從未初始化或綁定到ebp寄存器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM