Menu

Daxil olun Qeydiyyat

Assembler x86 Linux (64 bit)

Prosessor - CPU

Prosessor - CPU

CPU (prosessor) ilə sadə tanışlıq

CPU-nu kiçik bir mikrosxemə yerləşdirilimiş böyük bir zavod kimi təsəvvür eləmək olar. Onun iş prinsipini, strukturunu izah eləmək üçün bir neçə kitab tələb olunur. CPU barədə ətraflı məlumat əldə etmək istəyənlər üçün Intel 80386 Programmer's Reference Manual kitablarını məsləhət görürəm.

CPU unit (vahid) adlandırılan bir neçə hissədən ibarətdir. Bunlardan ən əsas hissələr Execution (instruksiyaları icra edən), Instruction Decode (instruksiyaları çevirən), SegmentPaging (yaddaşı idarə edən) və proqramlaşdırmada ən çox istifadə olunan Registers (registrlər) hissəsidir. Registrlərdən başqa yerdə qalan bütün hissələr sırf sistem proqramlaşdırmaya aiddir. Yeganə registrlərdən istifadəçi proqramlaşdırmada istifadə olunur. Bundan əlavə, istifadəçi proqramlarına prosessorun əməliyyatlar sisteminin müəyyən elədiyi kəsilmələr çağırmaq imkanı da verilir.

Burada biz assembler dilində istifadəçi proqramlaşdırmanı öyrənəcəyik. Buna görə, hələlik sadəcə registrləri bilməyimiz kifayətdir.

 

Register-lər

Registrlər prosessorun xarici dünya ilə əlaqə saxlaması üçündür. CPUilə əlaqə saxlamaq üçün istifadə olunan ən əsas iki vasitədən biri məhz CPU-nun registrləridir, digər vasitə isə, siqnallardır (kəsilmələr).

Qeyd: Nə qədər üzücü olsa da, qeyd eləməliyəm ki, Windows əməliyyatlar sistemində hansısa (naməlum) məqsədlər üçün istifadə olunan Registr ifadəsi CPU-nun registrləri ilə qarışıqlıq yaradır. CPU-nun registrləri ilə Windows-da istifadə olunan registr faylları arasında qətiyyən heç bir əlaqə yoxdur, tamamilə ayrı məfhumlardır. Sadəcə olaraq, anlamıram niyə Microsoft-un proqramçıları bu qədər kritik əhəmiyyəti olan "registrlər" terminindən ayrı məqsəd üçün istifadə edirlər.

 

Gəlin, registrlərlə daha yaxından tanış olaq.

Registr çox kiçik ölçüyə malik olan, prosessora aid yaddaş sahəsidir. Prosessor hər hansı proqramı icra etmək üçün fiziki yaddaşdan bu proqramın məlumat və instruksiyalarını kiçik hissələrlə əvvəlcə özünün registrlərinə köçürür, daha sonra, emal etmək üçün digər hissələrə ötürür. Bu fikirdən yanaşsaq, görərik ki, prosessor registrlərdən məlumatları müvəqqəti olaraq saxlamaq üçün istifadə edir.

Registrlərin ölçüsü prosessorun arxitekturasından asılı olaraq, 2, 4, 8 bayt və daha artıq ola bilər. Başqa sözlə, 16, 32, 64 bit və s. Prosessorun registrlərinin sayı arxitekturadan asılı olaraq müxtəlif ola bilər. İntel i386 arxitekturalı prosessorların təqribən 17-yə yaxın registri olur. Prosessor bu registrləri müxtəlif məqsədlər üçün istifadə edir. İstifadə sahələrinə görə, registrlər aşağıdakı qruplara bölünür: ümumi registrlər, yaddaş registrləri, idarə registrləri, sazlama registrləri, bayraqlar və s.

Biz bu dərslikdə əsasən, prosessorun ümumi registrlərini öyrənəcəyik.

Bundan sonra, prosessor dedikdə Intel 80386 arxitekturalı prosessorlar nəzərdə tutulur.

Prosessorun ümumi registrləri aşağıdakılardır: EAX, EBX, ECX, EDX, EBP, ESP, ESI və EDI. Bu registrlərin hər birinin ölçüsü 32 bitdir (4 bayt)

 


 

