ARM Özel Durum İşleme

ARM üzerinde Windows, zaman uyumsuz donanım tarafından oluşturulan özel durumlar ve zaman uyumlu yazılım tarafından oluşturulan özel durumlar için aynı yapılandırılmış özel durum işleme mekanizmasını kullanır. Dile özgü özel durum işleyicileri, dil yardımcı işlevleri kullanılarak Windows yapılandırılmış özel durum işleme üzerine oluşturulur. Bu belgede ARM üzerinde Windows'ta özel durum işleme açıklanır ve hem Microsoft ARM derleyicisi hem de MSVC derleyicisi tarafından oluşturulan dil yardımcıları açıklanır.

ARM Özel Durum İşleme

ARM üzerinde Windows, yapılandırılmış özel durum işleme (SEH) sırasında yığın geri sarmayı denetlemek için geri alma kodlarını kullanır. Geri sarma kodları, yürütülebilir görüntünün bölümünde depolanan .xdata bayt dizisidir. Bu kodlar, işlev prolog ve epilog kodunun çalışmasını soyut bir şekilde açıklar. İşleyici, çağıranın yığın çerçevesine geri geldiğinde işlev prologue'un etkilerini geri almak için bunları kullanır.

ARM EABI (katıştırılmış uygulama ikili arabirimi), geri alma kodları kullanan özel durum geri sarma için bir model belirtir. Model, SEH'nin Windows'ta gevşemesinde yeterli değildir. İşlemcinin bir işlevin prologunun veya entrikasının ortasında olduğu zaman uyumsuz durumları işlemelidir. Windows ayrıca, arm EABI'de birleştirilmiş olan işlev düzeyinde geri sarma ve dile özgü kapsam geri alma işlemlerine de ayrı ayrı denetim ekler. Bu nedenlerden dolayı ARM üzerinde Windows, geri sarmalama verileri ve yordamı için daha fazla ayrıntı belirtir.

Varsayımlar

ARM üzerinde Windows için yürütülebilir görüntüler Taşınabilir Yürütülebilir Dosya (PE) biçimini kullanır. Daha fazla bilgi için bkz . PE Biçimi. Özel durum işleme bilgileri görüntünün ve .xdata bölümlerinde depolanır.pdata.

Özel durum işleme mekanizması, ARM üzerinde Windows için ABI'yi izleyen kod hakkında belirli varsayımlarda bulunur:

  • bir işlevin gövdesinde bir özel durum oluştuğunda, işleyici prologue'un işlemlerini geri alabilir veya epilogue işlemlerini ileriye doğru yapabilir. Her ikisi de aynı sonuçları üretmelidir.

  • Prologlar ve epiloglar birbirini yansıtma eğilimindedir. Bu özellik, geri alma işlemini açıklamak için gereken meta verilerin boyutunu küçültmek için kullanılabilir.

  • İşlevler görece küçük olma eğilimindedir. Çeşitli iyileştirmeler, verilerin verimli bir şekilde paketlenmesi için bu gözleme dayanır.

  • Bir koşul bir epilog üzerine yerleştirilirse, epilogdaki her yönergeye eşit olarak uygulanır.

  • Prologue, yığın işaretçisini (SP) başka bir yazmaçta kaydederse, özgün SP'nin herhangi bir zamanda kurtarılabilmesi için bu yazmaç işlevin tamamında değişmeden kalmalıdır.

  • SP başka bir kayıt defterine kaydedilmediği sürece, tüm işlemesi kesinlikle prolog ve epilog içinde gerçekleşmelidir.

  • Herhangi bir yığın çerçevesini geri almak için bu işlemler gereklidir:

    • r13(SP) ayarını 4 baytlık artışlarla yapın.

    • Bir veya daha fazla tamsayı yazmaçları açılır.

    • Bir veya daha fazla VFP (sanal kayan nokta) kaydı açılır.

    • Rastgele bir yazmaç değerini r13'e (SP) kopyalayın.

    • Küçük bir azaltma sonrası işlemi kullanarak yığından SP yükleyin.

    • birkaç iyi tanımlanmış çerçeve türünden birini ayrıştırın.

.pdata Kayıt

.pdata PE biçimindeki bir görüntüdeki kayıtlar, her yığın işleme işlevini açıklayan sıralı bir sabit uzunluklu öğe dizisidir. Yaprak işlevleri (diğer işlevleri çağırmayen işlevler), yığını işlemezken kayıt gerektirmez .pdata . (Başka bir ifadeyle, herhangi bir yerel depolama alanı gerektirmezler ve geçici olmayan yazmaçları kaydetmeleri veya geri yüklemeleri gerekmez.) Alandan tasarruf etmek için bu işlevlerin kayıtları bölümünden .pdata atlanabilir. Bu işlevlerden birinin geri sarma işlemi, çağırana gitmek için bağlantı yazmacından (LR) dönüş adresini program sayacına (PC) kopyalayabilir.

ARM için her .pdata kayıt 8 bayt uzunluğundadır. Kaydın genel biçimi, işlevin göreli sanal adresini (RVA) ilk 32 bit sözcükte başlatır ve ardından değişken uzunlukta .xdata bir bloğun işaretçisini içeren ikinci bir sözcüğü veya bu tabloda gösterildiği gibi kurallı işlevin geri sarma dizisini açıklayan paketlenmiş bir sözcüğü içerir:

Sözcük Uzaklığı Bits Purpose
0 0-31 Function Start RVA işlevin başlangıcının 32 bit RVA'sıdır. İşlev başparmak kodu içeriyorsa, bu adresin düşük biti ayarlanmalıdır.
1 0-1 Flag , ikinci .pdata sözcüğün kalan 30 bitinin nasıl yorumlandığını gösteren 2 bitlik bir alandır. 0 ise Flag , kalan bitler bir Özel Durum Bilgisi RVA'sı oluşturur (düşük iki bit örtük olarak 0 ile). Flag Sıfır değilse, kalan bitler Paketlenmiş Geri Sarma verilerinin yapısını oluşturur.
1 2-31 Özel Durum Bilgileri RVA veya Paketlenmiş Geri Sarma Verileri.

Özel Durum Bilgileri RVA , bölümünde depolanan değişken uzunluklu özel durum bilgisi yapısının .xdata adresidir. Bu verilerin 4 bayt hizalanmış olması gerekir.

Paketlenmiş Geri Sarma Verileri , kurallı bir form varsayılarak işlevden geri sarmak için gereken işlemlerin sıkıştırılmış bir açıklamasıdır. Bu durumda kayıt .xdata gerekmez.

Paketlenmiş Geri Sarma Verileri

Prologları ve epilogları aşağıda açıklanan kurallı biçimi izleyen işlevler için paketlenmiş geri sarma verileri kullanılabilir. Kayıt gereksinimini .xdata ortadan kaldırır ve geri sarma verilerini sağlamak için gereken alanı önemli ölçüde azaltır. Kurallı prologlar ve özetler, özel durum işleyicisi gerektirmeyen basit bir işlevin ortak gereksinimlerini karşılamak için tasarlanmıştır ve kurulum ve silme işlemlerini standart bir sırada gerçekleştirir.

Bu tabloda, geri sarma verilerinin paketlendiği bir .pdata kaydın biçimi gösterilir:

Sözcük Uzaklığı Bits Purpose
0 0-31 Function Start RVA işlevin başlangıcının 32 bit RVA'sıdır. İşlev başparmak kodu içeriyorsa, bu adresin düşük biti ayarlanmalıdır.
1 0-1 Flag , şu anlamlara sahip 2 bitlik bir alandır:

