Assembly şu an neden kullanılmıyor?

dxmorgan

Hectopat
Katılım
14 Mayıs 2021
Mesajlar
405
Çözümler
1
Daha fazla  
Cinsiyet
Erkek
Merhaba, son günlerde ufaktan yazılım öğrenmek istiyorum, ama önce temelini anlamak istiyorum. Sorum şu;

Bütün yazılım dilleri Assembly (makine dili), den çıktı on off (0, 1) mantığını anladım. Şu anda kullanılmıyor çünkü C ve benzeri programlara bir kod yazınca otomatik olarak onu zaten Assembly'e çeviriyor, doğru anlamış mıyım?

Cevaplarsanız sevinirim.
 
Son düzenleyen: Moderatör:
Merhaba!

Aslında olay şöyle (basıt anlatımı).

İslemci en basit olarak 0 ve 1 bilir.

Bunları yan yana getirerek komutlar, sayısal değer vs. tanımlanabilir.

(Kafadan atıyorum)
01110001 MOVE komutu olsun
00011101 PUSH komutu vs.

Ben bu şekilde bir program yazabilirim: 001101000101110100100010011111011010011 ......

Yazılması zor ve hata ayıklanması daha da zor.

Assembler programlamayı biraz kolaylaştırıyor.

Mesela ben
MOVE A1,33h
PUSH A1
PUSHD

Şeklinde bir kodlama yapmış olayım. Değerleyici bu komutları alıp 011101001001 vs. koduna dönüştürü.

Kodlaması daha kolay, hata ayıklaması da basit hale gelmiş olur.
Zor kısım ise, yazmış olduğum kod sadece belirli bir işlemci ailesi için kullanılabilir olmasıdır.
Mesela İntel işlemcide çalışır, ARM işlemcide çalışmaz.

Bu nedenle daha yüksek bir programlama diline ihtiyaç duyulur. Burada 'taşınabilirlik' önemli.

Mesela printf(' ');

Kafadan atıyorum bu komutun açılımı
MOV A1,20h
INT 23,A1
şeklinde olsun.

Sen hangisini daha kolay aklında tutabilirsin?

Başka bir örnek:

Elinde mesela yep yeni üretilmiş ARM işlemcili bir bilgisayar var (RASPBERRY Pİ gibi) ve hiç bir işletim sistemi ve program yok.
011010010010010011111011 ..... şeklinde program yazmayı denesen, herhalde yıllarını/ömrünü alır.
Bu durumda cross-compiling kullanabilirsin. İntel işlemcili bir PC'de (mesela) programını C++ olarak kodlarsın fakat değerleyiciye 'bu programı İntel için değil, ARM işlemcisine değerle' komutunu ekleyebilirsin ve programını taşıyabilirsin.


Programlama dilin seviyesi yükseldikçe, programlama/kodlama basitleşir, fakat program biraz hantal olabilir. Senin makine dilinde yazdığın 3 satırlık kod, C++'da 50 satır olabilir.

Bu basit anlatımı. Mesela C/C++'de makine dili kodları ekleyebilirsin. Fakat bu şekilde programın taşınılabilirli kaybolmuş olur.
 
Çünkü C Compiler'ı her insandan daha iyi Assembly yazıyor.

Ben tam tersini düşünüyorum.

Bir uydurma örnek:

İki sayı toplamak istiyoruz.
ASSEMBLY şu şekilde olabilir.
MOV A1, 12d
ADD.L A1,22d

A1 operatöründe 12+22 = 34 yazar.

Programcı şuna dikkat etmeli: Bayraklarda (FLAGS) bir değişim var mı ya da ben işlem öncesi bayrakları atamam mı gerekiyor. Toplama işlemin toplamı negatif olabilir.

C/C++'da bu daha kolay. Değişkenleri işaretli (signed) yada işaretsiz (unsigned) tanımlayabiliriz. Uzunluğu Byte, Long, Double vs. Değerleyici bazı kontrolleri yapar, fakat algoritmada olan mantık hatalarını tespit edemez.

Ayrıca değerleyici komutları alt rutin olarak işler. Mesela değerlerliyici toplama işlemini şu şekile dönüştürebilir.

MOV A1,12d
PUSH A1
MOV A1,22d
PUSH A1
PUSHF
JSR TOPLAMA
MOV A1,[SP-2]
POPF
RET

TOPLAMA:
MOV A1,[SP-6]
ADD A1,[SP-4]
MOV [SP-4],A1
POP A1
PUSHF
PUSH A1
RTS

