Soru:
Değişken argüman işlevini tanımlama
Mellowcandle
2013-03-21 01:34:26 UTC
view on stackexchange narkive permalink

printf (char * format, ...) gibi bir C değişken bağımsız değişken işlevi, demonte edildiğinde nasıl görünür?

Her zaman kural çağırarak mı tanımlanır yoksa onu tanımlamanın başka yolları var mı?

Iki yanıtlar:
#1
+18
Igor Skochinsky
2013-03-21 05:14:36 UTC
view on stackexchange narkive permalink

Bazı mimarilerde çok basit, bazılarında ise çok açık değil. Aşina olduğum birkaç tanesini anlatacağım.

SystemV x86_64 (Linux, OS X, BSD)

Muhtemelen tanıması en kolay olanı. al 'da kullanılan XMM kayıtlarının sayısını belirtme konusundaki kafasız karar nedeniyle, çoğu vararg işlevi şu şekilde başlar:

  push rbp mov rbp, rsp sub rsp, 0E0h mov [rbp + var_A8], rsi mov [rbp + var_A0], rdx mov [rbp + var_98], rcx mov [rbp + var_90], r8 mov [rbp + var_88], r9 movzx eax, al lea rdx, ds: 0 [rax * 4] lea rax, loc_402DA1 sub rax, rdx lea rdx, [rbp + var_1] jmp rax movaps xmmword ptr [rdx-0Fh], xmm7 movaps xmmword ptr [rdx-1Fh], xmm6 movaps xmmword ptr [rdx-2Fh ], xmm5 movaps xmmword ptr [rdx-3Fh], xmm4 movaps xmmword ptr [rdx-4Fh], xmm3 movaps xmmword ptr [rdx-5Fh], xmm2 movaps xmmword ptr [rdx-6Fh], xmm1 movaps xmmword ptr [rdx ], xmm0loc_402DA1:  

Yığına kaç xmm kaydının dökülmesini belirlemek için al 'i nasıl kullandığına dikkat edin.

Windows x64 aka AMD64

Win64'te bu daha az açık, ama işte o ne işareti: eliptik parametrelere karşılık gelen yazmaçlar her zaman yığının üzerine ve yığında iletilen diğer argümanlarla aynı hizada olan konumlara dökülür. Örneğin. işte printf 'in prologu:

  mov rax, rsp mov [rax + 8], rcx mov [rax + 10h], rdx mov [rax + 18h] , r8 mov [rax + 20sa], r9  

Burada rcx , sabit format bağımsız değişkenini içerir ve eliptik bağımsız değişkenler rdx , r8 olarak iletilir ve r9 ve ardından yığında. rdx , r8 ve r9 'un tam olarak birbiri ardına ve rsp + 0x28 . [Rsp + 8..rsp + 0x28] alanı tam olarak bu amaç için ayrılmıştır, ancak vararg olmayan işlevler genellikle tüm yazmaç bağımsız değişkenlerini orada depolamaz veya bu alanı yerel değişkenler için yeniden kullanmaz. Örneğin, işte bir olmayan -vararg işlevi prologu:

  mov [rsp + 10h], rbx mov [rsp + 18h], rbp mov [rsp + 20h] , rsi  

Geçici olmayan kayıtları kaydetmek için ayrılmış alanı kullandığını ve kayıt argümanlarını yaymadığını görebilirsiniz.

ARM

ARM çağırma kuralı, ilk argümanlar için R0 - R3 'ü kullanır, bu nedenle vararg işlevlerinin, yığın üzerinde geçirilen diğer parametrelerle aynı hizaya gelmek için bunları yığına dökmesi gerekir. Böylece R0 - R3 (veya R1 - R3 veya R2 göreceksiniz - R3 veya sadece R3 ), genellikle vararg olmayan işlevlerde gerçekleşmeyen yığına itilir. % 100 kusursuz bir gösterge değildir - ör. Microsoft'un derleyicisi bazen R0 - R1 'i yığına iter ve diğer kayıtlara geçip onu kullanmak yerine SP kullanarak bunlara erişir. Ama bunun GCC için oldukça güvenilir bir işaret olduğunu düşünüyorum. GCC tarafından derlenen işlevin bir örneği:

  STMFD SP !, {R0-R3} LDR R3, = dword_86090STR LR, [SP, # 0x10 + var_14]! LDR R1, [SP, # 0x14 + varg_r0]; formatLDR R0, [R3]; sADD R2, SP, # 0x14 + varg_r1; argBL vsprintfLDR R3, = dword_86094MOV R2, # 1STR R2, [R3] LDR LR, [SP + 0x14 + var_14], # 4ADD SP, SP, # 0x10RET  

Açıkçası bu bir vararg işlevidir, çünkü vsprintf 'i çağırmaktadır ve R0 - R3 ' ün tam başlangıçta itildiğini görebiliriz ( Bundan önce başka hiçbir şeyi itmeyin çünkü potansiyel yığın bağımsız değişkenleri SP 'de mevcuttur ve bu nedenle R0 - R3 onlardan önce gelmelidir).

Harika, farklı senaryoları örneklerle parçalara ayırdığınız için teşekkürler!
#2
+10
Rolf Rolles
2013-03-21 01:40:29 UTC
view on stackexchange narkive permalink

(Cevabım x86'ya özgü).

İşleve içsel olarak, tıpkı diğer işlevler gibi görünür. Tek fark, işlev sırasında bir noktada, değişken olmayan son argümanın (yığın) adresini alacak ve onu platformdaki kelime boyutu kadar artıracaktır; bu daha sonra değişken argümanlarının tabanına bir işaretçi olarak kullanılır. İşleve harici olarak, işleve parametreler olarak farklı sayıda bağımsız değişken aktarıldığını gözlemleyeceksiniz (ve tipik olarak değişken olmayan bağımsız değişkenlerden biri, sabit kodlu bir biçim dizesi gibi bir değişken bağımsız değişken işlevi olarak bazı açık göstergeler olacaktır veya benzer bir şey). Değişken bağımsız değişken işlevleri __stdcall olamaz, çünkü __stdcall önceden derlenmiş ret XXh komutlarına dayanır, oysa bir değişken bağımsız değişken işlevinin amacı bilinmeyen parametre miktarı geçilebilir. Bu nedenle, bu işlevler __cdecl olmalıdır, yani arayan, tüm aktarılan bağımsız değişkenleri kaldırmak için yığını düzeltmelidir.



Bu Soru-Cevap, otomatik olarak İngilizce dilinden çevrilmiştir.Orijinal içerik, dağıtıldığı cc by-sa 3.0 lisansı için teşekkür ettiğimiz stackexchange'ta mevcuttur.
Loading...