- 00 = paketlenmiş geri alma verileri kullanılmaz; kalan bitler kayda işaret .xdata eder.
- 01 = paketlenmiş geri sarma verileri.
- 10 = işlevin prolog olmadığı varsayıldığı paketlenmiş geri sarma verileri. Bu, işlevin başlangıcıyla ilgisi olmayan işlev parçalarını tanımlamak için kullanışlıdır.
- 11 = ayrılmış.
1 2-12 Function Length , tüm işlevin uzunluğunu 2'ye bölünen bayt cinsinden sağlayan 11 bitlik bir alandır. İşlev 4K bayttan büyükse, bunun yerine tam .xdata kayıt kullanılmalıdır.
1 13-14 Ret işlevin nasıl döndürdüğünü gösteren 2 bitlik bir alandır:

- 00 = pop {pc} aracılığıyla döndür (bu durumda bayrak biti L 1 olarak ayarlanmalıdır).
- 01 = 16 bit dal kullanarak dönüş.
- 10 = 32 bit dal kullanarak dönüş.
- 11 = hiç epilog yok. Bu, yalnızca bir prolog içerebilen ancak başka bir yerde olan bitişik olmayan bir işlev parçasını tanımlamak için kullanışlıdır.
1 15 H , tamsayı parametresinin yazmaçlarını (r0-r3) işlevin başında göndererek "homes" işlevinin (r0-r3) çalışıp çalışmadığını gösteren ve döndürmeden önce 16 bayt yığını serbest bırakan 1 bitlik bir bayraktır. (0 = ev kayıtları değil, 1 = ev kayıtları.)
1 16-18 Reg , son kaydedilen geçici olmayan kaydın dizinini gösteren 3 bitlik bir alandır. R Bit 0 ise, yalnızca tamsayı yazmaçları kaydedilir ve n değeri 4 + Regdeğerine eşit olan r4-rN aralığında olduğu varsayılır. R Bit 1 ise, yalnızca kayan nokta yazmaçları kaydedilir ve N'nin 8 + Regdeğerine eşit olduğu d8-dN aralığında olduğu varsayılır. = 1 ve Reg = 7'nin R özel birleşimi hiçbir yazmaç kaydedilmediğini gösterir.
1 19 R , kaydedilen geçici olmayan yazmaçların tamsayı yazmaçları (0) veya kayan noktalı yazmaçlar (1) olup olmadığını gösteren 1 bitlik bir bayraktır. 1 olarak ayarlanırsa ve Reg alan 7 olarak ayarlanırsa R geçici olmayan kayıt gönderilmez.
1 20 L , işlevin LR'yi kaydedip kaydetmediğini/geri yükleyip yüklemediğini ve alan tarafından Reg belirtilen diğer yazmaçları gösteren 1 bitlik bir bayraktır. (0 = kaydetmez/geri yüklemez, 1 = kaydeder/geri yükler.)
1 21 C , işlevin hızlı yığın yürüyüş (1) veya değil (0) için çerçeve zinciri ayarlamaya yönelik ek yönergeler içerip içermediğini gösteren 1 bitlik bir bayraktır. Bu bit ayarlanırsa, r11 geçici olmayan tamsayı kayıtları listesine örtük olarak eklenir. (Bayrak kullanılıyorsa aşağıdaki kısıtlamalara C bakın.)
1 22-31 Stack Adjust , bu işlev için ayrılan yığın bayt sayısını 4'e bölünen 10 bitlik bir alandır. Ancak, yalnızca 0x000-0x3F3 arasındaki değerler doğrudan kodlanabilir. 4044 bayttan fazla yığın ayıran işlevlerin tam .xdata kayıt kullanması gerekir. Stack Adjust Alan 0x3F4 veya daha büyükse, düşük 4 bitin özel anlamı vardır:

- Bit 0-1, yığın ayarlama (1-4) eksi 1 sözcük sayısını gösterir.
- Prolog bu ayarlamayı gönderme işlemiyle birleştirdiyse bit 2 1 olarak ayarlanır.
- Epilog bu ayarı pop işlemiyle birleştirdiyse bit 3 1 olarak ayarlanır.

Yukarıdaki kodlamalardaki olası yedekliliklerden dolayı bu kısıtlamalar geçerlidir:

  • C Bayrak 1 olarak ayarlandıysa:

    • Çerçeve L zincirleme hem r11 hem de LR gerektirdiğinden bayrağın da 1 olarak ayarlanması gerekir.

    • r11, tarafından Regaçıklanan kayıt kümesine dahil edilmemelidir. Yani, r4-r11 gönderiliyorsa, Reg bayrak r11'i ima ettiğinden C yalnızca r4-r10'un açıklanmalıdır.

  • Ret Alan 0 olarak ayarlandıysa, L bayrak 1 olarak ayarlanmalıdır.

Bu kısıtlamaları ihlal etmek desteklenmeyen bir diziye neden olur.

Aşağıdaki tartışmanın amaçları doğrultusunda, iki sahte bayrak şunlardan Stack Adjusttüretilir:

  • PF veya "prologue folding" 0x3F4 veya daha büyük olduğunu Stack Adjust ve bit 2'nin ayarlandığını gösterir.

  • EF veya "epilog katlama" 0x3F4 veya daha büyük olduğunu ve 3. bitin ayarlandığını gösterir Stack Adjust .