Kod uzadığı için programın 'hızı' düşer. Her komut aynı hızda işlenmiyor. Bazı komutların hızı 1 clock olabilir, bazıları 4,6,12 ... clock olabilir.

Bazı kodlamaları Assembly dilinde yapmak zorundası. Mesela boot sektörün boyutu sınırlı ise.
 
C/C++'da bu daha kolay. Değişkenleri işaretli (signed) yada işaretsiz (unsigned) tanımlayabiliriz. Uzunluğu Byte, Long, Double vs. Değerleyici bazı kontrolleri yapar, fakat algoritmada olan mantık hatalarını tespit edemez.
Değerleyici değil, derleyici. Derleyiciler algoritmadaki hataları kontrol etmekle sorumlu değil zaten. Ek olarak aynı mantık assembly içinde geçerli. Assembler'da bulamayacak mantık hatalarını. Ayrıca anlattıklarının hiç biri hala bir insanın C derleyicisinden daha iyi Assembly yazabileceğini kanıtlamıyor.
 
Ben tam tersini düşünüyorum.

Bir uydurma örnek:

İki sayı toplamak istiyoruz.
Assembly şu şekilde olabilir.
MOV A1, 12D
ADD. L A1, 22D

A1 operatöründe 12+22 = 34 yazar.

Programcı şuna dikkat etmeli: Bayraklarda (FLAGS) bir değişim var mı ya da ben işlem öncesi bayrakları atamam mı gerekiyor. Toplama işlemin toplamı negatif olabilir.

C/C++'da bu daha kolay. Değişkenleri işaretli (signed) ya da işaretsiz (unsigned) tanımlayabiliriz. Uzunluğu Byte, Long, Double vs. Değerleyici bazı kontrolleri yapar, fakat algoritmada olan mantık hatalarını tespit edemez.

Ayrıca değerleyici komutları alt rutin olarak işler. Mesela değerlerliyici toplama işlemini şu şekile dönüştürebilir.

MOV A1, 12D
PUSH A1
MOV A1, 22D
PUSH A1
PUSHF
JSR TOPLAMA
MOV A1,[SP-2]
POPF
RET

TOPLAMA:
MOV A1,[SP-6]
ADD A1,[SP-4]
MOV [SP-4],A1
POP A1
PUSHF
PUSH A1
RTS

Kod uzadığı için programın 'hızı' düşer. Her komut aynı hızda işlenmiyor. Bazı komutların hızı 1 clock olabilir, bazıları 4, 6, 12.. Clock olabilir.

Bazı kodlamaları Assembly dilinde yapmak zorundası. Mesela boot sektörün boyutu sınırlı ise.

Varsayımlarla hareket etmek doğru değil. C Compiler'ı herhangi bir insandan daha iyi Assembly yazıyor su götürmez bir gerçek üzgünüm.

Ha yazarsın oturur haftalarca program üstünde çalışırsın ama maliyet değer mi bilemedim. 15-20 nanosecond için.

Örnek bir uydurma C++ kodum olsun. Topla adlı bir fonksiyonum olsun ve bunu t değerini bulmak için kullanayım.

C++:
int topla(int num1, int num2) {
 return num1 + num2;
}
int t = topla(1,2);

Optimizasyon ayarı olmadan C compilerından geçirdiğimde insancıl bir kod yazar:

Kod:
topla(int, int): # @topla(int, int)
 push rbp
 mov rbp, rsp
 mov dword ptr [rbp - 4], edi
 mov dword ptr [rbp - 8], esi
 mov eax, dword ptr [rbp - 4]
 add eax, dword ptr [rbp - 8]
 pop rbp
 ret
__cxx_global_var_init: # @__cxx_global_var_init
 push rbp
 mov rbp, rsp
 mov edi, 1
 mov esi, 2
 call topla(int, int)
 mov dword ptr [rip + t], eax
 pop rbp
 ret
_GLOBAL__sub_I_example.cpp: # @_GLOBAL__sub_I_example.cpp
 push rbp
 mov rbp, rsp
 call __cxx_global_var_init
 pop rbp
 ret
t:
 .long 0 # 0x0

Ancak optimizasyon ayarları ile verdiğimde insan doğasına aykırı bir şey yapacak:

Kod:
topla(int, int): # @topla(int, int)
 lea eax, [rdi + rsi]
 ret
t:
 .long 3 # 0x3