Bu registrlərin hər birinin ilk 16 bitinə ayrıca uyğun olaraq, AX, BX, CX, DX, BP, SP, SI və DI adları ilə müraciət etmək olar. 16 bitlik məlumatlarla işləyən zaman bu imkan çox əlverişlidir.

 


 

 

Bundan əlavə, AX, BX, CX, DX registrlərinin özləri də 8 bit-8 bit olmaq üzrə, 2 hissəyə bölünürlər. Bu hissələr uyğun olaraq AH, BH, CH, DH (15-8 bit) və AL, BL, CL DL (7-0 bit)-dir.

 


 

Proqramın daxili strukturu

Müasir icraolunabilən faylların (proqramların) daxili strukturu müxtəlif hissələrdən ibarətdir. Bu hissələrin hər birinin təyinatı və iş prinsipinin öyrənilməsi sistem proqramlaşdırma mövzusudur. Bu barədə ətraflı məlumat almaq istəyənlər aşağıdakı sənəddən faydalana bilərlər:

Tool Interface Standards (TIS) Portable Formats Specification, Version 1.1 Executable and Linkable Format (ELF)

Bu sənəddə elf tipli linklənəbilən və icraolunabilən faylların (obyekt faylların və proqramların) daxili strukturu tam detalları ilə izah olunur.

Biz isə, bir qədər sadələşdirilmiş şəkildə proqramın strukturu ilə tanış olacağıq. Strukturunun mürəkkəbliyindən asılı olmayaraq, hər bir proqram özündə iki əsas hissəni saxlamalıdır: məlumatlar və instruksiyalar. Məlumatlar proqramın icrası zamanı elan olunan və istifadə olunan məlumatlardır, İnstruksiyalar isə proqramın bu məlumatlar üzərində yerinə yetirdiyi əməliyyatlardır. Bunları nəzərə alsaq, icraolunabilən proqramın sadə strukturunu aşağıdakı kimi verə bilərik:

 


 

Proqramın məlumat hissəsi .data, instruksiyalar hissəsi isə .text kimi işarə olunur. Qeyd edim ki, yüksək səviyyəli dillərdə biz məlumatları və instruksiyaları proqram mətnində qarışıq istifadə edirik və proqramın mətnini məlumatlar və əməliyyatlar kimi müxtəlif hissələrə ayırmırıq. Bu işlər proqramın kompilyasiyası zamanı kompilyator tərəfindən həyata keçirilir. Assembler dilində isə, görəcəyimiz kimi məlumatlar və instruksiyaları proqramın müvafiq hissələrində yerləşdirməliyik.

 

İlk proqram

Beləliklə, biz prosessorun və proqramın strukturu ilə müəyyən dərəcədə tanış olduq, artıq assembler dilində ilk proqram nümunəsini daxil edə bilərik.


#prog1.s

.text
.globl _start

_start:

movl $1, %eax
int $0x80

Proqramın izahı:

Proqramın ilk sətri #prog1.s sətridir. Assembler proqramlarında # ilə başlayan sətirlər şərhləri bildirir.

Növbəti sətir .text sətridir. Bu ifadədə proqramın instruksiyalar hissəsinin başlanğıcını elan edirik.

Proqramımızda növbəti sətir .globl _start sətridir. Ümumiyyətlə, . ilə başlayan ifadələr yığma proqramı üçün nəzərdə tutulub (proqramın assembler mətn kodunu obyekt koda çevirən proqrama yığma proqramı deyilir).

.globl ifadəsi yığma proqramına _start nişanının qlobal nişan olduğunu bildirir. Bu barədə hələlik dərinə getməyək.

Proqramın növbəti sətri _start: sətridir. Assembler dilində qoşa nöqtə (:) ilə bitən ifadələr nişan adlandırılır və hansısa məlumat və ya kod hissəsinin başlanğıcına işarə edirlər.

Nişanları .text və .data hissələrində istədiyimiz kimi təyin edə bilərik. Bəzi nişanlar isə, o cümlədən, _start nişanı əvvəlcədən təyin olunmuş xüsusi əhəmiyyətli nişanlardır.

_start nişanı proqramın icraya başladığı yeri bildirir.