Kurallı işlevler için prologların en fazla 5 yönergesi olabilir (3a ve 3b'nin birbirini dışlayan yönergeler olduğuna dikkat edin):

Talimat İşlem kodu şu durumda olduğu varsayılır: Size Işlem kodu Geri Sarma Kodları
1 H==1 16 push {r0-r3} 04
2 C==1 veya L==1 veya R==0 veya PF==1 16/32 push {registers} 80-BF/D0-DF/EC-ED
3a C==1 ve (R==1 ve PF==0) 16 mov r11,sp FB
3b C==1 ve (R==0 veya PF==1) 32 add r11,sp,#xx FC
4 R==1 ve Reg != 7 32 vpush {d8-dE} E0-E7
5 Stack Adjust != 0 ve PF==0 16/32 sub sp,sp,#xx 00-7F/E8-EB

Bit 1 olarak ayarlandıysa H yönerge 1 her zaman mevcuttur.

Çerçeve zincirini ayarlamak için, bit ayarlandıysa 3a veya 3b yönergesi C bulunur. r11 ve LR dışında hiçbir yazmaç gönderilmezse 16 bittir mov ; aksi takdirde 32 bit addolur.

Katlanmamış bir ayarlama belirtilirse, yönerge 5 açık yığın ayarıdır.

2. ve 4. yönergeler, gönderim gerekip gerekmediğine göre ayarlanır. Bu tabloda, , , LRve PF alanlarına göre hangi kayıtların Ckaydedildiği özetlenir. Her durumda , N + 4'e Reg eşittir, E + 8'e Reg eşittir ve S (~Stack Adjust) & 3'e eşittir.

C L R PF Gönderilen Tamsayı Yazmaçları VFP Yazmaçları gönderildi
0 0 0 0 r4 - r*N* yok
0 0 0 1 r*S* - r*N* yok
0 0 1 0 yok d8 - d*E*
0 0 1 1 r*S* - r3 d8 - d*E*
0 1 0 0 r4 - r**N, LR yok
0 1 0 1 r*S* - r**N, LR yok
0 1 1 0 LR d8 - d*E*
0 1 1 1 r*S* - r3, LR d8 - d*E*
1 0 0 0 (geçersiz kodlama) (geçersiz kodlama)
1 0 0 1 (geçersiz kodlama) (geçersiz kodlama)
1 0 1 0 (geçersiz kodlama) (geçersiz kodlama)
1 0 1 1 (geçersiz kodlama) (geçersiz kodlama)
1 1 0 0 r4 - r**N, r11, LR yok
1 1 0 1 r*S* - r**N, r11, LR yok
1 1 1 0 r11, LR d8 - d*E*
1 1 1 1 r*S* - r3, r11, LR d8 - d*E*

Kurallı işlevlerin epilogları benzer bir biçimi izler, ancak tersten ve bazı ek seçeneklerle. Epilog en fazla 5 yönerge uzunluğunda olabilir ve formu kesinlikle prolog formu tarafından dikte edilir.

Talimat İşlem kodu şu durumda olduğu varsayılır: Size Işlem kodu
6 Stack Adjust!=0 ve EF==0 16/32 add sp,sp,#xx
7 R==1 ve Reg!=7 32 vpop {d8-dE}
8 C==1 veya (L==1 ve (H==0 veya Ret !=0)) veya R==0 veya EF==1 16/32 pop {registers}
9a H==1 ve (L==0 veya Ret!=0) 16 add sp,sp,#0x10
9b H==1 ve L==1 ve Ret==0 32 ldr pc,[sp],#0x14
10a Ret==1 16 bx reg
10b Ret==2 32 b address

6. yönerge, katlanmamış bir ayarlama belirtilirse açık yığın ayarlamasıdır. bağımsız PF olduğundan EF, yönerge 6 olmadan 5 yönergesinin mevcut olması veya tam tersi mümkündür.

7. ve 8. yönergeler, hangi yazmaçların yığından geri yükleneceğini belirlemek için prolog ile aynı mantığı kullanır, ancak şu üç değişiklikle birlikte: birincisi; EF ikinci yerine kullanılırPF, eğer = 0 ve H = 0 ise Ret , LR yazmaç listesindeki bilgisayarla değiştirilir ve epilogue hemen biter; üçüncü, eğer = 0 ve H = 1 ise Ret , daha sonra LR yazmaç listesinden atlanır ve 9b yönergesi tarafından gösterilir.

Ayarlanırsa H , 9a veya 9b yönergesi vardır. Yönerge 9a, sıfır olmayan olduğunda Ret kullanılır, bu da 10a veya 10b varlığını gösterir. L=1 ise, 8. yönergenin bir parçası olarak LR ortaya çıktı. Yönerge 9b, 1 olduğunda ve Ret sıfır olduğundaL, en erken sonu belirtmek ve yığını aynı anda geri döndürmek ve ayarlamak için kullanılır.

Epilog henüz sona ermediyse, değerine bağlı olarak 16 bit veya 32 bit dal belirtmek için 10a veya 10b yönergesi Retvardır.

.xdata Kayıt

Paketlenmiş geri sarma biçimi bir işlevin geri sarmasını açıklamak için yetersizse, değişken uzunlukta .xdata bir kayıt oluşturulmalıdır. Bu kaydın adresi, kaydın ikinci sözcüğünde .pdata depolanır. biçimi .xdata , dört bölümü olan paketlenmiş, değişken uzunlukta bir sözcük kümesidir:

  1. Yapının genel boyutunu açıklayan ve anahtar işlev verileri sağlayan 1 veya 2 sözcüklü .xdata üst bilgi. İkinci sözcük yalnızca Epilogue Sayısı ve Kod Sözcükleri alanlarının her ikisi de 0 olarak ayarlandığında bulunur. Alanlar bu tabloda ayrılmış:

    Word Bits Purpose
    0 0-17 Function Length , işlevin toplam uzunluğunu bayt cinsinden 2'ye bölünen 18 bitlik bir alandır. Bir işlev 512 KB'tan büyükse, işlevi tanımlamak için birden çok .pdata ve .xdata kayıt kullanılmalıdır. Ayrıntılar için bu belgenin Büyük İşlevler bölümüne bakın.
    0 18-19 Vers , kalan.xdata sürümü açıklayan 2 bitlik bir alandır. Şu anda yalnızca sürüm 0 tanımlanmıştır; 1-3 değerleri ayrılmıştır.
    0 20 X , özel durum verilerinin varlığını (1) veya devamsızlığı (0) gösteren 1 bitlik bir alandır.
    0 21 E , tek bir epilogu açıklayan bilgilerin daha sonra ek kapsam sözcükleri (0) gerektirmek yerine üst bilgide (1) paketlendiğini gösteren 1 bitlik bir alandır.
    0 22 F , bu kaydın bir işlev parçasını (1) veya tam işlevi (0) tanımladığını belirten 1 bitlik bir alandır. Bir parça, prolog olmadığını ve tüm prolog işlemlerin yoksayılması gerektiğini ifade eder.
    0 23-27 Epilog Sayısı , bitin E durumuna bağlı olarak iki anlamı olan 5 bitlik bir alandır:

    - 0 ise E , bu alan bölüm 2'de açıklanan genel kapsamların toplam sayısıdır. İşlevde 31'den fazla kapsam varsa, uzantı sözcüğünün gerekli olduğunu belirtmek için bu alanın ve Kod Sözcükleri alanının her ikisi de 0 olarak ayarlanmalıdır.
    - 1 ise E , bu alan tek epilogu açıklayan ilk geri sarma kodunun dizinini belirtir.
    0 28-31 Kod Sözcükleri , bölüm 4'teki tüm geri sarma kodlarını içermek için gereken 32 bit sözcük sayısını belirten 4 bitlik bir alandır. 63'ten fazla geri sarma kodu bayt için 15'ten fazla sözcük gerekiyorsa, uzantı sözcüğünün gerekli olduğunu belirtmek için bu alanın ve Özet Sayısı alanının her ikisi de 0 olarak ayarlanmalıdır.
    1 0-15 Genişletilmiş Epilogue Sayısı , olağan dışı derecede çok sayıda epilogu kodlamak için daha fazla alan sağlayan 16 bitlik bir alandır. Bu alanı içeren uzantı sözcüğü yalnızca ilk üst bilgi sözcüğündeki Epilog Sayısı ve Kod Sözcükleri alanları 0 olarak ayarlanmışsa bulunur.
    1 16-23 Genişletilmiş Kod Sözcükleri , çok fazla sayıda geri sarma kodu sözcüğü kodlamak için daha fazla alan sağlayan 8 bitlik bir alandır. Bu alanı içeren uzantı sözcüğü yalnızca ilk üst bilgi sözcüğündeki Epilog Sayısı ve Kod Sözcükleri alanları 0 olarak ayarlanmışsa bulunur.
    1 24-31 Ayrıldı
  2. Özel durum verilerinden sonra (üst bilgideki bit 0 olarak ayarlandıysa E ), bir sözcükle paketlenmiş ve başlangıç uzaklığını artırmak için depolanan en son kapsamlar hakkındaki bilgilerin listesidir. Her kapsam şu alanları içerir:

    Bits Purpose
    0-17 Epilogue Başlangıç Uzaklığı , işlevin başlangıcına göre 2'ye bölünen bayt cinsinden epilogun uzaklığını açıklayan 18 bitlik bir alandır.
    18-19 Res , gelecekteki genişletme için ayrılmış 2 bitlik bir alandır. Değeri 0 olmalıdır.
    20-23 Koşul , epilojinin yürütüldiği koşulu veren 4 bitlik bir alandır. Koşulsuz epiloglar için, "her zaman" ifadesini gösteren 0xE olarak ayarlanmalıdır. (Bir epilog tamamen koşullu veya tamamen koşulsuz olmalıdır ve Thumb-2 modunda, epilog BT opcode'undan sonraki ilk yönergeyle başlar.)
    24-31 Epilogue Başlangıç Dizini , bu entrikayı açıklayan ilk geri sarma kodunun bayt dizinini gösteren 8 bitlik bir alandır.
  3. En son kapsamlar listesi geldikten sonra, bu makalenin Geri Sarma Kodları bölümünde ayrıntılı olarak açıklanan, geri alma kodları içeren bir bayt dizisi gelir. Bu dizi, en yakın tam sözcük sınırına uçta doldurulur. Baytlar, küçük endian modunda doğrudan getirilebilmesi için küçük endian sırada depolanır.

  4. Üst bilgideki X alanı 1 ise, geri sarma kodu baytlarının ardından özel durum işleyicisi bilgileri eklenir. Bu, özel durum işleyicisinin adresini içeren bir Özel Durum İşleyici RVA'sını ve ardından hemen özel durum işleyicisi tarafından gerekli olan (değişken uzunluklu) veri miktarını içerir.

Kayıt .xdata , izleyen değişken boyutlu özel durum verilerinin uzunluğu dahil olmak üzere ilk 8 baytı getirmek ve kaydın tam boyutunu hesaplamak mümkün olacak şekilde tasarlanmıştır. Bu kod parçacığı kayıt boyutunu hesaplar:

ULONG ComputeXdataSize(PULONG Xdata)
{
    ULONG Size;
    ULONG EpilogueScopes;
    ULONG UnwindWords;

    if ((Xdata[0] >> 23) != 0) {
        Size = 4;
        EpilogueScopes = (Xdata[0] >> 23) & 0x1f;
        UnwindWords = (Xdata[0] >> 28) & 0x0f;
    } else {
        Size = 8;
        EpilogueScopes = Xdata[1] & 0xffff;
        UnwindWords = (Xdata[1] >> 16) & 0xff;
    }

    if (!(Xdata[0] & (1 << 21))) {
        Size += 4 * EpilogueScopes;
    }

    Size += 4 * UnwindWords;

    if (Xdata[0] & (1 << 20)) {
        Size += 4;  // Exception handler RVA
    }

    return Size;
}

Prologue ve her epilog unwind kodları için bir dizine sahip olsa da, tablo bunlar arasında paylaşılır. Hepsinin aynı geri alma kodlarını paylaşabilmesi nadir bir durum değildir. Belirtilebilen en büyük dizin 255 olduğundan ve belirli bir işlev için mümkün olan toplam geri alma kodu sayısını sınırladığından, derleyici yazıcılarının bu durum için iyileştirmesini öneririz.

Geri Sarma Kodları

Geri alma kodları dizisi, prologun etkilerinin tam olarak nasıl geri alındığını ve işlemlerin geri alınması gerektiği sırayı açıklayan bir yönerge dizileri havuzudur. Geri sarma kodları, bayt dizesi olarak kodlanmış bir mini yönerge kümesidir. Yürütme tamamlandığında, çağıran işlevin dönüş adresi LR yazmacındadır ve geçici olmayan tüm yazmaçlar işlev çağrıldığında değerlerine geri yüklenir.

Özel durumların yalnızca bir işlev gövdesi içinde gerçekleşeceği garanti edilirse ve hiçbir zaman bir prolog veya epilog içinde gerçekleşmezse, yalnızca bir geri sarma dizisi gerekir. Ancak Windows geri sarma modeli, kısmen yürütülen bir prologue veya epilog içinden geri alabilme özelliği gerektirir. Bu gereksinimi karşılamak için, geri sarma kodları prolog ve epilogdaki her ilgili opcode'a açık bir bire bir eşlemeye sahip olacak şekilde dikkatlice tasarlanmıştır. Bunun çeşitli etkileri vardır:

  • Geri sarma kodlarının sayısını sayarak prolog ve epilogun uzunluğunu hesaplamak mümkündür. Bu, 16 bit ve 32 bit opcode'lar için ayrı eşlemeler olduğundan, değişken uzunluklu Thumb-2 yönergeleriyle bile mümkündür.

  • Bir epilog kapsamının başlangıcını geçen yönergelerin sayısını sayarak, eşdeğer sayıda geri sarma kodunu atlayabilir ve bir dizinin geri kalanını yürüterek epilojinin gerçekleştirdiği kısmen yürütülen geri sarmayı tamamlayabilirsiniz.

  • Prologue'un sonundan önceki yönergelerin sayısını sayarak, eşdeğer sayıda geri sarma kodunu atlayabilir ve yalnızca yürütmeyi tamamlamış prologue bölümlerini geri almak için sıranın geri kalanını yürütebilirsiniz.

Aşağıdaki tabloda, geri sarma kodlarından opcode'lara eşleme gösterilmektedir. En yaygın kodlar yalnızca bir bayttır, daha az yaygın olan kodlar ise iki, üç, hatta dört bayt gerektirir. Her kod en önemli bayttan en az önemli bayta kadar depolanır. Geri sarma kodu yapısı ARM EABI'de açıklanan kodlamadan farklıdır, çünkü bu geri sarma kodları, kısmen yürütülen prologların ve epilogların geri alınabilmesi için prolog ve epilogdaki opcode'lara bire bir eşlemeye sahip olacak şekilde tasarlanmıştır.

Bayt 1 Bayt 2 Bayt 3 Bayt 4 Opsize Açıklama
00-7F 16 add sp,sp,#X

burada X (Kod & 0x7F) * 4
80-BF 00-FF 32 pop {r0-r12, lr}

burada Kod & 0x2000 ve r0-r12 açılırsa, karşılık gelen bit Kod & 0x1FFF olarak ayarlanırsa LR açılır
C0-CF 16 mov sp,rX

burada X Kod & 0x0F
D0-D7 16 pop {r4-rX,lr}

burada X (Kod & 0x03) + 4 ve Kod & 0x04 LR gösterilir
D8-DF 32 pop {r4-rX,lr}

burada X (Kod & 0x03) + 8 ve Kod & 0x04 LR gösterilir
E0-E7 32 vpop {d8-dX}

burada X (Kod & 0x07) + 8
E8-EB 00-FF 32 addw sp,sp,#X

burada X (Kod & 0x03FF) * 4
EC-ED 00-FF 16 pop {r0-r7,lr}

Burada Kod & 0x0100 ve r0-r7 açılırsa, karşılık gelen bit Kod & 0x00FF olarak ayarlanırsa LR açılır
EE 00-0F 16 Microsoft'a özgü
EE 10-FF 16 Kullanılabilir
EF 00-0F 32 ldr lr,[sp],#X

burada X (Kod & 0x000F) * 4
EF 10-FF 32 Kullanılabilir
F0-F4 - Kullanılabilir
F5 00-FF 32 vpop {dS-dE}

burada S (Kod & 0x00F0) >> 4, E ise Kod & 0x000F
F6 00-FF 32 vpop {dS-dE}

burada S ((Kod & 0x00F0) >> 4) + 16 ve E ise (Kod & 0x000F) + 16
F7 00-FF 00-FF 16 add sp,sp,#X

burada X (Kod & 0x00FFFF) * 4
F8 00-FF 00-FF 00-FF 16 add sp,sp,#X

burada X (Kod & 0x00FFFFFF) * 4
F9 00-FF 00-FF 32 add sp,sp,#X

burada X (Kod & 0x00FFFF) * 4
FA 00-FF 00-FF 00-FF 32 add sp,sp,#X

burada X (Kod & 0x00FFFFFF) * 4
FB 16 nop (16 bit)
FC 32 nop (32 bit)
FD 16 end + 16 bit nop in epilog
FE 32 end + 32 bit nop in epilog
FF - end

Bu, opcode boyutu Opsize ve buna karşılık gelen özgün yönerge yorumuyla birlikte bir sarma kodu Kodundaki her bayt için onaltılık değerler aralığını gösterir. Boş hücreler daha kısa geri sarma kodlarını gösterir. Birden çok baytı kapsayan büyük değerlere sahip yönergelerde, en önemli bitler önce depolanır. Opsize alanı, her Thumb-2 işlemiyle ilişkili örtük opcode boyutunu gösterir. Tablodaki farklı kodlamalara sahip görünen yinelenen girdiler, farklı opcode boyutlarını ayırt etmek için kullanılır.

Geri sarma kodları, kodun ilk baytının hem kodun bayt cinsinden toplam boyutunu hem de yönerge akışında karşılık gelen opcode'un boyutunu bildirmesi için tasarlanmıştır. Prolog veya epilog boyutunu hesaplamak için, sıranın başından sonuna kadar geri sarma kodlarının adımlarını uygulayın ve karşılık gelen işlem kodunun ne kadar uzun olduğunu belirlemek için bir arama tablosu veya benzer bir yöntem kullanın.

geri sarma kodları 0xFD ve 0xFE normal bitiş kodu 0xFF eşdeğerdir, ancak en son durumda 16 bit veya 32 bit olmak üzere fazladan bir nop opcode değerini hesaba ekler. Prologlar için kodlar 0xFD, 0xFE ve 0xFF tam olarak eşdeğerdir. Bu, eşdeğer bir prolog yönergesi olmayan veya yaygın en sonlarını ifade eder bx lr b <tailcall-target>. Bu, geri sarma dizilerinin prolog ve epiloglar arasında paylaşılma olasılığını artırır.

Çoğu durumda, prolog ve tüm epiloglar için aynı geri sarma kodları kümesini kullanmak mümkün olmalıdır. Ancak, kısmen yürütülen prologue'ların ve epilogların geri sarmasını işlemek için sıralama veya davranış olarak değişen birden çok geri alma kod dizisine sahip olmanız gerekebilir. Bu nedenle her bir epilogu yürütmeye nereden başlayacağını göstermek için unwind dizisinde kendi dizini vardır.

Kısmi Prologları ve Epilogları Sarmalama

En yaygın geri alma durumu, özel durumun işlevin gövdesinde, prologdan ve tüm epiloglardan uzak olmasıdır. Bu durumda, unwinder 0 dizininden başlayarak unwind dizisindeki kodları yürütür ve bir son işlem kodu algılanana kadar devam eder.

Bir prologue veya epilogue yürütülürken bir özel durum oluştuğunda, yığın çerçevesi yalnızca kısmen oluşturulur ve geri sarmalayıcının doğru bir şekilde geri almak için tam olarak ne yapıldığını belirlemesi gerekir.

Örneğin, bu prolog ve epilog dizisini göz önünde bulundurun:

0000:   push  {r0-r3}         ; 0x04
0002:   push  {r4-r9, lr}     ; 0xdd
0006:   mov   r7, sp          ; 0xc7
...
0140:   mov   sp, r7          ; 0xc7
0142:   pop   {r4-r9, lr}     ; 0xdd
0146:   add   sp, sp, #16     ; 0x04
0148:   bx    lr

Her işlem kodunun yanında bu işlemi açıklamak için uygun geri sarma kodu bulunur. Prologue için geri sarma kodları dizisi, son yönergeyi saymayan, epilog için geri sarma kodlarının ayna görüntüsüdür. Bu durum yaygın bir durumdur ve prologue için geri sarma kodlarının her zaman prologue'un yürütme sırasına göre ters sırada depolandığı varsayılmasıdır. Bu bize ortak bir geri sarma kodları kümesi sağlar:

0xc7, 0xdd, 0x04, 0xfd

0xFD kodu, sıranın sonu için özel bir koddur; bu, epilogun prologdan daha uzun bir 16 bit yönerge olduğu anlamına gelir. Bu, geri sarma kodlarının daha fazla paylaşımını mümkün kılar.

Örnekte, prolog ve epilog arasındaki işlev gövdesi yürütülürken bir özel durum oluşursa, geri alma işlemi epilog kodu içindeki 0 uzaklığında, epilog durumuyla başlar. Bu, örnekteki uzaklık 0x140 karşılık gelir. Temizleme yapılmadığından, geri sarmalayıcı tam geri sarma dizisini yürütür. Bunun yerine özel durum, epilogue kodunun başlangıcından sonra bir yönerge oluşursa, ilk geri alma kodunu atlayarak geri sarmayı başarıyla geri alabilir. İşlem kodları ve geri sarma kodları arasında bire bir eşleme göz önünde bulundurulduğunda, epilogdaki n yönergesinden geri alınıyorsa, geri sarmalayıcı ilk n geri alma kodlarını atlamalıdır.

Benzer mantık, prolog için ters çalışır. Prologue'da 0 uzaklığından geri sarıyorsanız hiçbir şeyin yürütülmesine gerek yoktur. içindeki bir yönergeden geri alınıyorsa, prologue geri alma kodları ters sırada depolandığından, geri alma dizisinin sonundan bir geri alma kodu başlatması gerekir. Genel durumda, prologda n yönergesinden geri alınıyorsa, geri alma işlemi kod listesinin sonundan n geriye doğru kod yürütmeye başlamalıdır.

Prologue ve epilogue unwind kodları her zaman tam olarak eşleşmez. Bu durumda, geri sarma kodu dizisinin birkaç kod dizisi içermesi gerekebilir. Kodları işlemeye başlamak için uzaklığı belirlemek için şu mantığı kullanın:

  1. İşlevin gövdesinden geri sarıyorsanız, 0 dizininde geri sarma kodlarını yürütmeye başlayın ve son işlem koduna ulaşılana kadar devam edin.

  2. Bir epilog içinden geri sarıyorsanız, epilog kapsamı tarafından sağlanan epiloga özgü başlangıç dizinini kullanın. Bilgisayarın en başından itibaren kaç bayt olduğunu hesaplayın. Önceden yürütülen tüm yönergeler hesaba aktarılana kadar geri sarma kodlarını atlayın. Bu noktadan başlayarak geri sarma dizisini yürütür.

  3. Prologue'un içinden geri sarıyorsanız, geri sarma kodlarındaki dizin 0'dan başlayın. Dizideki prolog kodunun uzunluğunu hesaplayın ve ardından bilgisayarın prologun sonundan kaç bayt olduğunu hesaplayın. Tüm yönetilmeyen yönergeler hesaba aktarılana kadar geri sarma kodlarını atlayın. Bu noktadan başlayarak geri sarma dizisini yürütür.

Prologue için geri sarma kodları her zaman dizideki ilk kod olmalıdır. bunlar aynı zamanda vücudun içinden geri sarmak için kullanılan kodlardır. Herhangi bir entrikaya özgü kod dizileri, prolog kod dizisinin hemen ardından izlenmelidir.

İşlev Parçaları

Kod iyileştirme için bir işlevi bitişik olmayan parçalara bölmek yararlı olabilir. Bu işlem tamamlandığında, her işlev parçası kendi ayrı .pdata(ve büyük olasılıkla .xdata) kaydını gerektirir.

İşlev prologunun işlevin başında olduğunu ve bölünemezseniz, dört işlev parçası örneği vardır:

  • Yalnızca prologue; diğer parçalardaki tüm yazılar.

  • Prolog ve bir veya daha fazla epilog; diğer parçalarda daha fazla epilog.

  • Prolog veya epilog yok; prolog ve diğer parçalarda bir veya daha fazla epilog.

  • Yalnızca epiloglar; diğer parçalarda prolog ve muhtemelen daha fazla epiloglar.

İlk durumda, yalnızca prolog açıklanmalıdır. Bu işlem, prologu normal bir şekilde tanımlayarak ve herhangi bir Ret epilog belirtmemek için 3 değeri belirterek kompakt .pdata biçimde yapılabilir. Tam .xdata formda, bu her zamanki gibi dizin 0'da prologue unwind kodları sağlanarak ve 0 epilog sayısı belirtilerek yapılabilir.

İkinci durum normal bir işlev gibidir. Parçada yalnızca bir epilog varsa ve parçanın sonundaysa, sıkıştırılmış .pdata bir kayıt kullanılabilir. Aksi takdirde, tam .xdata kayıt kullanılmalıdır. Epilog başlangıcı için belirtilen uzaklıkların işlevin özgün başlangıcına değil parçanın başlangıcına göre olduğunu unutmayın.

Üçüncü ve dördüncü vakalar sırasıyla birinci ve ikinci vakaların varyantlarıdır, ancak prolog içermezler. Bu gibi durumlarda, epilog başlamadan önce bir kod olduğu varsayılır ve normalde prologun etkilerini geri alarak kaldırılacak olan işlevin gövdesinin bir parçası olarak kabul edilir. Bu nedenle bu durumlar, gövdenin içinden nasıl geri alındığını açıklayan ancak parçanın başında kısmi bir geri sarma yapılıp yapılmayacağını belirlerken 0 uzunluklu olarak değerlendirilen sahte bir prologue ile kodlanmalıdır. Alternatif olarak, bu sahte prologue muhtemelen eşdeğer işlemler gerçekleştirdikleri için epilog ile aynı geri alma kodları kullanılarak açıklanabilir.

Üçüncü ve dördüncü durumlarda, sıkıştırılmış .pdata kaydın alanı 2 olarak ayarlanarak Flag veya üst bilgideki .xdata F bayrağı 1 olarak ayarlanarak sahte bir prologun varlığı belirtilir. Her iki durumda da kısmi prologue geri sarma denetimi yoksayılır ve epilog olmayan tüm geri bildirimler dolu olarak kabul edilir.

Büyük İşlevler

Parçalar, üst bilgideki bit alanları .xdata tarafından uygulanan 512 KB sınırından büyük işlevleri açıklamak için kullanılabilir. Daha büyük bir işlevi tanımlamak için 512 KB'tan küçük parçalara ayırması gerekir. Her parçanın, bir epilojiyi birden çok parçaya bölmemesi için ayarlanması gerekir.

İşlevin yalnızca ilk parçası bir prolog içerir. Diğer tüm parçalar herhangi bir prologa sahip değil olarak işaretlenir. Epilog sayısına bağlı olarak, her parça sıfır veya daha fazla epilog içerebilir. Bir parçadaki her bir entrika kapsamının, işlevin başlangıcına değil, parçanın başlangıcına göre başlangıç uzaklığını belirttiğini unutmayın.

Bir parçanın prologu yoksa ve epilogu yoksa, işlevin gövdesinden nasıl geri alındığını açıklamak için kendi kaydını ve muhtemelen .xdatakaydını gerektirir.pdata.

Küçültme kaydırma

İşlev parçalarının daha karmaşık bir özel durumu, küçültme sarmalama olarak adlandırılır. Bu, işlevin başlangıcından daha sonraki bir işleve yazmaç kaydetmelerini ertelemek için kullanılan bir tekniktir. Kayıt kaydetme gerektirmeyen basit durumlar için iyileştirir. Bu durumun iki bölümü vardır: yığın alanını ayıran ancak en az sayıda yazmaç kaydeden bir dış bölge ve diğer yazmaçları kaydedip geri yükleyen bir iç bölge vardır.

ShrinkWrappedFunction
    push   {r4, lr}          ; A: save minimal non-volatiles
    sub    sp, sp, #0x100    ; A: allocate all stack space up front
    ...                      ; A:
    add    r0, sp, #0xE4     ; A: prepare to do the inner save
    stm    r0, {r5-r11}      ; A: save remaining non-volatiles
    ...                      ; B:
    add    r0, sp, #0xE4     ; B: prepare to do the inner restore
    ldm    r0, {r5-r11}      ; B: restore remaining non-volatiles
    ...                      ; C:
    pop    {r4, pc}          ; C:

Küçültme sarmalanmış işlevlerin normalde normal prologue'da ek yazmaç tasarrufları için alanı önceden ayırması ve ardından veya stm yerine kullanarak str yazmaçları kaydetmesi pushbeklenir. Bu eylem, tüm yığın işaretçisi işlemesini işlevin özgün prologunda tutar.

Örnek daraltılmış işlev, açıklamalarda , Bve C olarak Aişaretlenmiş üç bölgeye ayrılmalıdır. İlk A bölge, geçici olmayan ek kaydetmelerin sonunda işlevin başlangıcını kapsar. Bir .pdata veya .xdata kaydı, bu parçanın bir prologa sahip olduğunu ve hiçbir epilog içermediği şeklinde tanımlanacak şekilde oluşturulmalıdır.

Orta B bölge kendi .pdata veya .xdata hiçbir prologue ve epilog olmayan bir parça tanımlayan bir kayıt alır. Ancak, işlev gövdesi olarak kabul edildiğinden bu bölgenin geri sarma kodları hala mevcut olmalıdır. Kodlar, hem bölgeye kaydedilen özgün yazmaçları hem de bölgeye A girmeden Bönce kaydedilen ek yazmaçları tek bir işlem dizisi tarafından üretilmiş gibi temsil eden bileşik bir prolog tanımlamalıdır.

Bölge B için yazmaç kayıtları "iç prologue" olarak düşünülemez çünkü bölge B için açıklanan bileşik prolog hem bölge A prologunu hem de kaydedilen ek yazmaçları açıklamalıdır. Parçanın B bir prologu varsa, geri sarma kodları bu prologue'un boyutunu da ifade eder ve bileşik prologu yalnızca ek yazmaçları kaydeden opcode'larla bire bir eşleyen bir şekilde açıklamanın hiçbir yolu yoktur.

Ek yazmaç kayıtları bölgenin Abir parçası olarak kabul edilmelidir, çünkü bunlar tamamlanana kadar bileşik prolog yığının durumunu doğru şekilde açıklamaz.

Son C bölge kendi .pdata veya .xdata kaydına sahip olur ve prologu olmayan ancak bir epilogu olan bir parçayı açıklar.

Bölgeye B girmeden önce yapılan yığın düzenlemesi tek yönergeye indirgenebiliyorsa alternatif bir yaklaşım da kullanılabilir:

ShrinkWrappedFunction
    push   {r4, lr}          ; A: save minimal non-volatile registers
    sub    sp, sp, #0xE0     ; A: allocate minimal stack space up front
    ...                      ; A:
    push   {r4-r9}           ; A: save remaining non-volatiles
    ...                      ; B:
    pop    {r4-r9}           ; B: restore remaining non-volatiles
    ...                      ; C:
    pop    {r4, pc}          ; C: restore non-volatile registers

Temel içgörü, her yönerge sınırında yığının bölge için geri sarma kodlarıyla tamamen tutarlı olmasıdır. Bu örnekte iç gönderimden önce bir geri sarma oluşursa, bölgenin Abir parçası olarak kabul edilir. Sadece bölge A prologue unwound. geri sarma iç gönderimden sonra oluşursa, bölge parçası Bolarak kabul edilir ve hiçbir prologue yoktur. Ancak, hem iç gönderimi hem de bölgeden Aözgün prologue'yi açıklayan geri sarma kodları vardır. İç pop için benzer mantık tutar.

Kodlama İyileştirmeleri

Geri sarma kodlarının zenginliği ve sıkıştırılmış ve genişletilmiş veri biçimlerinden yararlanma olanağı, alanı daha da azaltmak için kodlamayı iyileştirmeye yönelik birçok fırsat sağlar. Bu tekniklerin agresif kullanımıyla, geri sarma kodları kullanılarak işlevleri ve parçaları açıklamanın net yükü en aza indirilebilir.

En önemli iyileştirme fikri: Geri sarma amacıyla prolog ve epilog sınırlarını derleyici perspektifinden mantıksal prolog ve epilog sınırlarıyla karıştırmayın. Geri sarma sınırları küçülebilir ve verimliliği artırmak için daha sıkı hale getirilebilir. Örneğin, bir prolog, doğrulama denetimleri yapmak için yığın kurulumundan sonra kod içerebilir. Ancak tüm yığın işlemesi tamamlandıktan sonra, daha fazla işlem kodlamaya gerek yoktur ve bunun ötesindeki her şey geri sarmalayan prologue'dan kaldırılabilir.

Bu kural işlev uzunluğu için de geçerlidir. Bir işlevdeki bir yazıyı izleyen veriler (değişmez değer havuzu gibi) varsa, işlev uzunluğunun bir parçası olarak dahil edilmemelidir. İşlevi yalnızca işlevin parçası olan koda küçülterek, en sonda epilogun olması ve kısa .pdata bir kaydın kullanılabilmesi çok daha büyük bir olasılıktır.

Bir prologda, yığın işaretçisi başka bir kayıt defterine kaydedildikten sonra, genellikle başka işlem kodları kaydetmeye gerek yoktur. İşlevi geri almak için yapılan ilk şey, kaydedilen kayıttan SP'yi kurtarmaktır. Diğer işlemlerin geri sarma üzerinde herhangi bir etkisi yoktur.

Tek yönergeli epilogların kapsamlar veya geri sarma kodları olarak kodlanması gerekmez. Bu yönerge yürütülmeden önce bir geri sarma gerçekleşirse, işlevin gövdesinden olduğunu varsaymak güvenlidir. Prologue unwind kodlarının yürütülmesi yeterlidir. Tek yönerge yürütüldükten sonra geri sarma işlemi gerçekleştiğinde, tanım gereği başka bir bölgede gerçekleşir.

Çok yönergeli epilogun ilk yönergesini önceki noktayla aynı nedenle kodlamak zorunda değildir: bu yönerge yürütülmeden önce geri sarma gerçekleşirse, tam bir prologue geri sarma yeterlidir. Bu yönergeden sonra geri sarma gerçekleşirse yalnızca sonraki işlemlerin dikkate alınması gerekir.

Geri sarma kodunun yeniden kullanılması agresif olmalıdır. Dizin her epilog kapsamı, geri alma kodları dizisindeki rastgele bir başlangıç noktasına işaret eder. Önceki bir sıranın başlangıcına işaret etmek zorunda değildir; ortayı işaret edebilir. En iyi yaklaşım, geri sarma kod dizisini oluşturmaktır. Ardından, zaten kodlanmış dizi havuzunda tam bayt eşleşmesi için tarama yapın. Yeniden kullanım için başlangıç noktası olarak herhangi bir mükemmel eşleşmeyi kullanın.

Tek yönergeli epiloglar yoksayıldıktan sonra, kalan epiloglar yoksa, kompakt .pdata bir form kullanmayı düşünün; bir epilogun yokluğunda çok daha olası hale gelir.

Örnekler

Bu örneklerde görüntü tabanı 0x00400000.

Örnek 1: Yaprak İşlevi, Yerel Ayar Yok

Prologue:
  004535F8: B430      push        {r4-r5}
Epilogue:
  00453656: BC30      pop         {r4-r5}
  00453658: 4770      bx          lr

.pdata (sabit, 2 sözcük):

  • Word 0

    • Function Start RVA = 0x000535F8 (= 0x004535F8-0x00400000)
  • Word 1

    • Flag = 1, kurallı prolog ve epilog biçimlerini gösterir

    • Function Length = 0x31 (= 0x62/2)

    • Ret = 1, 16 bit dal dönüşünü gösterir

    • H = 0, parametrelerin giriş yapılmadığını gösterir

    • R = 0 ve Reg = 1, r4-r5'in gönderimini/pop'ını gösterir

    • L = 0, LR kaydetme/geri yükleme olmadığını gösterir

    • C = 0, çerçeve zincirleme olmadığını gösterir

    • Stack Adjust = 0, yığın ayarlaması olmadığını gösterir

Örnek 2: Yerel Ayırma ile İç İçe İşlev

Prologue:
  004533AC: B5F0      push        {r4-r7, lr}
  004533AE: B083      sub         sp, sp, #0xC
Epilogue:
  00453412: B003      add         sp, sp, #0xC
  00453414: BDF0      pop         {r4-r7, pc}

.pdata (sabit, 2 sözcük):

  • Word 0

    • Function Start RVA = 0x000533AC (= 0x004533AC -0x00400000)
  • Word 1

    • Flag = 1, kurallı prolog ve epilog biçimlerini gösterir

    • Function Length = 0x35 (= 0x6A/2)

    • Ret = 0, pop {pc} dönüşünü gösterir

    • H = 0, parametrelerin giriş yapılmadığını gösterir

    • R = 0 ve Reg = 3, r4-r7'nin gönderimini/pop'ını gösterir

    • L = 1, LR'nin kaydedildiğini/geri yüklendiğini gösterir

    • C = 0, çerçeve zincirleme olmadığını gösterir

    • Stack Adjust = 3 (= 0x0C/4)

Örnek 3: İç İçe Variadic İşlevi

Prologue:
  00453988: B40F      push        {r0-r3}
  0045398A: B570      push        {r4-r6, lr}
Epilogue:
  004539D4: E8BD 4070 pop         {r4-r6}
  004539D8: F85D FB14 ldr         pc, [sp], #0x14

.pdata (sabit, 2 sözcük):

  • Word 0

    • Function Start RVA = 0x00053988 (= 0x00453988-0x00400000)
  • Word 1

    • Flag = 1, kurallı prolog ve epilog biçimlerini gösterir

    • Function Length = 0x2A (= 0x54/2)

    • Ret = 0, pop {pc} stilinde bir dönüş (bu durumda bir ldr pc,[sp],#0x14 dönüş) gösterir

    • H = 1, parametrelerin giriş yapıldığını gösterir

    • R = 0 ve Reg = 2, r4-r6'nın gönderimini/pop'ını gösterir

    • L = 1, LR'nin kaydedildiğini/geri yüklendiğini gösterir

    • C = 0, çerçeve zincirleme olmadığını gösterir

    • Stack Adjust = 0, yığın ayarlaması olmadığını gösterir

Örnek 4: Birden Çok Epilog ile İşlev

Prologue:
  004592F4: E92D 47F0 stmdb       sp!, {r4-r10, lr}
  004592F8: B086      sub         sp, sp, #0x18
Epilogues:
  00459316: B006      add         sp, sp, #0x18
  00459318: E8BD 87F0 ldm         sp!, {r4-r10, pc}
  ...
  0045943E: B006      add         sp, sp, #0x18
  00459440: E8BD 87F0 ldm         sp!, {r4-r10, pc}
  ...
  004595D4: B006      add         sp, sp, #0x18
  004595D6: E8BD 87F0 ldm         sp!, {r4-r10, pc}
  ...
  00459606: B006      add         sp, sp, #0x18
  00459608: E8BD 87F0 ldm         sp!, {r4-r10, pc}
  ...
  00459636: F028 FF0F bl          KeBugCheckEx     ; end of function

.pdata (sabit, 2 sözcük):

  • Word 0

    • Function Start RVA = 0x000592F4 (= 0x004592F4-0x00400000)
  • Word 1

    • Flag = 0, kaydın .xdata mevcut olduğunu gösterir (birden çok bölüm için gereklidir)

    • .xdata adres - 0x00400000

.xdata (değişken, 6 sözcük):

  • Word 0

    • Function Length = 0x0001A3 (= 0x000346/2)

    • Vers = 0, ilk sürümünü gösterir.xdata

    • X = 0, özel durum verileri olmadığını gösterir

    • E = 0, epilog kapsamlarının listesini gösterir

    • F = 0, prolog da dahil olmak üzere tam işlev açıklamasını gösterir

    • Epilogue Count = 0x04, toplam 4 entrika kapsamını gösterir

    • Code Words = 0x01, 32 bitlik bir geri alma kodu sözcüğünü gösterir

  • 4 konumda 4 epilog kapsamı açıklayan 1-4 sözcükleri. Her kapsam, 0x00 uzaklıkta prologue ile paylaşılan ortak bir geri alma kodları kümesine sahiptir ve koşul 0x0E (her zaman) belirterek koşulsuzdur.

  • Word 5'te başlayan geri sarma kodları: (prolog/epilog arasında paylaşılan)

    • Geri sarma kodu 0 = 0x06: sp += (6 << 2)

    • Geri sarma kodu 1 = 0xDE: pop {r4-r10, lr}

    • Geri sarma kodu 2 = 0xFF: end

Örnek 5: Dinamik Yığın ve İç Özet ile İşlev

Prologue:
  00485A20: B40F      push        {r0-r3}
  00485A22: E92D 41F0 stmdb       sp!, {r4-r8, lr}
  00485A26: 466E      mov         r6, sp
  00485A28: 0934      lsrs        r4, r6, #4
  00485A2A: 0124      lsls        r4, r4, #4
  00485A2C: 46A5      mov         sp, r4
  00485A2E: F2AD 2D90 subw        sp, sp, #0x290
Epilogue:
  00485BAC: 46B5      mov         sp, r6
  00485BAE: E8BD 41F0 ldm         sp!, {r4-r8, lr}
  00485BB2: B004      add         sp, sp, #0x10
  00485BB4: 4770      bx          lr
  ...
  00485E2A: F7FF BE7D b           #0x485B28    ; end of function

.pdata (sabit, 2 sözcük):

  • Word 0

    • Function Start RVA = 0x00085A20 (= 0x00485A20-0x00400000)
  • Word 1

    • Flag = 0, kaydın .xdata mevcut olduğunu gösterir (birden çok bölüm için gereklidir)

    • .xdata adres - 0x00400000

.xdata (değişken, 3 sözcük):

  • Word 0

    • Function Length = 0x0001A3 (= 0x000346/2)

    • Vers = 0, ilk sürümünü gösterir.xdata

    • X = 0, özel durum verileri olmadığını gösterir

    • E = 0, epilog kapsamlarının listesini gösterir

    • F = 0, prolog da dahil olmak üzere tam işlev açıklamasını gösterir

    • Epilogue Count = 0x001, toplam 1 özet kapsamını gösterir

    • Code Words = 0x01, 32 bitlik bir geri alma kodu sözcüğünü gösterir

  • Word 1: 0xC6 uzaklığında (= 0x18C/2) özet kapsamı, 0x00'da geri sarma kodu dizinini başlatma ve 0x0E (her zaman) koşuluyla

  • Word 2'den başlayarak geri sarma kodları: (prolog/epilog arasında paylaşılan)

    • Geri sarma kodu 0 = 0xC6: sp = r6

    • Geri sarma kodu 1 = 0xDC: pop {r4-r8, lr}

    • Geri sarma kodu 2 = 0x04: sp += (4 << 2)

    • Geri sarma kodu 3 = 0xFD: end, özet için 16 bit yönerge olarak sayılır

Örnek 6: Özel Durum İşleyicili İşlev

Prologue:
  00488C1C: 0059 A7ED dc.w  0x0059A7ED
  00488C20: 005A 8ED0 dc.w  0x005A8ED0
FunctionStart:
  00488C24: B590      push        {r4, r7, lr}
  00488C26: B085      sub         sp, sp, #0x14
  00488C28: 466F      mov         r7, sp
Epilogue:
  00488C6C: 46BD      mov         sp, r7
  00488C6E: B005      add         sp, sp, #0x14
  00488C70: BD90      pop         {r4, r7, pc}

.pdata (sabit, 2 sözcük):

  • Word 0

    • Function Start RVA = 0x00088C24 (= 0x00488C24-0x00400000)
  • Word 1

    • Flag = 0, kaydın .xdata mevcut olduğunu gösterir (birden çok bölüm için gereklidir)

    • .xdata adres - 0x00400000

.xdata (değişken, 5 sözcük):

  • Word 0

    • Function Length =0x000027 (= 0x00004E/2)

    • Vers = 0, ilk sürümünü gösterir.xdata

    • X = 1, özel durum verilerinin mevcut olduğunu gösterir

    • E = 1, tek bir epilojiyi gösterir

    • F = 0, prolog da dahil olmak üzere tam işlev açıklamasını gösterir

    • Epilogue Count = 0x00, epilogue geri sarma kodlarının uzaklık 0x00 başladığını gösterir

    • Code Words = 0x02, geri sarma kodlarının iki 32 bit sözcüğüne işaret eder

  • Word 1'den başlayarak geri sarma kodları:

    • Geri sarma kodu 0 = 0xC7: sp = r7

    • Geri sarma kodu 1 = 0x05: sp += (5 << 2)

    • Geri sarma kodu 2 = 0xED/0x90: pop {r4, r7, lr}

    • Geri sarma kodu 4 = 0xFF: end

  • Word 3 özel durum işleyicisi = 0x0019A7ED (= 0x0059A7ED - 0x00400000) belirtir

  • 4 ve sonrasındaki sözcükler, çizgili özel durum verileridir

Örnek 7: Funclet

Function:
  00488C72: B500      push        {lr}
  00488C74: B081      sub         sp, sp, #4
  00488C76: 3F20      subs        r7, #0x20
  00488C78: F117 0308 adds        r3, r7, #8
  00488C7C: 1D3A      adds        r2, r7, #4
  00488C7E: 1C39      adds        r1, r7, #0
  00488C80: F7FF FFAC bl          target
  00488C84: B001      add         sp, sp, #4
  00488C86: BD00      pop         {pc}

.pdata (sabit, 2 sözcük):

  • Word 0

    • Function Start RVA = 0x00088C72 (= 0x00488C72-0x00400000)
  • Word 1

    • Flag = 1, kurallı prolog ve epilog biçimlerini gösterir

    • Function Length = 0x0B (= 0x16/2)

    • Ret = 0, pop {pc} dönüşünü gösterir

    • H = 0, parametrelerin giriş yapılmadığını gösterir

    • R = 0 ve Reg = 7, hiçbir yazmaç kaydedilmediğini/geri yüklenmediğini gösterir

    • L = 1, LR'nin kaydedildiğini/geri yüklendiğini gösterir

    • C = 0, çerçeve zincirleme olmadığını gösterir

    • Stack Adjust = 1 × 4 bayt yığını ayarlamasını gösteren 1

Ayrıca bkz.

ARM ABI Kurallarına Genel Bakış
Genel Visual C++ ARM Geçiş Sorunları