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 + Reg değ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 + Reg değ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
Reg
açıklanan kayıt kümesine dahil edilmemelidir. Yani, r4-r11 gönderiliyorsa,Reg
bayrak r11'i ima ettiğindenC
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 Adjust
türetilir:
PF
veya "prologue folding" 0x3F4 veya daha büyük olduğunuStack 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österirStack 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 add
olur.
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, , , L
R
ve PF
alanlarına göre hangi kayıtların C
kaydedildiğ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 Ret
vardı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:
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 iseE
, 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 iseE
, 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ı Ö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. 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.
Ü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:
İş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.
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.
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 .xdata
kaydı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 push
beklenir. Bu eylem, tüm yığın işaretçisi işlemesini işlevin özgün prologunda tutar.
Örnek daraltılmış işlev, açıklamalarda , B
ve C
olarak A
iş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 A
bir 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 A
bir parçası olarak kabul edilir. Sadece bölge A
prologue unwound. geri sarma iç gönderimden sonra oluşursa, bölge parçası B
olarak 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österirFunction Length
= 0x31 (= 0x62/2)Ret
= 1, 16 bit dal dönüşünü gösterirH
= 0, parametrelerin giriş yapılmadığını gösterirR
= 0 veReg
= 1, r4-r5'in gönderimini/pop'ını gösterirL
= 0, LR kaydetme/geri yükleme olmadığını gösterirC
= 0, çerçeve zincirleme olmadığını gösterirStack 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österirFunction Length
= 0x35 (= 0x6A/2)Ret
= 0, pop {pc} dönüşünü gösterirH
= 0, parametrelerin giriş yapılmadığını gösterirR
= 0 veReg
= 3, r4-r7'nin gönderimini/pop'ını gösterirL
= 1, LR'nin kaydedildiğini/geri yüklendiğini gösterirC
= 0, çerçeve zincirleme olmadığını gösterirStack 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österirFunction Length
= 0x2A (= 0x54/2)Ret
= 0, pop {pc} stilinde bir dönüş (bu durumda birldr pc,[sp],#0x14
dönüş) gösterirH
= 1, parametrelerin giriş yapıldığını gösterirR
= 0 veReg
= 2, r4-r6'nın gönderimini/pop'ını gösterirL
= 1, LR'nin kaydedildiğini/geri yüklendiğini gösterirC
= 0, çerçeve zincirleme olmadığını gösterirStack 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österirE
= 0, epilog kapsamlarının listesini gösterirF
= 0, prolog da dahil olmak üzere tam işlev açıklamasını gösterirEpilogue Count
= 0x04, toplam 4 entrika kapsamını gösterirCode 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österirE
= 0, epilog kapsamlarının listesini gösterirF
= 0, prolog da dahil olmak üzere tam işlev açıklamasını gösterirEpilogue Count
= 0x001, toplam 1 özet kapsamını gösterirCode 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österirE
= 1, tek bir epilojiyi gösterirF
= 0, prolog da dahil olmak üzere tam işlev açıklamasını gösterirEpilogue Count
= 0x00, epilogue geri sarma kodlarının uzaklık 0x00 başladığını gösterirCode 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österirFunction Length
= 0x0B (= 0x16/2)Ret
= 0, pop {pc} dönüşünü gösterirH
= 0, parametrelerin giriş yapılmadığını gösterirR
= 0 veReg
= 7, hiçbir yazmaç kaydedilmediğini/geri yüklenmediğini gösterirL
= 1, LR'nin kaydedildiğini/geri yüklendiğini gösterirC
= 0, çerçeve zincirleme olmadığını gösterirStack 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ı