Direkt işlem sonucu belli olduğundan 3 değerini T'ye atayacak. Bunu tüm for döngülerinde while döngülerinde yani sonucu daha sonradan belli olan her şeyde yapıyor. Üstelik sen kodunda fonksiyon olarak kullandığından tek bir şeyi değiştirirken compiler arkada belki de binlerce değişkenin son durumunu hesaplayıp başlangıç değerlerini direkt işlemin sonucu olarak belirliyor. Büyük ölçekli projelerde kalkıp bunu bir insan yapar dersen biraz komik olur.

C Compiler'ı zeki insanların yazdığı zeki bir araç. Çoğu zaman insanlardan daha zeki.
 
Son düzenleme:
Ancak optimizasyon ayarları ile verdiğimde insan doğasına aykırı bir şey yapacak:

Kod:
topla(int, int): # @topla(int, int)
 lea eax, [rdi + rsi]
 ret
t:
 .long 3 # 0x3

Aslında değil. Sen oturup 1+2 toplayan bir program yazmasın. İki sabitin toplamı yine sabittir.

Aynı şekilde sen de 3 sayısını atayabilirsin.

Büyük ölçekli projelerde kalkıp bunu bir insan yapar dersen biraz komik olur.

Tabii ki mümkün değil. Eğer mümkün olsa, o zaman neden değişik programlama araçlarına ihtiyaç duyulsun. Büyük projeyi boş ver, sen kalkıp Windows için bir programı Assembly dilinde programlar mısın?

Ben bunları yazarken aslında aklımda başka bir örnek vardı. Kesmeler (İnterrupts)/time critical code.
Sanırım ne demek istediğimi anladın.

İstersen toplama işlemi için BASİC kullanırsın. Sana kimse birşey diyemez. Hiç kod yazmana da gerek yok. Alırsın hesap makinesini sayıları toplarsın.
 
Değerleyici değil, derleyici. Derleyiciler algoritmadaki hataları kontrol etmekle sorumlu değil zaten. Ek olarak aynı mantık Assembly içinde geçerli. Assembler'da bulamayacak mantık hatalarını. Ayrıca anlattıklarının hiçbiri hala bir insanın C derleyicisinden daha iyi Assembly yazabileceğini kanıtlamıyor.

Tam olarak aynı fikirde değilim. Konu optimizasyon olunca Assembly ile yazılan program C derleyicilerinden daha performanslı olabiliyor. Örnek vermek gerekirse:
Bu içeriği görüntülemek için üçüncü taraf çerezlerini yerleştirmek için izninize ihtiyacımız olacak.
Daha detaylı bilgi için, çerezler sayfamıza bakınız.

Ve ayrıyeten NASA gibi yerlerdede bundan dolayı C yerine akıcı Assembly yazabilen developer aranmakta. 64 KB'lık bir belleğe C ile optimize çalışamazsınız.
 
Ve ayrıyeten NASA gibi yerlerdede bundan dolayı C yerine akıcı Assembly yazabilen developer aranmakta. 64 KB'lık bir belleğe C ile optimize çalışamazsınız.
40Kb'lık oyun yapmak için C'de yeterli. NES uç bir örnek, profesyonel hayata uygulanabilirliği yok. NES çıktığı dönemde, C bu kadar yaygın değildi, compilerlar bu kadar gelişmiş değildi.
1722879683061.png
1722879718317.png
1722882055247.png

GCC'nin çıkış tarihi 1987. İlk C compilerlarından olan PCC ise 1979.

NES ise 1983 Japonya, 1986 Avrupa. NES çıktığında ortalıkta adam gibi bir C compiler'ı bile yoktu. Bu sebepten ötürü Assembly kullanılıyordu. Daha stable compilerlar yeni yeni ortaya çıkarken, teknoloji ve internet bu durumda değilken, NES'in Assembly kullanmasında şaşılacak bir şey yok.

Attığın videoyu da izledim, adamların video boyunca asıl değindikleri nokta grafiklerle nasıl başa çıktıkları. Assembly'ın daha optimize olduğu değil. Bu kadar kısıtlı bir alanda, datayı meta tile'lar, mirrored spritelar şeklinde tuttuklarından, böylece alandan nasıl tasarruf ettiklerinden bahsetmişler.

NASA'nın durumu da yine bir edge case. Nasa sadece Assembly bilen programcılar aramıyor. Voyager programı için arıyorlar. Bu da hala C compilerlarının insandan daha iyi kod ürettiğine dair bir kanıt değil. Edge case gereksinimi yüzünden, güncel bir dile çekilemeyecek bir sistem olmasından kaynaklanıyor.
 

Technopat Haberler

Geri
Yukarı