Bu site emekli olmuştur. Arşiv amaçlı olarak BT AKADEMİ sponsorluğunda yayın hayatına devam etmektedir.




C#nedir?com
 
YAZAR HAKKINDA
Eren Erener
Eren Erener
http://www.csharpnedir.com/
İletişme geçmek için tıklayın.
12 Makalesi yayınlanmakta.
Yazar hakkında detaylı bilgi için tıklayın.
Yayınlanan diğer makaleleri için tıklayın.
İlgili etiketler: aslinda bitlik bunlar byte’lik degeri degerleri degisken degiskenler deklare direktifi dizinin erismek hafizada pointer program X86 Assembly Eren Erener
 
YAZI HAKKINDA
Türü : Makale
Serbest Köşede C#nedir?com üyelerinin hazırladıkları yazılar yayınlanır. Bu yazılar editör incelemesine girmeden yayınlanır.
Seviyesi : Başlangıç
Kategori : X86 Assembly
Yayınlanma Tarihi : 2.5.2005
Okunma Sayısı : 56091
Yorum Sayısı : 1     yorum yaz
Site İçi AramaSİTE İÇİ ARAMA
Üye Girişini AçÜye GİRİŞİ
Üye girişi için tıklayın.
Kullanıcı Adı
Şifre
 
Beni her zaman hatırla
Bir hafta boyunca kullanıcı bilgilerinizi kullanıcı çıkışı yapana kadar hatırlar. (Paylaşılan bilgisayarlarda önerilmez.)
 
Şifremi / Kullanıcı Adımı unuttum.
 
.net TV RSS Serbest KÖŞE (?)
Serbest Köşede C#nedir?com üyelerinin hazırladıkları yazılar yayınlanır. Bu yazılar editör incelemesine girmeden yayınlanır.
emre TAŞ
Silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
Makale Gönder Bende Yazmak İstiyorum
.net TV RSSBlogroll
Turhal Temizer
Conda install environment.yml Package 21.11.2024
Turhal Temizer
Mac OS/X Removing CUDA 21.11.2024
Burak Selim Şenyurt
Rust ile ECS Yaklaşımını Anlamak 21.11.2024
Burak Selim Şenyurt
Birlikte Rust Öğrenelim Serisi 21.11.2024
  Diğer Herşey
Sponsorlar
BT Akademi
Medya Portakal
Video Hosting Sponsoru
Csharpnedir.com bir Ineta üyesidir
Uzman Abi
Her Yönüyle C# - Sefer Algan
X86 Assembly Dilinde Değişken Bildirimi - 1
 
Kapat
Sayfayı Yazdır Sık Kullanılanlara Ekle Arkadaşıma Gönder MySpace Del.Ico.Us Digg Facebook Google Mixx Reddit StumbleUpon
Daha önce üst seviye programlama dilleri ile uğraştıysanız değişkenler hakkında bilginiz muhakkak vardır. x86 assembly dilinde de programcılar programlarında kullanacakları bazı verileri, değişken olarak tanımlarlar. Aslında bunlar byte yada bytelardan oluşan dizilerdir. Hafızadaki bu veriler, programınızdaki kullanım şekline göre değişik haller alabilir.

DEĞİŞKENLERİ DEKLARE ETMEK

Örneğin 2 sayıyı toplayan program yazmayı düşünelim. Bunu 2 değişik şekilde yapabiliriz. Birincisi acil adresleme modu ile;

MOV    AL,5
ADD    AL,4

Bu örnekte hiçbir değişken tanımlanmamıştır ve bu program parçası sadece 5 ile 4 ü toplar ve sonucu işlemcinin içindeki AL kaydedicisinde saklar. Tabi bu programın ne kadar kullanışlı olduğunu artık siz tahmin edin. Oysa bu sayıları birer değişken olarak tanımlasaydık daha esnek bir program hazırlamış olurduk.

.DATA
sayi1    DB    5
sayi2    DB    4
toplam    DB    ?
.
.
.
.CODE
.
.
MOV    AL,sayi1
ADD    AL,sayi2
MOV    toplam,AL

Yukarıdaki program parçasında 3 adet bir byte’lık değişken tanımlanmıştır. Bunlar sayi1, sayi2 ve toplam değişkenleridir. Aslında bu yazdığımız satırlar assembler’a bir demeç şeklindedir. Assembler programımızı derlerken, hafızada bizim kullanmamız için 3 byte’lık alan ayıracak ve bu alanlardan birine 5 diğerine 4 değerlerini yerleştirecektir. Toplam değişkeninin değeri program çalıştığında önemli olacağından dolayı, onun değeri henüz atanmamış fakat şundan da emin olun ki o adreste muhakkak bir değer mevcuttur.