Növbəti sətir movl $1, %eax instruksiyasıdır. Bu instruksiya birbaşa prosessor tərəfindən icra olunur və bu zaman prosessorun %eax registrinə 1 qiyməti yazılır. Assembler dilində (AT&T sintaksisi) registr adlarını dəyişən və digər adlardan fərqləndirmək üçün registr adlarının əvvəlinə faiz (%) işarəsi artırılır. Ədədləri isə, yaddaş ünvanlarından fərqləndirmək üçün $ işarəsindən istifadə edirlər. Bu barədə ətraflı irəlidə, yaddaşa müraciət metodlarını öyrəndikdə tanış olacağıq.

Proqramın sonuncu instruksiyası isə, int $0x80 instruksiyasıdır.

int instruksiyası kəsilmə instruksiyasıdır. İstifadəçi proqramları əməliyyatlar sistemindən hər hansı xidmətin yerinə yetirilməsini sifariş vermək üçün kəsilmədən istifadə edirlər. Bu xidmətlərə daimi yaddaşa, şəbəkəyə və kompüterin digər resurslarına müraciət daxildir. Baxdığımız halda biz sistemdən proqramı söndürməyi xahiş edirik.

Bütün bu deyilənlərdən belə aydın olur ki, baxdığımız proqram icraya başlayır, prosessorun %eax registrinə 1 qiyməti yazır və icrasını başa çatdırır.

 

Assembler dilində proqramların icrası

Yuxarıda verilmiş proqramı icra edək. Bunun üçün proqram kodunu proq1.s adlı mətn faylında yadda saxlayırıq. proq1.s-dən icra oluna bilən proqram almaq üçün onu yığmalıyıq. Terminaldan prog1.s faylı yerləşən qovluğa daxil oluruq və aşağıdakı əmrləri daxil edirik:

as prog1.s -o prog1.o

ld prog1.o -o prog1

Nəticədə, işci qovluqda proq1 adlı yeni proqram faylı yaranacaq. Bu proqramı icra eləmək üçün ./prog1 əmrini daxil edirik.

Aşağıdakı kimi:


[user@unix progs]$ 
[user@unix progs]$ as prog1.s -o prog1.o
[user@unix progs]$ ld prog1.o -o prog1
[user@unix progs]$ ./prog1
[user@unix progs]$

Qeyd: Kitabda daxil etdiyimiz bütün proqramlar bu üsulla yığılıb yerinə yetirilir.

Proqramı icra etdikdə, gördüyümüz kimi, heç bir nəticə almırıq, proqramı yükləyən kimi o, dərhal başa çatır. Ancaq gördüyümüz işin doğruluğunu yoxlamaq üçün nəticəni test edə bilmək mütləq vacibdir. Ən azından ekranda hansısa məlumat çap edə bilsək, nəyisə yoxlaya bilərik. Amma təəssüf ki, bunu etmək üçün əlimizdə yüksək səviyyəli dillərdə olduğu kimi printf, std::cout, Console.writeln və s. kimi funksiyalar yoxdur. Buna görə, assemblerdə çap etməni öyrənənə kimi bir müddət primitiv üsullarla nəticələri yoxlamalı olacağıq.

Misal üçün, əgər proqramın sonunda %ebx registrinə hansısa məlumat yazsaq, proqramı icra etdikdən sonra bu məlumatı echo $? əmri ilə öyrənə bilərik.

Gəlin, assembler dilində ikinci proqramımıza nəzər salaq.


#proq2.s
 
.text
.globl _start

_start:

movl $4, %ebx

movl $1, %eax
int $0x80

Bu proqramı yığıb icra etsək və dərhal sonra echo $? əmrini daxil etsək, onda ekranda 4 qiyməti çap olunar.

Nəticə:


[user@unix progs]$ 
[user@unix progs]$ as proq2.s -o proq2.o
[user@unix progs]$ ld proq2.o -o proq2
[user@unix progs]$ ./proq2
[user@unix progs]$ echo $?
4
[user@unix progs]$ 
[user@unix progs]$

Bu başlıqda biz prosessorun məlumat registrləri, proqramın əsas struktur vahidləri, assembler dilində proqram yazmaq, yığmaq və test etmək qaydaları ilə tanış olduq. Növbəti başlıqda biz CPU-nun bəzi ümumi instruksiyaları ilə tanış olacağıq.

Tapşırıq:

1. Hər dəfə %ebx registrinə 0-la 255 arasında olan müxtəlif qiymətlər verməklə, proq2.s proqramını bir neçə dəfə təkrar yerinə yetirib nəticəni yoxlayın.


Bizi dəstəkləyənlər