Bit əməliyyatları
Biz qeyd elədik ki, məlumatın ölçü vahidi bayt-dır. Lakin bəzən verilmiş baytın və ya baytlar ardıcıllığının hansısa mövqedə yerləşən bir və ya bir neçə bitinin qiymətini öyrənmək, dəyişmək, sola-sağa sürüşdürmək və s. əməliyyatlar aparmaq lazım gəlir. Bilirik ki, %eax registrinin ölçüsü 4 baytdır, başqa sözlə 32 bit. Registrin bitləri sağdan sola 0-dan başlayaraq nömrələnir.
Sola - Sağa sürüşmə
Bitlər ardıcıllığını sola və ya sağa sürüşdürmək üçün shll və shrl instruksiyalarından istifadə olunur. Misal üçün, shrl say, arq instruksiyası arq məlumatının bitlərini say vahid sağa sürüşdürür. Boşalan bitlərin yerinə 0-lar yazılır. Misal üçün, 0011010 bitlər ardıcıllığını 1 vahid sağa sürüşdürsək, 0001101 alarıq. 001110 bitlər ardıcıllığını 2 vahid sola sürüşdürsək isə, 111000 alarıq.
Və , Və ya əməliyyatları
Bitlər ardıcıllığı üzərində VƏ, VƏ YA əməliyyatları icra etmək üçün andl və orl instruksiyalarından istifadə edirlər.
and instruksiyası 2 arqument qəbul edir:
and arq1, arq2 şəklində. arq1 ilə arq2-in müvafiq bitlərinə VƏ əməliyyatı tətbiq edərək, nəticəni arg2-də saxlayır. Bitlərə VƏ əməliyyatının tətbiqi aşağıdakı kimidir:
BİT1 | BİT2 | BİT1 VƏ BİT2
-------------------------------
1 | 1 | 1
1 | 0 | 0
0 | 0 | 0
0 | 1 | 0
Cədvəldən gördüyümüz kimi, iki bitin VƏ-si yalnız və yalnız onların hər ikisinin qiyməti 1 olduqda 1 qiyməti alır.
Misal üçün, 0101 ilə 1100 bitlər ardıcıllığının and-i, 0100-a bərabər olar, aşağıdakı kimi:
0|1|0|1
1|1|0|0
-------
0|1|0|0
Başqa misala baxaq, 0100010101011101 ilə 01101111100001011-in and-i 01000101000001011 olar, aşağıdakı kimi:
0|1|0|0|0|1|0|1|0|1|0|1|1|1|0|1|1
0|1|1|0|1|1|1|1|1|0|0|0|0|1|0|1|1
---------------------------------
0|1|0|0|0|1|0|1|0|0|0|0|0|1|0|1|1
Bitlərə VƏ YA əməliyyatının tətbiqi aşağıdakı kimidir:
BİT1 | BİT2 | BİT1 VƏ BİT2
-------------------------------
1 | 1 | 1
1 | 0 | 1
0 | 0 | 0
0 | 1 | 1
Verilimiş iki bitə VƏ YA - orl əməliyyatının tətbiqi cədvəldən gördüyümüz kimi, hər iki bit 0 olduqda, 0 qiyməti alır, qalan bütün hallarda, yəni heç olmasa, ikisindən biri və ya hər ikisi 1 olduqda 1 qiyməti alır.
Maskalama
Sola - sağa sürüşdürmə, VƏ, VƏ YA əməliyyatlarının birgə kompazisiyasından istifadə etməklə, bitlər ardıcıllığı üzərində maraqlı əməliyyatlar yerinə yetirmək olar.
Misal üçün, tutaq ki, %eax registrinin ilk bitinin qiymətini öyrənmək istəyirik. Bunun üçün 0-cı bitin maskasından istifadə etməliyik. 0-cı bitin maskası aşağıdakı kimi olar:
00000000000000000000000000000001
Uyğun olaraq, 1-ci bitin maskası
00000000000000000000000000000010,
31-ci bitin maskası
10000000000000000000000000000000,
15-ci bitin maskası
00000000000000000100000000000000
kimi olar.
Bir daha qeyd edim ki, bitlərin nömrələnməsi 0-dan başlayır.
Qiymətini tapmaq istədiyimiz bitin maskasını %ebx-ə köçürək.
movl 0b00000000000000000000000000000001, %ebx
Artıq %ebx-də ilk bitin maskası yerləşir. Daha sonra, %eax registrinə %ebx registri ilə və - and əməliyyatını tətbiq etsək, ilk %eax registrinin ilk bitinin qiymətini alarıq.
andl %ebx, %eax
Belə ki, %ebx-in ilk bitindən başqa bütün yerdə qalan bitləri 0 olduğundan, %eax-lə VƏ əməliyyatı zamanı %eax-in ilk bitindən savayı yerdə qalan bütün bitləri silinəcək, 0-a bərabərləşəcək. Yekun qiymət isə, %eax-in ilk bitinin qiymətindən asılı olacaq, belə ki, əgər %eax-in ilk biti 0-dırsa, onda nəticə də 0, əks halda isə, 1 olar. Beləliklə, biz %eax-in ilk bitinin qiymətini təyin etmiş olduq.
Gəlin, konkret proqram nümunəsi ilə bunu test edək.
#prog19.s
#%eax registrinin ilk bitini çap edən proqram
.data
setir1:
.ascii " %eax registrinin qiymətini ikili formada daxil edin\n"
say1:
.long 53
setir2:
.ascii "ilk bitin qiyməti "
say2:
.long 18
yeni_str:
.ascii "\n"
str:
.ascii " "
eded1:
.long 0
onluq_simvollar:
.ascii "0123456789"
bufer:
.rept 100
.ascii "\0"
.endr
.text
.globl _start
.type _start, @function
_start:
#%eax registrinin qiymətinin daxil edilməsini istə
pushq say1
pushq $setir1
call cap_et
#qiyməti sətir şəklində qəbul et
pushq $100
pushq $bufer
call daxil_et
#sətri ədədə çevir
pushq $bufer
pushq $eded1
call ikili_setri_edede_cevir
#nəticəni %eax-ə köçür
movl eded1, %eax
#ilk bitin maskasını %ebx-ə yerləşdirək
#əslində, bu halda movl $1, %ebx yazmaq da kifayət edər
movl $0b00000000000000000000000000000001, %ebx
#eax-i #ebx-lə maskalayaq
andl %ebx, %eax
#indi %eax-də ilk bitin qiyməti durur
#onu çap edək
movl %eax, eded1
#nəticəni çap etmək üçün yenidən sətrə çevir
pushq eded1
pushq $str
call ededi_setre_cevir
#məlumatlandırıcı sətir
pushq say2
pushq $setir2
call cap_et
#sətir formasında olan ədədi çap et
pushq $10
pushq $str
call cap_et
#yeni sətir simvolunu çap et
pushq $1
pushq $yeni_str
call cap_et
son:
movl $1, %eax
int $0x80
#==========================================#
# FUNKSİYALAR #
#==========================================#
#cap_et funksiyasə
.type cap_et, @function
cap_et:
pushq %rbp
movq %rsp, %rbp
movl $4, %eax
movl $1, %ebx
movq 16(%rbp),%rcx
movq 24(%rbp),%rdx
int $0x80
popq %rbp
ret
#daxil_et funksiyası
.type cap_et, @function
daxil_et:
pushq %rbp
movq %rsp, %rbp
movl $3, %eax
movl $0, %ebx
movq 16(%rbp),%rcx
movq 24(%rbp),%rdx
int $0x80
popq %rbp
ret
#sətri ədədə çevir
.type setri_edede_cevir, @function
ikili_setri_edede_cevir:
pushq %rbp
movq %rsp, %rbp
#buferdəki sətri ədədə çevir
subq $8, %rsp
#simvolların sayını hesablayaq
#sonuncu simvol '\n' simvoludur
movl $0, %ecx
movl 24(%rbp), %esi
isec_dovr:
movb (%esi, %ecx, 1), %ah
cmpb $'\n', %ah
je isec_dovr_son
incl %ecx
jmp isec_dovr
isec_dovr_son:
movl $1, %ebx
movl $0, -8(%rbp)
movl $0, %eax
decl %ecx
yeni_isec_dovr:
movb (%esi, %ecx, 1), %al
subb $'0', %al
movl %ebx, %edx
imull %eax, %edx
addl %edx, -8(%rbp)
shll $1, %ebx
decl %ecx
cmpl $0, %ecx
jl yeni_isec_dovr_son
jmp yeni_isec_dovr
yeni_isec_dovr_son:
movl 16(%rbp), %ebx
movl -8(%rbp), %eax
movl %eax, (%ebx)
addq $8, %rsp
popq %rbp
ret
#ədədi sətrə çevir
.type ededi_setre_cevir, @function
ededi_setre_cevir:
pushq %rbp
movq %rsp, %rbp
subq $8, %rsp
movl $0, -8(%rbp)
e_s_c_dovr:
movl $10, %edi
movl $0, %edx
movl 24(%rbp), %eax
div %edi
movl %eax, 24(%rbp)
xorq %rbx, %rbx
movb onluq_simvollar(%edx), %bh
pushq %rbx
incl -8(%rbp)
movl $0, %ebx
movl 24(%rbp), %eax
cmpl %eax, %ebx
je e_s_c_dovr_son
jmp e_s_c_dovr
e_s_c_dovr_son:
movl -8(%rbp), %ecx
movl 16(%rbp), %eax
xorl %ebx, %ebx
stekden_setre:
cmpl %ebx, %ecx
je e_s_c_son
popq %rdx
movb %dh, (%eax)
incl %eax
incl %ebx
jmp stekden_setre
e_s_c_son:
addq $8, %rsp
popq %rbp
ret
Nəticəni yoxlayaq:
[user@unix progs_as]$ as prog19.s -o prog19.o
[user@unix progs_as]$ ld prog19.o -o prog19
[user@unix progs_as]$ ./prog19
%eax registrinin qiymətini ikili formada daxil edin
10101011010101
ilk bitin qiyməti 1
[user@unix progs_as]$ ./prog19
%eax registrinin qiymətini ikili formada daxil edin
1001010
ilk bitin qiyməti 0
[user@unix progs_as]$
[user@unix progs_as]$