Gördüğünüz gibi değişkenlerini isimleri, türleri ve değerleri mevcut. Değişken ismi (sayi1 gibi) aslında bir offset adresidir ve kullanımı seçimliktir. Şayet değişken tanımlarken isim kullanmazsanız assembler yine hafızada değişkenin türüne göre yer ayırır. Fakat böyle bir durumda değişkeni programınızın içinde kullanmak için adresini (ds:0000 gibi) bilmeniz gerekir. Çok sayıda değişken tanımlarken bu adresleri hesaplamak güç olacağından dolayı değişkenlere isim vermemek pek tavsiye edilmez. Değişkenin türü ise boyutu ile alaklıdır, örneğin DB ile değişkenimizin 1 byte’lık olacağını belirtiyoruz. Son olarak değişkenin değeri tabi ki bir rakam yada sayı olmak durumunda. Şayet başlangıçta değer önemli değilse ? operatörünü kullanabilirsiniz.

Kaynak kodda değişkenleri bu şekilde yazarak assemblera hafızada yer tahsis etmesini söylemiş, bir başka deyişle değişken deklare etmiş oluyoruz.

İşaret Karmaşası

1 byte’lık bir hafıza alanına ne sığar? Toplam 256 adet farklı değer 1 byte ile tanımlanabilir. Bunlar onluk düzende 0-255 arası sayılar veya -128’den 127 ye kadar olan işaretli sayılar olabilir. Kafanız karışmasın bu değerleri aslında binary olarak düşünmek lazım, çünkü 0...255 ve -128...127 arası sayılar toplam 512 adet ediyor. Aslında, bunlar sadece 1’lerin ve 0’ların kombinasyonlarıdır. Yani 1 byte 0000 00002 ile 1111 11112 arasında değişen kombinasyonlardan oluşur.

Günlük hayatımızda işaretli bir sayıyı tanımlamak ne kadarda kolay değil mi? Başına - işaretini getirdiğimiz zaman işlem tamamdır. Fakat bilgisayarlarda 1 ve 0 dan başka kullanacağınız bir değer yok. İşaretli veya işaretsiz sayılar, harfler, metinler, resimler, mp3’ler ve Tomb Raider :) tamamen 1 ve 0’lardan oluşur. İşte bu 1 ve 0’ları program içinde yorumlamak önemlidir, ancak o zaman anlam kazanırlar.

Aslında işlemci (CPU) sadece matematiksel, mantıksal ve veri taşıma işlemleri yapar. Bu bağlamda bizim için alt seviyede önemli olan 1 ve 0’lardır. O zaman işaretli ve işaretsiz sayılar neye göre belirlenecek? Boyutlar ve işlemci durum kaydedicisi (flag register) burada imdadımıza yetişiyor. Örneğin 1111 1111 değeri onluk düzende 255’mi yoksa -1’mi.

255’tir, çünkü 1111 11112 = 20+21+22+23+24+25+26+27 = 255

-1’dir, çünkü 1 ile toplandığında 1 byte’lık alanda 0000 00002 değeri elde edilir ve elde biti oluşur.


Şekil 1 - 1 byte’lık bir değer 1 byte’lık başka bir değerle toplanınca sonuç 1 byte’lık olmak zorundadır.

1 byte’lık bir değer 1 byte’lık başka bir değerle toplanınca sonuç bir byte’lık olmak zorundadır, çünkü ayrılan fiziksel alan bu kadardır. Bu işlemde artan 1 bitlik değer ilkokul matematiğinden bildiğimiz elde’dir ve bu elde işlemci durum kaydedicisinin C (carry) bitinde saklanır. Daha önce işlemci durum kaydedicisinin bitsel olarak önemli olduğundan bahsetmiştim.

Bu kargaşa tamamen boyutların sınırlı olmasından kaynaklanıyor. Ayrıca bilgisayarın bu hesap mantığı ile pozitif bir sayı bir başka pozitif sayı ile toplandığında negatif bir değer de elde edilebilir. Bunu tam tersi de olabilir. Biz bunları ilerleyen makalelerimizde, işlemci durum kaydedicisini anlatırken işaret ve boyut taşması olarak inceleyeceğiz. Şimdilik siz matematiksel hesaplamalar yaparken alanlarını kısıtlı olduğunu göz ardı etmeyin. Yani 2 sayıyı toplayan program yerine, sonuç olarak maksimum 255 değerini gösteren program demek şu anda daha doğru olur :)

