2012-04-02 17 views
8

Ben C/Objective-C, bu arada Apple does it üzerinde hafif bir bükülme içinde üst düzey görüşme ile kullanmak için bazı trambolin fonksiyonları ile çalışıyorum.Çıkarma argümanlar, ARM montaj

sen hiç yolu Objective-C IMP eserlerine aşina iseniz, temelde void(*)(id obj, SEL sel, ...) gibi ilk iki argüman Bir mesajın alıcısı ve mesaj seçicinin adı verilebilir bir işlev işaretçisi, bu. çalışma zamanı daha yeni sürümleri yöntem uygulamaları void(^)(id obj, ...) gibi, C blokları kullanarak çalışma zamanında sentezlenmiş izin verir. Bu bloklar seçiciye sahip değil; Çalışma zamanı alıcı ile seçici, blok işaretçi ile alıcı üzerine yazar bir trambolini oluşturur ve çalıştırmadan hareket eder.

bu bloğa argümanlar geleneksel yöntem send argümanlar tamamen aynı olacak şekilde, ilk iki bağımsız değişken ya olmamasından içerir belli belirsiz benzer bir şey yapmak istiyorum, artı yürütülmesi için blok işaretçisi amaçları, yani void(*)(Block *, ...). Bu sadece blok göstericide kopyalama gerektirir ve sanırım bir argümandan kurtulmayı düşünüyorum. İşte

__a1a2_tramphead_argonly: 
    popl %eax 
    andl $0xFFFFFFF8, %eax 
    subl $0x1000, %eax 
    movl 4(%esp), %ecx // self -> ecx 
    movl %ecx, 8(%esp) // ecx -> _cmd 
    movl (%eax), %ecx // blockPtr -> ecx 
    movl %ecx, 4(%esp) // ecx -> self 
    jmp *12(%ecx) // tail to block->invoke 

Ben ARM üzerindeki montaj var:

__a1a2_tramphead_argonly: 
    // calculate the trampoline's index (512 entries, 8 bytes each) 
#ifdef _ARM_ARCH_7 
    // PC bias is only 4, no need to correct with 8-byte trampolines 
    ubfx r1, r1, #3, #9 
#else 
    sub r1, r1, #8    // correct PC bias 
    lsl r1, r1, #20 
    lsr r1, r1, #23 
