2011-07-26 15 views
19

Bir okul projesinden bazı eski kodlara bakıyorum ve onu dizüstü bilgisayarımda derlemeye çalışırken bazı sorunlara rastladım. Orijinal olarak gcc'nin eski bir 32 bit sürümü için yazılmıştır. Her neyse, derlemenin bir kısmını 64 bit uyumlu koda çevirmeye çalışıyordum ve birkaç tıkanıklığa neden oluyordum.Bir kesme hizmeti rutini için x86_64 kayıt defterleri nasıl kaydedilir?

pusha 
pushl %ds 
pushl %es 
pushl %fs 
pushl %gs 
pushl %ss 

pusha 64 bit modunda geçerli değil:

İşte orijinal kodudur. Peki, x86_64 derlemesinde 64 bit kipte bunu yapmanın en uygun yolu ne olurdu?

pusha'un 64 bit kipte geçerli olmamasının bir nedeni olmalı, bu nedenle tüm yazmaçların iyi bir fikir olmamasına el ile itme hissim var. gereksiz olduğu için

cevap

7

bu tür şeyleri yapan kodlar mevcut öğrenin. Örneğin:

(benzer NetBSD içinde vector.S olan) regs "elle itme" Aslında

, orada yok PUSHA beri AMD64 tek yoludur. AMD64 bu yönüyle benzersiz değildir - x86 olmayan CPU'ların çoğu bir noktada kayıt-kayıt-kaydetme/geri yükleme gerektirir.

Ama yakından değil tüm işleyicileri/kaydetmek tüm kayıt kümesi geri gerektiren kesme, böylece oda optimizasyonları için orada olduğunu göreceksiniz başvurulan sourcecode incelemek eğer.

+0