BASİT DEĞİŞKENLER

Byte  Değişkenleri

Bir byte boyutunda değerleri deklare etmek istiyorsak genellikle DB direktifini kullanıyoruz. DB İngilizce’de Define Byte yani byte tanımla anlamına gelir. Bu direktif ile hafızada 1 byte’lık bir alan tahsis eder ve bu alana adresi ile erişebilirsiniz. MASM ile DB direktifi yerine byte yada sbyte direktiflerini de kullanabilirsiniz, fakat sonuçta assembler’ın yapacağı iş aynıdır.

i db 0 j byte 255 ;MASM için alternatif direktif k sbyte -1 ;MASM için alternatif direktif Yukarıdaki üç tanımlama farklı gibi gözükse de assembly dili yazımı değişkenleri tanımlarken boyut dışında bir sınır koymaz. Örneğin k değişkenine sonradan "mov k, 125" komutu ile pozitif bir değer atayabiliriz. Yapılamayacak olan ise "mov i, 300" veya "mov j, -150" gibi 1 byte’a sığmayacak değerleri bu değişkenlere atamaktır.

DB direktifi ile;

Ayrılan Hafıza Alanı : 1 Byte
Tanımlanabilecek Değer Aralığı: -128...255

Word  Değişkenler

DW 8086’dan 80286 işlemcisine kadar offset adresleri, işaretli ve işaretsiz tamsayılar tanımlamak için kullanılan en geniş veri tipiydi.

-32768...65535 arasındaki tam sayları DW direktifi ile deklare edebiliriz. MASM için word ve sword direktifleri de aynı işi görür. Word değişkenler hafızada 16 bit yani 2 byte’lık alan kaplarlar.

sayi1 dw ?
sayi2 dw ?
isayi1 dw ?
sayi_0 dw 0
sayi_eksi dw -1
sayi_enbuyuk dw 65535
pointer    dw           sayi1
Özetle DW direktifi ile;

Ayrılan Hafıza Alanı : 2 Byte
Tanımlanabilecek Değer Aralığı: -32768...65535

Double Word Değişkenler

4 byte’lık değişkenler tanımlamak için kullanılır. DD direktifi ile bu türdeki değişkeleri tanımlayabilirsiniz. MASM ile dword, sdword direktiflerini de kullanabilirsiniz.

sayi1 dd ?
sayi2 dd ?
isayi1 dd ?
sayi_0 dd 0
sayi_eksi dd -1
sayi_enbuyuk dd 4000000000
pointer     dd           sayi2
DD direktifi ile;

Ayrılan Hafıza Alanı : 4 Byte
Tanımlanabilecek Değer Aralığı: -2,147,483,648...4,294,967,295

6, 8 ve 10 Byte’lık Değişkenler

DF direktifi ile 6, DQ direktifi ile 8 ve DT direktifi ile 10 byte’lık değişkenler tanımlanır. Fakat bu direktifler aslında kayar noktalı BCD (ikilik düzende kodlanmış onluk sayılar) sayılar için kullanılır. Bu 3 direktifin asıl kullanım amaçları aşağıda açıklanıyor.

DF: 80386 ve üstü işlemcilerde, 32 bitlik korumalı modda, 48 bitlik pointer (indeksleme amacıyla, offset adreslerini göstermek için kullanılan bir işaretçi) olarak kullanılır. Bu direktif ile 6 byte’lık değişkenlerin tanımlanması mümkün olsa da 80386 ve sonrası işlemcilerde pointer olarak kullanılır.

DQ: 64 bitlik kayar noktalı sayları 64 bitlik tamsayıları deklare etmek için kullanılır. Daha çok kayar noktalı sayıları deklare etmek için kullanılır, çünkü x86 ailesinin henüz 64 bitlik genel amaçlı bir kaydedicisi yoktur. Yani bu direktif ile 64 bitlik bir tam sayı deklare ettiğinizde, bu sayı ile doğrudan işlem yapamazsınız çünkü en büyük kaydedici 32 bitliktir.

DT: Daha hassas (80 bitlik) kayar noktalı sayılar ve 10 byte’lık BCD değerleri deklare etmek için kullanılır.

Yukarıdaki direktiflerle ilgili ayrıntılı bilgileri kayar noktalı sayılarla işlemler başlığı altında ilerleyen makalelerimizde vereceğim.

Pointer Veri Tipleri

Pointer işaretçi anlamına gelip adresleme modlarında gördüğümüz indeksli adresleme ile alakalıdır. x86 uyumlu işlemciler iki tür pointer’ı desteklerler. Bunlar near (yakın) ve far (uzak) pointer’lardır. Buradaki yakın ve uzak kavramı referans alınan adresin segmenti (64Kb.) aşmaması yada aşması durumunu ifade eder.

