2012-11-12 38 views
6

Bir TLS değişkenini montajda artırmak istiyorum ancak montaj kodunda bölümlendirme hatası veriyor. Derleyicinin başka bir kayıt veya belleği değiştirmesine izin vermek istemiyorum. Gcc giriş ve çıkış sözdizimi kullanmadan bunu yapmak için bir yolu var mı? Eğer gerçekten nedense bunu yapabilmek için gerekirseiş parçacığı içinde yerel depolama iş parçacığı

__thread unsigned val; 
int main() { 
    val = 0; 
    asm("incl %gs:val"); 
    return 0; 
} 
+0

1) Neden ''val + = 1;'' yazamıyorsunuz? 2) Bunu, -O2-S ile derleyin ve derleme çıktısını inceleyin; '__thread' değişkenlerine nasıl erişeceğiniz konusunda yanıldığınızı keşfedeceksiniz. – zwol

+1

@Zack Bununla ilgili bir cevap yazabilir misin? – 0x90

+0

val ++, $ 0x1,% gs: 0xfffffffc çevirir, ancak el ile ("movl $ 1,% gs: val") el ile yaptığımda, $ 0x1,% gs: 0x8049f14 movl çevirir. Benim programımda 0xfffffffc adresi nasıl alınır. – Yogi

cevap

14

, böyle, C adresini önceden yükleyerek derleme dilden bir iş parçacığı yerel bir değişkene erişmeye olmalıdır:

__thread unsigned val; 
void incval(void) 
{ 
    unsigned *vp = &val; 
    asm ("incl\t%0" : "+m" (*vp)); 
} 

Bunun nedeni, iş parçacığı yerel değişkenine erişmek için gereken kod sırasının, GCC tarafından desteklenen hemen hemen tüm işletim sistemi ve CPU kombinasyonu için farklı olması ve ayrıca bir yürütülebilir kitaplık yerine (örneğin, -fPIC ile) bir paylaşılan kitaplık için derleme yapıyorsanız değişiklik göstermesidir. Yukarıdaki yapı, derleyicinin sizin için doğru kod dizisini yayınlamasına izin verir. İplik-yerel değişkene herhangi bir ekstra talimat olmaksızın erişilebildiği durumlarda, adres üretimi montaj operasyonuna katlanacaktır. Örnekleme yoluyla, buradan .../Linux (Ben netlik için, her durumda montajcı direktifleri bir demet kaldırdık) birkaç farklı olası modlarda yukarıda derleme yöntemiyle x86 4.7 gcc olduğunu

# -S -O2 -m32 -fomit-frame-pointer 
incval: 
     incl %gs:[email protected] 
     ret 

# -S -O2 -m64 
incval: 
     incl %fs:[email protected] 
     ret 

# -S -O2 -m32 -fomit-frame-pointer -fpic 
incval: 
     pushl %ebx 
     call __x86.get_pc_thunk.bx 
     addl $_GLOBAL_OFFSET_TABLE_, %ebx 
     leal [email protected](,%ebx,1), %eax 
     call [email protected] 
     incl (%eax) 
     popl %ebx 
     ret 

# -S -O2 -m64 -fpic 
incval: 
     .byte 0x66 
     leaq [email protected](%rip), %rdi 
     .value 0x6666 
     rex64 
     call [email protected] 
     incl (%rax) 
     ret 

'un dört örneğinin tümü'un x86/OSX için derlenmiş ve x86/Windows için farklı olsa da farklı olacağını anlayın.

+0

Güzel cevap. Son koddaki ek önekler mi? – Jester

+2

@Jester Bağlayıcıya bir miktar daha fazla boşluk bırakacaklar, böylece daha etkili bir sırayla (ancak daha uzun talimatlar içeren) gördüğünüz talimatları değiştirebilir. Ayrıntılı bilgi için http://people.redhat.com/drepper/tls.pdf ve http://www.x86-64.org/pipermail/discuss/2002-September/002829.html adresini ziyaret edin. – zwol

İlgili konular