[wiki makalesi] (http://en.wikipedia.org/wiki/X86-64) x86-64'ün x86 ile geriye dönük olarak uyumlu olduğunu okurum. Bir talimatı kaldırmak uyumsuzluk olmaz mı? –

3

pusha 64-bit modunda geçerli değildir. Her bir kaydı tek tek basmak tam olarak yapılacak şeydir.

+4

Ayrıca, 64 bit modda bölüm kayıtlarını zorlayamazsınız. İlk önce onları başka bir kayıt defterine kopyalamanız gerekir. mov% ds,% eax; % rax’i bas. – ughoavgfhw

+0

@ughoavgfhw Segment kayıtlarının uzun modda anlamlı bir değeri yoktur. Temel bölümleri MSR 0xC0000100 ve 0xC0000101 tarafından kontrol edilen ve uygun iş parçacığı yerel depolama işaretçileri olarak kullanılmak üzere tasarlanan FS ve GS dışındaki tüm segmentler sıfır temel ve sınırsızdır. – doug65536

+1

@ doug65536 Hala bunları korumak için bazen gereklidir. Örneğin, 32-bit programlar çalıştıran 64-bit bir işletim sistemi, bir kesme işlemi olduğunda bölüm yazmaçlarını kaydetmelidir, çünkü bu program için segmentasyon kullanılır. – ughoavgfhw

15

AMD onlar 64 bit x86 uzantıları geliştirdi zaman REX önekleri ve diğer bazı yeni yönergeler için yeni opcodes eklemek için bazı oda gerekli. Bazı opcodes'ların anlamını bu yeni talimatlara değiştirdiler. Talimatların Çeşitli

basitçe mevcut talimatların kısa formları edildi ya da başka gerekli değildi. PUSHA kurbanlardan biriydi. PUSHA'u neden yasakladıkları açık değil, ancak yeni talimat opcodes'larının üstesinden gelmiyor. Belki de bunlar tamamen kullanıldıklarından ve daha hızlı olmayacaklarından ve kod için yeterli miktarda kod bulunmadıklarından dolayı PUSHA ve POPA opcodes'leri daha sonra kullanmak üzere rezerve etmişlerdir. eax, ecx, edx, ebx, esp, ebp, esi, edi:

PUSHA sırası

kullanıcı kodlama sırası oldu. O gereksiz yere esp itti unutmayın! İçe aktardığı verileri bulmak için esp'u bilmeniz gerekir!

64-bit kod dönüştürme yapıyorsanız PUSHA kod zaten hiç iyi değil, bunu r15 aracılığıyla yeni sicillerdir r8 itmek güncellemeniz gerekir.Ayrıca, çok daha büyük bir SSE durumu, xmm8 ve xmm15'u kaydetmeniz ve geri yüklemeniz gerekir. Onları clobber edeceğini varsayarsak. kesme işleyici kodu basitçe C koduna ileten bir saplama ise

, sen kayıtları tüm kaydetmek gerek yoktur. C derleyicisinin, rbx, rbp, rsi, rdi ve r12'u r15 aracılığıyla koruyacak kod üreteceğini varsayabilirsiniz. Yalnızca kaydedip rax, rcx, rdx ve r8r11 aracılığıyla geri gerekir gerekir. : - (Not Linux veya diğer Sistemi V ABI platformlarında, derleyici rbx, rbp, r12 koruyarak olacak r15, sen rsi ve clobbered rdi bekleyebilirsiniz). (Kesintili iplik 32-bit uyumluluk modunda çalışıyorsa sayesinde ughoavgfhw, segmentlere kayıtları korumalıdır)

kademeli kayıt uzun kipinde değer tutun. Aslında, uzun modda segmentasyonun çoğundan kurtuldular, ancak FS hala iş parçacığı yerel verileri için bir temel adres olarak kullanmak için işletim sistemleri için ayrılmıştır. kendisi önemli değil kayıt değeri, FS ve GS taban MSR'ler 0xC0000100 ve 0xC0000101 aracılığıyla ayarlanır. FS kullanamayacağınızı varsayarak, bunun için endişelenmenize gerek yok, sadece C kodu tarafından erişilen herhangi bir iş parçacığı yerel verilerin herhangi rastgele bir iş parçacığının TLS kullanarak olabileceğini unutmayın. Bunun için dikkatli olun çünkü C çalışma zamanı kitaplıkları bazı işlevler için TLS kullanır (örnek: strtok genellikle TLS kullanır). (Hatta kullanıcı modunda) FS veya GS içine bir değer yüklüyor

FSBASE veya GSBASE MSR'yi üzerine yazılır. Bazı işletim sistemleri, "işlemci yerel" depolama alanı olarak GS'u kullandıklarından (her CPU için bir yapıya işaretçinin olması için bir yönteme ihtiyaç duyuyorlar), kullanıcı modunda GS yüklendikten sonra bir yere ulaşamayacakları bir yerde tutmaları gerekir. Bu sorunu çözmek için, GSBASE kayıt için ayrılmış iki MSR vardır: biri aktif bir ve bir gizli olan. Çekirdek modunda, çekirdek en GSBASE zamanki GSBASE MAB'nde tutulur ve kullanıcı modu tabanı diğer (gizli) GSBASE MAB'nde olduğunu. İçerik kernel modundan bir kullanıcı kipine geçtiğinde ve bir kullanıcı kipi bağlamı kaydederken ve kernel kipini girerken, içerik anahtar kodu, görünür ve gizli GSBASE MSR değerlerini değiştiren SWAPGS komutunu yürütmelidir. Çekirdek en GSBASE güvenle kullanıcı modunda diğer MAB'nde gizlenmiş olduğundan, kullanıcı modu kodu GS içine bir değer yükleyerek çekirdek en GSBASE clobber olamaz. İşlemci çekirdek modunu tekrar bağladığında, içerik kaydetme kodu SWAPGS'u çalıştıracak ve kernel'in GSBASE sürümünü geri yükleyecektir.

0

Merhaba bunu yapmak için doğru bir yol olmayabilir ama bir

gerekiyorsa bir başka r8-15 kayıtlarını eklemek sonunda

.macro pushaq 
    push %rax 
    push %rcx 
    push %rdx 
    push %rbx 
    push %rbp 
    push %rsi 
    push %rdi 
.endm # pushaq 

ve

.macro popaq 
    pop %rdi  
    pop %rsi  
    pop %rbp  
    pop %rbx  
    pop %rdx  
    pop %rcx 
    pop %rax 
.endm # popaq 

ve benzeri makrolar oluşturabilirsiniz

İlgili konular