Near pointer’ler 16 bitlik’tir ve bir segmentin offsetlerine erişmek için kullanılırlar. p bir değişken olsun, p=1000h için aşağıdaki kodları inceleyelim.

mov     bx, p           ;BX’e p pointerını yükle.
mov     ax, [bx]       ;p’nin gösterdiği konumdaki veriyi AX’e getir.

Örnekte AX kaydedicisinin değeri pointer’ın işaret ettiği adresten alınacak 2 byte’lık değer ile değişecektir. Bir başka deyişle DS:1000h ve DS:1001h adresindeki değerler AX’e yüklenecek. Bu işlem aynı segment içinde olduğundan dolayı, pointer near yani yakın bölgedeki bir adresi göstermiş oldu. Aslında mov ax,ds:1000h komutu da aynı işi yapardı fakat pointer değişkeni kullanılmadığından sonradan pointer değerini değiştirip aynı komut satırı ile hafızanın başka bir bölgesine erişmek mümkün olmazdı.

Far (uzak) pointer’lar ile hafızanın istediğiniz bölgesine erişip işlem yapabilirsiniz. Bunun için pointer deklare edilirken DD direktifinin kullanılması gerekir, yani pointer 32 bitlik olmalıdır. BX, BP, SI ve DI kaydedicilerini erişeceğiniz uzak offsetler için herhangi bir segment kaydedicisini de (ki bu genellikle ES olur) erişmek istediğiniz segment için kullanabilirsiniz. İsterseniz bunu bir örnek ile açıklamaya çalışalım.

5555:3333 adresine erişip, buraya FFh değerini kopyalamaya çalışacağız. Bu işlemi yapan program aşağıdaki gibidir. Kaynak kodları buradan download edebilirsiniz.


Şekil 2 - Uzak adreslere erişmek için 32 bitlik pointer’lar kullanılır.

Bu örnekte pointer 32 bitlik’tir ve erişeceğimiz segment:offset adresini gösterir. LES komutu ES kaydedicisine pointer değişkeninin yüksek değerlikli 2 byte’ını (5555h) yüklerken, operandında gösterilen kaydediciye de (bu örnekte BX) düşük değerlikli 2 byte’ını (3333h) yükler. MOV ES:[BX], AL komutu ile de 5555:3333 adresine AL deki FFh değeri kopyalanır. Aşağıdaki şekiller ile bu programın pointer kullanarak nasıl uzak adreslere eriştiğini görebilirsiniz.


Şekil 3 - LES BX, P komutu işlenmeden önce ES ve BX’in durumu


Şekil 4 - Pointer değişkeni ilgili kaydedicilere yüklendikten sonra


Şekil 5 - 5555:3333 adresine FF değeri yüklendikten sonra

ÇOKLU DEĞİŞKENLER

Bu tür değişkenler birden fazla parçadan oluşur. Tek boyutlu ve çok boyutlu diziler (arrays) ve yapılar (structures) bu tür değişkenlerdir. Bu makalede sadece tek boyutlu dizileri anlatmaya çalışacağım, çok boyutlu diziler ve yapıları başka bir makalede güzel örneklerle, amacına uygun bir şekilde anlatacağım.

Diziler

Dizilerlerde diğer değişkenler gibi hafızaya yerleştirilmiş verilerden oluşur. Ard-arda gelen byte, word veya double word değişkenler dizileri oluşturabilir. Daha önceki makalelerimizde "Merhaba Assembly" yazısını ekrana yazdırmıştık, işte bu karakterlerde hafızada dizi olarak saklanır. Şu anda yazdığım karakterlerde hafızada bir dizi veri olarak saklanacak.

Dizi kavramının yanında getirdiği bazı terimler vardır, bunlar indeks, taban adresi, dizi elemanı ve eleman tipi’dir. Burada dikkat edilmesi gereken en önemli nokta diziyi oluşturacak elemanların aynı türden olma koşuludur. Diğer terimleride isterseniz aşağıdaki şekille açıklamaya çalışalım.


Şekil 6 - Diziler ile ilgili terimler.

Dizinin tüm elemanlarının aynı türden olması gerektiğini söylemiştik, bununla beraber dizinin ilk elemanının adresi taban adresidir. Dizinin elemanlarına erişmek için bu adres referans olarak alınabilir. Son olarak dizinin ilk elemanından itibaren adresler artarak devam eder ve bu adreslerdeki her elemana indeks değerleri ile erişilir. Dizinin herhangi bir elemanına erişmek için kullanılacak klasik formül;