#endif 

    // load block pointer from trampoline's data 
    adr r12, __a1a2_tramphead_argonly // text page 
    sub r12, r12, #4096   // data page precedes text page 
    ldr r12, [r12, r1, LSL #3] // load block pointer from data + index*8 

    // shuffle parameters 
    mov r1, r0     // _cmd = self 
    mov r0, r12     // self = block pointer 

    // tail call block->invoke 
    ldr pc, [r12, #12] 

Benzer kod x86_64 için var; Yukarıdaki kod bu yüzden doğrudan Apple’dan. (Reciever olarak kullanılan) İlk argüman bloğu değişmezi olacak şekilde kişisel bilgi için, ben ikinci ilk gerçek argüman olduğunu ve benzerleri, nerede bir tartışma excising ile başlamak merak ediyorum.

Ben ASM de inanılmaz noobish değilim, bu yüzden herhangi bir yardım büyük beğeni topluyor. Denediğim her şey gittikçe ilginç şekillerde patladı. Şimdiden teşekkürler.

+1

Dikkat edin, birçok Linux dağıtımı şu anda ARM Sert Şamandıra ABI'ye geçme aşamasındadır. Bu yine sizin için her şeyi kırmayacak. – ams

+0

Bu ilginç, gelecek için aklımda tutacağım. Bununla birlikte, bu çoğunlukla Darwin'i hedeflemektedir. Teşekkür ederim! Düzenleme: Bu, en azından şimdilik, ARMV6 ve ARMV7 anlamına gelir. – zwaldowski

cevap

2

iOS ABI, AAPCS'yi etkin bir şekilde kullanır ve yalnızca farklılıkları tanımlar, bu nedenle önce http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ihi0042d/index.html ile başlamak isteyeceksiniz. Sonra (Ben erişmeye ücretli bir iOS Dev Center üyeliği gerek) Apple'ın iOS ABI işlev çağrısı Kılavuzu'nu okuyun.

bir objc IMP ulaşmak için, kural Özetleme:

  • kendini R0 gider
  • _cmd R1
  • birinci int veya işaretçi bağımsız değişken R2 gider
  • ikinci int veya işaretçi değişkeni gider
  • diğer tüm argümanlar yığın devam R3 gider
mov r0, r2 
mov r1, r3 
:Yani, sadece en fazla 2 parametreler, onları kayan nokta/int64_t/yapı hiçbiri, kendini ve _cmd argümanları kaldırmak ile argümanlar bakıyorsanız R0-R4 karıştırma meselesi olduğunu Apple'ın blok trambolin durumunda

mov r3, r1 
mov r2, r0 
ldr r1, [address of _cmd] 
ldr r0, [address of self] 

, onlar değiştiriyor ne yaptığınızı:

Veya iki params alır ve kendini crams ve IMP iletilmeden hemen önce de _cmd bir işlev yazmak için, sadece bu var [foo performBlockOnSelf: block] işlevine etkin bir şekilde [blok foo] çağrısı.Söylediğiniz gibi, blok işaretleyici r0 (normal self pozisyon) ile biter ve hedef parametre foo r1 (normal _cmd pozisyonu) ile biter. Eğer bloklar gerçekten IMP'ler olsaydı, elbette, bu saçmalık olurdu, çünkü foo bir SEL değil, ama değil, bu yüzden sorun değil.

Bildirinizden "İlk iki argümana sahip olmamayı gerektiren belli belirsiz bir şey yapmak istiyorum, böylece bu bloğa verilen argümanlar, geleneksel yöntemin argümanlarıyla tam olarak aynıdır,"

  1. (C# açısından) bir "temsilci" nesnesi tanımlayın, temelde hedefine sahip bir blok inşaat anda pişmiş: Eğer yapmaya çalıştığını iki şeyden hangisinin tam olarak net değildir. Bu durumda, sadece blok gösterici yerine, r0 (blok işaretçisi) ve r1 (hedef) bazı temsilciler tablosundan bakmak isteyeceksiniz. Ancak, bu tabloyu oluşturan herhangi bir derleyici yardımına sahip olmayacaksınız - bu da onu ayarlayıp saf C'ye erişebileceğiniz anlamına gelir ve aynı zamanda uygun montaj ve özel bir montaj trambolini oluşturacaktır. (Uygulamada önemli olmayan bir performans kaybıyla ObjC sözlüklerinde bile bunu yapabilirsiniz.)

  2. Her şeyin saklanmasını sağlayan bir bloğa normal bir iletiyi döndürün, böylece Apple'ın trambolin kodu aramaya çalıştığında Geleneksel yöntemle sona eren blok, blok parametreleri yerine parametreler gönderir. Bu sizin hedefinizse, mesajları bloklara dönüştürmeye çalışmak yerine mesajın etrafında bir blok sarmalayıcı kullanmak daha basit ve çok daha güvenlidir ve bununla ilgili verimlilik veya esneklik maliyetleri olduğundan şüphelenirim.

+0

Yanıtlamak için bu kadar uzun sürdüğüm için özür dilerim, bunu Nisan ayında istediğim şeyden bu yana uygun bir cevap olarak tekrar ekledim ve işaretledim. Benzer şeyler yapan bazı insanlarla görüştükten sonra, libffi'yi kullanarak bir çözüm bulduk. İkinci argümanı (_cmd) kaldırmak kesinlikle zorunluydu. Tartışmaların ön yüklemesi arasında (en azından ARM'de), çerçevemizin kullanıcılarını dört argüman veya gergin olmayan yöntemlerle sınırlamaksızın yapmak zor olurdu. Nihai çözümümüz selefinden daha hızlı ve daha işlevseldi, ben de mutluyum. Teşekkürler! – zwaldowski