Ceviz Forum'a hoşgeldiniz.
Toplam 3 sayfadan 1. sayfa 1 2 3 En SonEn Son
30 sonuçtan 1 ile 10 arası gösteriliyor
  1. #1
    Ceviz Üyesi
    Üyelik Tarihi
    11/2009
    Mesaj
    733

    Varsayılan Şu GCC'nin Optimizasyon Bug'ları :|

    Program yazarken karşılaştığım sorunların %10 gibi bir bölümü gcc nin optimizasyon bugları

    Daha doğrusu , gcc , sonucunu kullanmayacağımızı düşünüp, kod içinde yap dediğimiz bir çok şeyi yapmayabiliyor.

    Örneğin boş bir fonksiyon çağırdığımızda ne de olsa bir iş yapmıyor diye fonksiyona hiç girmiyor, ya da fonksiyon her daim 5 değerini döndürüyor ve biz bu değeri ekrana yazıyorsak, fonksiyona girip dönüş değerini alacağına printf e kendisi 5 veriyor ve ekrana yazdırıyor

    Kulağa hoş gelse bile bu özellikler bazen çok canımı sıkıyor. Şimdi size vereceğim şu küçük kodu Dev C++ ile dediğim gibi çalıştırırsanız ne demek istediğimi anlayacaksınız. Ya da Gcc .... -O3 şeklinde çalıştırabilirsiniz konsoldan.

    Bilindiği gibi C de fonksiyon çağırmanın bazı usülleri vardır. Örneğim _cdecl _stdcall _pascal gibi fonksiyon çağırma yöntemi vardır.

    Bu yöntemlerin birbirinden farkı, fonksiyona parametreler hangi sırada atılacak ve stack i fonksiyon mu toparlayacak vs.

    Dev C++ ı en iyi optimizasyona ayarlayarak kodumu yazıyordum, ancak fonksiyon yapması gereken işi yapmıyor adeta saçmalıyordu. Önce dizilerden birisi taşıp fonksiyon parametrelerini mi değiştirdi diye düşündüm ama öyle olsa daha önce gelen fonksiyonun dönüş adresi de değişmeliydi. Halbuki fonksiyona giriyordu ama hatalı sonuç üretiyordu.

    Daha sonra hatanın kaynağını tespit edip en temel haliyle göstereyim dedim. Aşağıda verdiğim kodu çalıştırmadan önce Dev C++ da araçlar-derleyici ayarları-kod-optimizasyon-diğer optimizasyon-en iyi optimizasyon bölümünü yes yapın.



    Daha sonra aşağıdaki kodu çalıştırın. Bendeki ekran görüntüsünü de koyuyorum...

    PHP Kodu:
    #include <stdio.h>
     
     
    int fonksiyon (int x,int y,int z ){
         
     
    //    printf(" %X %X %X\n\n",&x,&y,&z);
                 
         
    printf(" Birinci parametre adres : %X | deger : %X\n", &x,  *(&x));
         
    printf(" ikinci  parametre adres : %X | deger : %X\n", &x+1,*(&x+1));
         
    printf(" Ucuncu  parametre adres : %X | deger : %X\n", &x+2,*(&x+2));
         
    printf("\n Geri donus degeri %X\n",*(&x-1));
         
         return 
    x+y+z;
     }
     
     
    int main(){
         
    int i;
         
         
    i=fonksiyon(0x50,0x60,0x70);
     
         
    getch();
         return 
    0;
     } 



    Aslında x parametresinin adresinde 50h değeri varken y parametresinde 60h z parametresinde ise 70h değeri olması gerekiyordu. Ayrıca x parametresi stack e atılamdan önce geri dönüş değeri atılacağından &x-1 adresinde ise fonksiyonun geri dönüş değeri olması gerekiyordu.

    Tabi her zaman yaptığım gibi optimizasyonu kapatarak kodu tekrar derleyim dedim, sonucu tahmin ediyorsunuz. Deminki yes yaptığınız bölümü no yapıp kodu tekrar derleyelim..



    Gördüğünüz üzre fonksiyon taş gibi çalışıyor. Peki optimizasyon durumunda Gcc bunu neden yapıyor??

    Çünkü kodu kısaltmak ve hızlandırmak adına, _cdecl fonksiyon çağırma standartını bile eziyor, bizim parametrelere bu adreslerden erişmediğimizi düşünüp, onları istediği atreslere atıyor, ancak bizim o adresleri görmek istediğimizi anlarsa o zaman parametreleri doğru adreslere taşıyor.

    Bunun ispatı için öncelikle tekrar Dev C++ ı en iyi optimizasyona alıyoruz, demin gösterdiğim yerden tekrar yes deyin. Şimdi kodu derlemeden önce // printf(" %X %X %X\n\n",&x,&y,&z); satırını tekrar açın, ben o satırı derlenmemek üzere yorum satırı haline getirmiştim, tek yapmanız gereken baştaki // yı kaldırmak.

    Şimdi program bizim bu nesnelerin adreslerini görmek istediğimiz anlıyor ve parametreleri adreslere standartlara göre diziyor. Böylelikle bizim kodumuz da doğru çalışıyor.



    Evet olay böyle cereyan ediyor, bu işlemleri linux da ya da konsolda yapmak için derleyicide kodu önce gcc ... şeklinde sonra da -O3 parametresi ile ayrı ayrı derlemelisiniz.
    Uludağda karı düşünüyorum karı
    Donları çözülmüş karı
    Masamda buz gibi biram
    Hani ya rakım
    Herkesin elinde ski kayıyor
    Benimki kırık
    Benim adım Orhan Veli Kanık
    Yüreği yanık...


  2. #2
    Ceviz Üyesi
    Üyelik Tarihi
    11/2009
    Mesaj
    733

    Varsayılan

    Bu arada sadece yanlış sonuç verdi diye derleyicinin standart çağırım biçimini ihlal ettiğini iddaa etmiyorum, elbette fonksiyona girerken değerler doğru yerde olduğu halde fonksiyon içinde yerleri değiştirilmiş olabilir. Bunun da ispatı burada

    Öncelikle optimizasyonsuz programda fonksiyona girdiği ana bakıyoruz...



    Görüldüğü gibi parametreler ve geri dönüş değeri stack de olması gerektiği gibi duruyor, ilk sayılar adres, ikincileri parametre değeri. Bu durum fonksiyon çağrım standartlarına uygun...

    Peki bir de optimizasyonlu halini inceleyelim.


    İkinci resime dikkat edin, stack bölümünde parametreler yok, neden dersiniz buna ben bile şaşırdım. Gcc aslında fonksiyona parametre aktarmıyor...

    Dikkat yazdığım bölüme bakın, orada 50 sayısını görüyorsunuz. &x ve x değerlerini kullandığımız içim gcc x değerini fonksiyon içerisinde kendisi oluşturuyor ve ekrana yazdırıyor, ancak &x+1 ile &y yi kastettiğimizi anlayamadığından 60 ve 70 parametrelerini fonksiyonun içindeyken bile oluşturmuyor.

    Yani biz fonksiyona dışardan parametre gönderdiğimizi sanırken gcc o sayıyı fonksiyonun kaynak koduna yazmış ve aslında bizim gönderdiğimiz birşey yok, fonksiyon zaten ekrana 50 yazmaya programlanmış

    Özetle, optimizasyonlu bir derleyici ile program yazıyorsanız, optimizasyondsan doğabilecek sorunları düşünüp kodunuzda bir hata olduğunda optimizasyonu kapatmayı düşünün.
    Benim kullandığım mingw nin son versiyonu, linux da ve mingw nin eski versiyonlarında aynı kodu üretmeye bilir. Ayrıca gcc nin dandik bir derleyici olduğunu sanmayın, koskoca linux işletim sistemi Gcc ile derleniyor, doğru kullanmak önemlidir.

    Ben hatalı mı kullanıyorum, optimizasyonu açtıysam, kodu da ona göre yazmalıyım, optimizasyonun kullanıcıya bırakılan bir seçenek olmasının sebebi de budur, eğer tam hatasız kod üretse zaten bize sormadan optimizasyonu yapar. Ben sadece ilerde doğabilecek sorunlar için sizi uyarayım dedim. Herkese iyi çalışmalar.
    Uludağda karı düşünüyorum karı
    Donları çözülmüş karı
    Masamda buz gibi biram
    Hani ya rakım
    Herkesin elinde ski kayıyor
    Benimki kırık
    Benim adım Orhan Veli Kanık
    Yüreği yanık...


  3. #3
    Okan Akyüz
    Üyelik Tarihi
    03/2009
    Mesaj
    880

    Varsayılan

    Formun başka yerlerinde sözü edilen konuya çarpıcı örnek. Benim gibi siz de gcc mail liste baktıysanız sıklıkla göreceğiniz gibi -02 tavsiye olan peki üçte ne yapılıyor.

    Bu optimizasyonda fonksiyonların en hızlı şalışması hedeflenmiş. Sizin örneğinizde fonksiyona statik değerler yolluyorsunuz ve fonksiyonu yalnız bir kere kullanıyorsunuz. Aslında gcc bu konuda çok akıllıca bir çözüm üretmiş. Çünkü doğru düzgün bir programlamada kimse tutupta ikinci parametreyi
    stack adresini arttırarak çekmez. İkinci parametrenin bir ismi cismi vardır. Ayrıca bir derleyici illa stack mimarisini sizin istediğiniz gibi yapacak diye standart bir kuram yoktur. Sizin bir değişkeniniz ve değişken adresiniz vardır.

    Açıkçası söylemek gerekirse bir fonksiyonu mantığa uygun olmayan şekilde işlettiğiniz için sonuç doğal. Hata mı evet ama majör hata mı tabiikide hayır.

  4. #4
    Ceviz Üyesi
    Üyelik Tarihi
    11/2009
    Mesaj
    733

    Varsayılan

    Zaten bunu ben de kalın karakterlerle belirttim.
    Uludağda karı düşünüyorum karı
    Donları çözülmüş karı
    Masamda buz gibi biram
    Hani ya rakım
    Herkesin elinde ski kayıyor
    Benimki kırık
    Benim adım Orhan Veli Kanık
    Yüreği yanık...


  5. #5
    Ali Çehreli
    Üyelik Tarihi
    10/2002
    Mesaj
    4,150

    Varsayılan

    Evet ama gcc'nin tanımsız davranış karşısında ne yapmasını bekleriz? Bu programda tanımsız davranış var, çünkü tanımlanmamış verilere erişmeye çalışıyor. &x+1 yasal bir adres mi? Değil. *(&x+1) yasal bir veri mi? Değil.

    gcc'nin hatalı olduğunu söyleyebilmemiz için ancak ve ancak C dilinin kuralları içinde yazılmış bir programın yanlış davranması gerekir.

    Her programın olduğu gibi, gcc'nin de hataları vardır ama bu konuda hatalı olduğunu söyleyemeyiz.

    Konuyla doğrudan ilgili olmasa da, C dilinin "program yığıtı" (program stack) diye bir şey bile tanımlamadığını hatırlatmak isterim.

    Ali

  6. #6
    Ceviz Üyesi
    Üyelik Tarihi
    11/2009
    Mesaj
    733

    Varsayılan

    Tamam da hocam programda printf satırlarını, doğal olarak *(&x+1) ifadesini yazmasam da program aynı şekilde derleniyor.

    Benim söylemek istediğim şey başkaydı, C de _cdecall fonksiyon çağırma standartına göre derler çoğu derleyici, C standartlarında olmasa da birçok derleyicinin default sistemi budur. Ben buna güvenmemek gerektiğini, kodu buna göre yazınca hata çıkabileceğini göstermek istedim.

    Zaten en sonunda benim de hata yaptığımı açıkça belirttim ve aynı hatalara düşebilecek arkadasları uyardım.
    gcc nin dandik bir derleyici olduğunu sanmayın, koskoca linux işletim sistemi Gcc ile derleniyor, doğru kullanmak önemlidir.

    Ben hatalı mı kullanıyorum, optimizasyonu açtıysam, kodu da ona göre yazmalıyım, optimizasyonun kullanıcıya bırakılan bir seçenek olmasının sebebi de budur, eğer tam hatasız kod üretse zaten bize sormadan optimizasyonu yapar. Ben sadece ilerde doğabilecek sorunlar için sizi uyarayım dedim. Herkese iyi çalışmalar.
    He bunun dışında özellikle döngülerden sabit ifadeleri döngü dışına çıkarma ve bu gibi durumlarda -O3 de birçok bug ile karşılaştığım için bu başlığı rahat açtım, eğer o kodları bulursam ayrıca burada yine gösteririm arkadaşlara.

    Belirtmek istediğim açıkçası şu : Optimizasyon açıkken fonksiyonun kesin çağırılmasını, bir işlemin kesin yapılmasını beklemeyin, en hızlı sonuç ne ise o yapılır, gerektiğinde bir sayının bir döngü boyunca işlem yapılıp elde edilmesi durumunda bile derleyici o döngüyü hiç kurmayıp doğrudan sonuç olan sayıyı yazabilir.

    Örneğin kısa bir döngü 5 kez dönüp bir sonuç bulmuş olabilir, bu durumda alttaki satırda döngü değişkeni olan i yi kullanayım derseniz , i nin değeri sandığınız gibi 5 olmaya bilir, 0 olabilir, çünkü aslında o döngü hiç kurulmamış olabilir. İşte bu tür durumlar için uyarmak istedim. Yoksa yineliyorum, fonksiyon çağırma standartı diye birşey C standartlarında yoktur, derleyici eklentisidir.
    Uludağda karı düşünüyorum karı
    Donları çözülmüş karı
    Masamda buz gibi biram
    Hani ya rakım
    Herkesin elinde ski kayıyor
    Benimki kırık
    Benim adım Orhan Veli Kanık
    Yüreği yanık...


  7. #7
    Ali Çehreli
    Üyelik Tarihi
    10/2002
    Mesaj
    4,150

    Varsayılan

    Alıntı KUTALMIS, mesajından alıntı: Mesajı Gör
    Örneğin kısa bir döngü 5 kez dönüp bir sonuç bulmuş olabilir, bu durumda alttaki satırda döngü değişkeni olan i yi kullanayım derseniz , i nin değeri sandığınız gibi 5 olmaya bilir, 0 olabilir
    Eğer öyle olursa derleyici hatası kabul edilir işte.

    Derleyiciler "mış gibi" olduğu sürece istediklerini yapabilirler. Doğru derleyici döngüyü çalıştırmayacaksa, i'nin değerini de sabit olarak 5 yapar.

    Eğer derleyici hatasını gösterdiğine inandığın kodları bulursan ben de görmek isterim. (Bizim de rastladığımız gcc hataları oluyordu.)

    Ali

  8. #8
    Ceviz Üyesi
    Üyelik Tarihi
    11/2009
    Mesaj
    733

    Varsayılan

    Alıntı acehreli, mesajından alıntı: Mesajı Gör
    Eğer öyle olursa derleyici hatası kabul edilir işte.

    Derleyiciler "mış gibi" olduğu sürece istediklerini yapabilirler. Doğru derleyici döngüyü çalıştırmayacaksa, i'nin değerini de sabit olarak 5 yapar.

    Eğer derleyici hatasını gösterdiğine inandığın kodları bulursan ben de görmek isterim. (Bizim de rastladığımız gcc hataları oluyordu.)

    Ali
    Hocam eskiden Dev C++ ı direkt indiriyordum, bu ide yıllardır güncellenmediğinden içindeki mingw de eski versiyondu sanırım, birçok kez for döngüsü yüzünden saatlerce saçımı başımı yolduğumu hatırlıyorum, program göz göre göre hatalı çalışıyordu.

    Şimdilerde mingw nin son versiyonunu indirip Dev C++ ı onunla kuruyorum, bu arada mingw gcc için 30 sayfa bug rapor edilmiş ve 22 sayfası kapatılmış

    http://sourceforge.net/tracker/?grou...35&atid=102435

    Listeden gcc yi filtreleyerek gcc buglarını görebilirsiniz. Bu arada şimdi bir kaç numara denedim ama yemedi Örneğin döngüyü oluşturmuyor ancak i nin değerini de arttırıyor ..

    Bu arada ld nin de windows versiyonunun bildim bileli kapatılmayan bir hatası var, CSDOS dökümanlarındaki falt binary makalesinde de değinilmiş. Sırf bu yüzden kernel denemelerim için linux kuruyorum, gcc kodları çok güzel derliyor ancak ld ye gelince
    "ld asd.o -e main --oformat binary -N " şeklinde bağlamaya çalışınca "ld: cannot perform PE operations on non PE output file 'a.exe'." diyor, halbuki linux versiyonunda böyle bir sorun yok :|
    Uludağda karı düşünüyorum karı
    Donları çözülmüş karı
    Masamda buz gibi biram
    Hani ya rakım
    Herkesin elinde ski kayıyor
    Benimki kırık
    Benim adım Orhan Veli Kanık
    Yüreği yanık...


  9. #9
    Okan Akyüz
    Üyelik Tarihi
    03/2009
    Mesaj
    880

    Varsayılan

    _cdecl çağrı fonksiyonu gibi kullanmayan derleyiciler de var örneğin tcc kaynak koduna bakın. _cdecl 0 olarak define edilmiştir. Daha sonra bunu bir değerler fonksiyonuna tip olarak alıyor ve switch yapıyor. Yani fonksiyon tipine göre sağdan push etme işlemi yapılmış oluyor (pascal soldan mesela) Yine benzer şekilde tcc bunu sisteme standart şekilde girmeyebilirdi.

    Optimizasyonlu programlarda sanki bir sonuç döndürüyor gcc. Bundaki mantık klasik dil ayıklama probleminde de gördüğümüz, bağımlı değişken bağımsız değişken ilişkisi. Yani optimizasyonda bağımsız değişkenler hesapla değil çözüm ile yer alıyor, bağımlı değişkenler ise rutin oluşturarak çözülüyor.

  10. #10
    Ceviz Üyesi
    Üyelik Tarihi
    11/2009
    Mesaj
    733

    Varsayılan

    Hocam C tipi fonksiyon çağırma, pascal tipi fonksiyon çağırma gibi söylemlerden dolayı, sanki her C fonksiyonu çağırılırken C tipiyle çağırılacakmış gibi düşündüm, aslında düşününce standartlarda böyle bir kavram olmadığına göre istediği gibi çağırır.

    Yani ben sağdan sola parametreleri push edecek bunlardan önce geri dönüş adresini push edecek meselelerini fazla kafaya takmışım ali hoca da sen de haklısın. Konunun başlığı "şu benim bug lu programlarım" olarak değiştirilebilir
    Uludağda karı düşünüyorum karı
    Donları çözülmüş karı
    Masamda buz gibi biram
    Hani ya rakım
    Herkesin elinde ski kayıyor
    Benimki kırık
    Benim adım Orhan Veli Kanık
    Yüreği yanık...



 

Konu Bilgileri

Users Browsing this Thread

Şu an 1 kullanıcı bu konuya bakıyor. (0 üye ve 1 ziyaretçi)

Sık Kullanılanlar

Sık Kullanılanlar

Mesaj Yazma Hakları

  • Yeni mesajgöndermezsiniz
  • Cevap yazamazsınız
  • Dosya ekleyemezsiniz
  • Mesajınızı düzenleyemezsiniz
  •  
Yukarı Çık