Eleman_Adresi = Taban_Adresi + ((Indeks - İlk_Index) x Eleman_Boyutu)

Bu formülde ilk_indeks 0 ise göz ardı edilebilir.

Dizilerin Deklare Edilmesi

Başlangıçta elemanların değerleri önemli değilse;

Dizi    DB     100    DUP (?)    ;byte türünden 100 elemanlı bir dizi
Dizi    DW    100    DUP (?)    ;word türünden olduğundan dolayı hafızada 200 byte’lık alan kaplar.

Buradak DUP direktifi ingilizcedeki duplicate (diğerinin aynısı) kelimesinin karşılığıdır.

Elemanlar aynı olacaksa;

Dizi    DB     100    DUP (12h)    ; Hafızaya 100 adet 12h yerleştirir.

Elemanlar farklı ise;

Dizi    DB    32, 45, 67, 3F, 0, 7, 11    ;7 tane byte türünden elemandan oluşan bir dizi.
Yazi    DB    ’Merhaba Assembly’         ;16 elemanlı bir karakter dizisi, hafızada ascii kod karşılıkları saklanır.

Unutulmaması gerekir ki taban adresi dizinin başında yazdığımız etikettir, örneğin yukarıda ’Merhaba Assembly’ karakterlerinden oluşan byte türündeki dizinin taban adresi Yazi’dır.

Tek Boyutlu Dizilerin Elamanlarına Erişmek

WordDizi    DW    1, 45, 1234h, 567Ah, 99, 105Eh

Yukarıdaki dizinin 2. elemanına erişmek demek o elemanın adresini bulmak ile aynı anlama gelir. Bunun için formülümüz vardı;

Eleman_Adresi = Taban_Adresi + ((Indeks - İlk_Index) x Eleman_Boyutu)

Bu formülü word tipindeki dizimize uygulayacak olursak;

Eleman_Adresi = WordDizi + ((2 - 0) x 2)

yada;

Eleman_Adresi = WordDizi + 2 olarak bulunur.

Tabi ki bu işlemi bir program ile yapmak lazım. Aynı işi yapan program parçası aşağıda verilmiştir.

mov    bx, 2                    ; indeks değeri BX’e yükleniyor,
add     bx, bx                  ; 2*bx işlemi yapılıyor,
mov    ax, WordDizi [bx]    ; AX’e dizinin 2. elemanı (1234h) yükleniyor.

Dizi elemanlarına erişmek için çok değişik teknikler mevcut, fakat bunları ilerleyen makalelerimizde açıklayacağım. Bazen assembly programcıları dizilerini deklare ederken, dizinin ilk elemanı olarak indeks değerini koyarlar. Tabi ki bu durumun doğruluğu görecelidir. Örneğin byte türünden bir dizi için bu teknikle en fazla 255 elemandan oluşan bir dizi deklare edebilirsiniz. Daha fazla eleman deklare etmek için indeks değerinin boyutunu arttırmak gerekir ama bu durumda da dizi elemanlarının aynı türden olması şartını göz ardı etmemek gerekir.

Diziler usta programcıların vazgeçemediği veri yapılarıdır. Önemli olan dizinin elemanlarına erişmek için kullanılacak olan fonksiyonu assembly dilinde yazabilme kabiliyetidir. Örneğin;

Yildizlar    DB    10  DUP    (’*’)

dizisinden aşağıdaki üçgeni ekrana yazdırmak gibi.

*
**
***
****

Alın size ödev, bir daha ki makaleye kadar bu programı yazmaya çalışın, böylece hem adresleme modlarını hem de tek boyutlu dizileri kavramış olursunuz. Sakın zor demeyin elin oğlu dizilerden matrix türetip, sonra ona felsefi bir boyut ekleyip filim yapıyor :)

Makale:
X86 Assembly Dilinde Değişken Bildirimi - 1 Assembly ve X86 Programlama Eren Erener
  • Yazılan Yorumlar
  • Yorum Yaz
AĞU
23
2010
sonda dediğiniz yıldızlı üçgen programını nasıl yazıcaz?
Sayfalar : 1 
Yorum yazabilmek için üye girişi yapmalısınız. Üye girişi için tıklayın.
Üye değilseniz Üyel Ol linkine tıklayarak üyeliğinizi hemen başlatabilirisniz.
 
  • Bu Konuda Son 10
  • Eklenen Son 10
  • Bu Konuda Geçmiş 10
Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
Son Eklenen 10 Makale Yükleniyor
Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor