2012-09-03 26 views
6

DWARF bilgilerinden çağrı kuralları hakkında bilgi almaya çalışıyorum. Daha spesifik olarak, argümanları işlevlere iletmek için hangi yazmaçların/yığın konumlarının kullanıldığını görmek istiyorum. Benim problemim, bazı durumlarda DWARF dökümünden yanlış bilgi alıyorum. cüce Dökümü almak için Şimdi aşağıdaki komutu kullandığınızdaDWARF bilgilerinden çağrıları çağırma

gcc -c -g -m32 test.c -o test.o 

:

int __attribute__ ((fastcall)) __attribute__ ((noinline)) mult (int x, int y) { 
return x*y; 
} 

aşağıdaki komutu kullanarak bu örneği derlemek: Ben kullanıyorum örnek aşağıdaki "C kodu" dir

< 2><0x00000042>  DW_TAG_formal_parameter 
         DW_AT_name     "x" 
         DW_AT_decl_file    0x00000001 /home/khaled/Repo_current/trunk/test.c 
         DW_AT_decl_line    0x00000001 
         DW_AT_type     <0x0000005b> 
         DW_AT_location    DW_OP_fbreg -12 
< 2><0x0000004e>  DW_TAG_formal_parameter 
         DW_AT_name     "y" 
         DW_AT_decl_file    0x00000001 /home/khaled/Repo_current/trunk/test.c 
         DW_AT_decl_line    0x00000001 
         DW_AT_type     <0x0000005b> 
         DW_AT_location    DW_OP_fbreg -16 
0123:
dwarfdump test.o 

bu işlevi hakkında aşağıdaki bilgileri alıyorum

DW_AT_location girişlerine bakıldığında, çerçeve tabanından bir miktar ofset. Bu onların bellek argümanları olduklarını ima eder, ancak gerçek çağrı kuralı "fastcall" güçleri onları kayıtlara geçirir. Üretilen nesne dosyasının sökülmesine bakarak, kayıtlardan işlevin giriş noktasında yığın konumlarına kopyalandıklarını görebiliyorum. Cüce çöplüğünden bilmenin bir yolu var mı - yoksa başka bir yolla-- argümanlar başlangıçta çağrıya geçtiğinde?

sayesinde

cevap

6

Eğer gcc -c -g -m32 test.c -o test.o kullandığınız çünkü. Bir fastcall işlevi olsa da, GCC hala işlevlerin başında yazmaçlardan yığıt çerçevesine değerleri kaydetmek için kod üretmesi gerekir. Bu olmadan, herhangi bir hata ayıklayıcı veya gdb programda hata ayıklayamaz veya argümanın optimize edildiğini ve gösterilmediğini söylerler. Hata ayıklamayı imkansız kılar.

x86_64'de, derleyici, bir işlev için öznitelik fastcall belirtilmeksizin, bazı argümanları varsayılan olarak geçmek için bazı yazmaçlar kullanır. Ayrıca bu kayıtların da yığına kopyalandığını görebilirsiniz.

// x86_64 assembly code 
_mult: 
Leh_func_begin1: 
     pushq %rbp 
Ltmp0: 
     movq %rsp, %rbp 
Ltmp1: 
     movl %edi, -4(%rbp) 
     movl %esi, -8(%rbp) 
     movl -4(%rbp), %eax 
     movl -8(%rbp), %ecx 
     imull %ecx, %eax 

optimizasyon bayrağı -O, -O2, -O3 (olursa olsun -g veya değil) açarsanız, size sökebilirsiniz ve yığın çerçeveye kopyalanan şey yok bulabilirsiniz. Optimize edilen yürütülebilir dosyayı gdb ve yerel değişkenleri göstermek için işlevin başında durduğunuzda, gdb bu argümanların optimize edildiğini size söyleyecektir.

32 bit programının dwarfdump örneği

0x00000083:  TAG_formal_parameter [4] 
       AT_name("x") 
       AT_decl_file("test.c") 
       AT_decl_line(1) 
       AT_type({0x0000005f} (int)) 
       AT_location(0x00000000 
        0x00000000 - 0x00000003: ecx 
        0x00000003 - 0x00000018: ecx) 

0x00000090:  TAG_formal_parameter [4] 
       AT_name("y") 
       AT_decl_file("test.c") 
       AT_decl_line(1) 
       AT_type({0x0000005f} (int)) 
       AT_location(0x0000001e 
        0x00000000 - 0x00000003: edx 
        0x00000003 - 0x00000018: edx) 

gibi görünecektir Ve oluşturulan derleme kod çok basit ve temiz bulabilirsiniz.

_mult: 
     pushl %ebp 
     movl %esp, %ebp 
     movl %ecx, %eax 
     imull %edx, %eax 
     popl %ebp 
     ret  $12