
Herkese selamlar.
Bir önceki konumuz olan Assembly Eğitim Serisi (Sıfırdan İleri Seviye) Bölüm #8 den devam ediyoruz ve 9. Bölüme geçiyoruz. Bir önceki bölümde programın karar vermesini öğrendik. cmp, test ve koşullu atlamalar ile artık “şart varsa şuraya git” diyebiliyoruz. Bu bölümde bir adım daha ileri gidiyoruz:
Programın bir işi tekrar tekrar yapmasını öğreneceğiz. Yani döngü (loop) mantığını.
Şimdiden iyi okumalar.
Döngü Nedir?
Döngü kısaca şu demektir:
Belirli bir şart sağlandığı sürece aynı kod bloğunu tekrar çalıştırmak.
Yüksek seviyeli dillerde bunu şöyle görürüz:
C:
while(i < 10)
{
i++;
}
Assembly’de ise while ya da for diye bir komut yoktur. Assembly’de döngü kurmak demek:
- Bir etikete gitmek
- Koşulu kontrol etmek
- Şart sağlanıyorsa geri dönmek
- Label (etiket) - Kodun geri dönülecek noktası
- jmp (jump) - Koşulsuz atlama
- Koşullu jump (jne, jge vs.) - Şarta bağlı atlama
Label Nedir?
Label (etiket), kod içinde isim verdiğimiz bir noktadır. Örneğin:
Kod:
start:
Bu bir label’dır. Program buraya atlayabilir. Label aslında bellekte bir adresi temsil eder. Yani start: demek:
“Bu kodun bulunduğu adresin ismi start olsun.”
En Basit Döngü
Şimdi basit bir döngü yapalım. Burada amaç: 5’ten geriye doğru saymak.
Kod:
mov rcx, 5
loop_start:
dec rcx
cmp rcx, 0
jne loop_start
Şimdi buradaki komutları adım adım inceleyelim.
mov rcx, 5 komutu
mov komutu veri taşır. Bunu önceki dersimizde de işlemiştik. Burada RCX register’ına 5 yazıyoruz. RCX burada sayaç (counter) görevi görüyor. Sayaç demek:
Kaç kez tekrar edileceğini tutan değişken.
dec rcx komutu
dec komutu register değerini 1 azaltır. Yani:
Kod:
rcx = rcx - 1
cmp rcx, 0 komutu
cmp iki değeri karşılaştırır. Aslında rcx - 0 işlemini yapar ama sonucu yazmaz. Sadece flag register içindeki bitleri ayarlar. Burada özellikle Zero Flag (ZF) önemlidir.
- Eğer rcx = 0 ise - ZF = 1
- Değilse - ZF = 0
jne loop_start komutu
jne demek: Jump if Not Equal (Eşit değilse atla) Teknik olarak:
ZF = 0 ise atla.
Yani rcx sıfır değilse tekrar başa dön. Bu yapı şunun karşılığıdır:
C:
int i = 5;
while(i != 0)
{
i--;
}
Assembly’de döngü mantığı aynen bu şekildedir. Label + Koşul + Geri atlama.
Bir döngü 3 temel parçadan oluşur:
- Başlangıç değeri
- Koşul kontrolü
- Artış veya azalış
Sonsuz Döngü Nedir?
Eğer geri dönüş var ama çıkış koşulu yoksa:
Kod:
start:
jmp start
Bu bir infinite loop (sonsuz döngü)’dür. Program sürekli aynı adrese atlar. CPU durmadan aynı kodu çalıştırır. Reverse engineering’de (tersine mühendislik) bazen bilinçli olarak kullanılır.
while Mantığı
Assembly da while döngüsünün mantığına şu şekilde bir örnek verebiliriz:
Kod:
mov rcx, 0
while_start:
cmp rcx, 10
jge while_end
inc rcx
jmp while_start
while_end:
Burada fark ettiyseniz yeni bir komut gördük. jge komutu. Peki nedir bu jge komutu? Gelin ona da bakalım.
jge - Jump if Greater or Equal (Büyük veya eşitse atla)
Signed (işaretli) karşılaştırmada: Eğer rcx ≥ 10 ise çık şeklinde kullanılır. Bu mantık şunun karşılığıdır:
C:
while(rcx < 10)
{
rcx++;
}
Burada önemli teknik bir nokta vardır. Koşul döngünün başında kontrol edilir. Şart sağlanmazsa gövdeye girilmez.
for Mantığı
Assembly da for döngüsü aslında while’ın düzenlenmiş halidir. Hemen örnek üzerinden gidelim:
Kod:
mov rcx, 0
for_start:
cmp rcx, 5
jge for_end
; burada çalışacak kod
inc rcx
jmp for_start
for_end:
Burada mantık şudur:
Başlat - Kontrol - Çalıştır - Artır - Geri dön
Assembly’de özel bir for komutu yoktur. Hepsi atlama kombinasyonudur.
loop Komutu (x86’ya Özgü)
x86 mimarisinde özel bir komut vardır:
Kod:
mov rcx, 5
loop_label:
; yapılacak iş
loop loop_label
loop komutu şunu yapar:
- RCX’i 1 azaltır
- RCX sıfır değilse etikete atlar
Şimdi konunun pekişmesi adına bazı teknik terimlerin anlamlarını bilmemiz gerekiyor. Bazıları şu şekildedir:
Register: CPU içindeki hızlı veri alanı.
Flag: İşlem sonucunun durumunu gösteren bit.
Label: Kod içindeki isimlendirilmiş adres.
Jump: Program akışını başka adrese taşıma işlemi.
Counter: Döngü kaç kez çalışacak bilgisini tutan değer.
Infinite loop: Çıkış koşulu olmayan döngü.
Bu teknik terimleri bilmek, Assembly kodu okurken bize avantaj sağlar.
O zaman şimdiye kadar öğrendiğimiz konuları tek bir örnek üzerinde toparlayalım:
- Register kullanımı
- mov / inc / dec
- cmp / test
- Flag mantığı
- Koşullu atlama (je, jne, jge, ja vs.)
- Döngü
- Signed / Unsigned farkı
- Label ve jump
- call / ret (temel mantık)
Aşağıda hem öğretici hem de tekrar amaçlı bir örnek var. Kod Linux x86-64 NASM mantığına göredir. (ama asıl amacımız mimariyi pekiştirmek).
Şimdi kodun amacı:
- 0’dan 9’a kadar say
- Her sayıyı kontrol et
- Eğer sayı çiftse sayaç artır
- Eğer sayı 5’e eşitse özel kontrol yap
- Döngü sonunda toplam çift sayı adedini elde et
Kod:
section .text
global _start
_start:
mov rcx, 0 ; i = 0
mov rbx, 0 ; even_count = 0
loop_start:
cmp rcx, 10 ; i < 10 ?
jge loop_end ; i >= 10 ise çık
; --- sayı 5 mi kontrol ---
cmp rcx, 5
je five_label
continue_check:
; --- çift mi kontrol ---
test rcx, 1 ; en düşük bit kontrol
jnz not_even ; 1 ise tek sayı
inc rbx ; çiftse even_count++
not_even:
inc rcx ; i++
jmp loop_start ; döngü başına dön
five_label:
; buraya sadece rcx == 5 gelirse girilir
inc rcx
jmp loop_start
loop_end:
; program sonu
mov rax, 60 ; exit syscall
xor rdi, rdi
syscall
Şimdi kodu parça parça detaylı şekilde inceleyelim:
Register Kullanımı
RCX - sayaç (i)RBX - çift sayı adedi
Önceki derslerde gördüğümüz register dediğimiz şey CPU içindeki hızlı veri alanıdır.
Döngü Mantığı
Kod:
loop_start:
cmp rcx, 10
jge loop_end
Buradaki blok şu yapıya benzer:
C:
while(rcx < 10)
cmp - rcx - 10 yapar
jge - Greater or Equal (Büyük veya Eşit) ise atla
Signed karşılaştırmadır.
Eşitlik Kontrolü
Kod:
cmp rcx, 5
je five_label
Bu blokta cmp flag (bayrak) ayarlar. je - Zero Flag (ZF) = 1 ise atlar. Bu aslında şu demektir:
C:
if(rcx == 5)
test Komutu
Kod:
test rcx, 1
jnz not_even
Burada test AND işlemi yapar ama sonucu yazmaz. rcx & 1 kontrol edilir. Binary olarak:
- Son bit 0 - çift
- Son bit 1 - tek
C:
if(rcx % 2 != 0)
inc / dec
Kod:
inc rbx
inc rcx
Burada inc register değerini 1 artırır.
Koşulsuz Atlamak
Kod:
jmp loop_start
Burada hiçbir koşul yok. Direkt belirtilen label’a gider. Bu kısımda program akışını manuel yönlendiriyoruz.
Program Çıkışı (System Call)
Kod:
mov rax, 60
xor rdi, rdi
syscall
Linux’ta 60 - exit syscall numarasıdır. Burada:
RAX - sistem çağrısı numarası
RDI - çıkış kodu
Yani syscall - kernel’e geçiş yapar.
Yukarıdaki Assembly kodunun yüksek seviyeli dile karşılığı şudur:
C:
int even_count = 0;
for(int i = 0; i < 10; i++)
{
if(i == 5)
continue;
if(i % 2 == 0)
even_count++;
}
Assembly’de bu olay tamamen:
- Flag kontrolü
- Register manipülasyonu
- Akış yönlendirme
Neden Bu Örnek Önemli?
Çünkü gerçek hayatta:
- Şifre kontrol mekanizmaları
- Serial doğrulamalar
- Hash hesaplamalar
- Crackme algoritmaları
Bu bölümde Assembly da döngüleri işledik ve hangi komutlar kullanılır bunları gördük. Siz de bu örneklerden yola çıkarak pratik yapabilir ve kendinizi geliştirebilirsiniz. Bir sonraki konuda görüşmek üzere, herkese iyi forumlar dilerim.





