Menu

Daxil olun Qeydiyyat

Assembler x86 Linux (64 bit)

Bit əməliyyatları

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Ə 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ə  əməliyyatı tətbiq edərək, nəticəni arg2-də saxlayır. Bitlərə  ə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 -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]$


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