匯編語言——更靈活的定位內存地址的方法
and和or指令
1、and指令
將2進制中的1當做真,2進制中的0當做假
則:只有2個事件都為真的時候才為真,即1&&1==>1,1&&0==>0,0&&0==>0;
用處:假如想把一個數的第7位變成0,讓它和01111111B執行與操作就好了
1 mov al,10001101B ; 8位數據 2 3 add al,01111111B 4 5 >> (al)=00001101B
2、or指令
只要2個事件中有1個是真即為真,即1||1==>1,1||0==>1,0||0==>0;
用處:假如想把一個數的第7位變成1,讓它和10000000B執行或操作就好了
mov al,01101101B ; 8位數據 or al,10000000B >> (al)=11101101B
ASCII碼
大小寫轉換
由上圖可以得知大寫字母的ASCII碼比小寫字母的ASCII碼小32(20H),也就是說大寫字母和小寫只有第5位不同(大寫:0,小寫:1)
大寫 二進制 小寫 二進制 A 01000001 a 01100001 B 01000010 b 01100010 C 01000011 c 01100011 D01000100 d 01100100
示例:將BaSiC全部變成大寫,將iNfOrMaTiOn全部變成小寫。
1 assume cs:codesg,ds:datasg 2 datasg segment 3 db ‘BaSiC‘ ; 0~4內存單元 4 db ‘iNfOrMaTiOn‘ ; 5~15內存單元 5 datasg ends 6 7 codesg segment 8 start: mov ax,datasg 9 mov ds,ax 10 mov bx,0 11 movcx,5 ; 循環5次 12 13 ; 將BaSiC全部變成大寫 14 s:mov al,[bx] ; 獲取相應內存單元的值,賦給al低位寄存器 15 add al,11011111B; 將第5位變成0 16 mov [bx],al ; 將修改後的放回之前的內存單元 17 inc bx ; bx自增1 18 loop s 19 20 mov bx,5 21 mov cx,11 22 ; 將iNfOrMaTiOn全部變成小寫 23 s0:mov al,[bx] 24 or al,00100000B ; 將第5位變成0 25 mov [bx],al 26 inc bx 27 loop s0 28 29 codesg ends 30 end start
[bx+idata]
我們可以用[bx]的方式來指明一個內存單元, 我們還可以用一種更為靈活的方式來指明內存單元:
[bx+idata]表示一個內存單元,它的偏移地址為(bx)+idata(bx中的數值加上idata)。
示例:使用[bx+idata],將BaSiC全變小寫,將MinIX全變大寫
1 assume cs:codesg,ds:datasg 2 datasg segment 3 db ‘BaSiC‘ ; 內存單元0-4 4 db ‘MinIX‘ ; 內存單元5-9 5 datasg ends 6 7 codesg segment 8 start: mov ax,datasg 9 mov ds,ax 10 11 mov bx,0 12 mov cx,5 13 14 s:mov al,[bx] 15 or al,00100000B ; 或操作,全變成小寫 16 mov [bx],al 17 18 mov bl,[bx+5] 19 and al,11011111B ; 與操作,全變成大寫 20 mov [bx+5],al 21 inc bx 22 loop s 23 24 mov ax,4c00H 25 int 21H 26 27 codesg ends 28 end start
SI和DI寄存器
si和di寄存器和ds寄存器的作用一樣,都是用來表示內存的偏移地址的。只是SI和DI不能夠分成兩個8 位寄存器來使用。
我們還可以這樣使用它們:[bx+si],[bx+di]和[bx+si+idata],[bx+di+idata],其實和[dx+idata]一樣
示例:*****
將datasg段中每個單詞改為大寫字母
我們很容易就會想到以下代碼,因為在第2層循環中修改了cx。等它們跳出第二層循環時cx=0,第一層循環會執行cx=cx-1 ==>-1(FFFF),從而進入死循環
1 assume cs:codesg,ds:datasg 2 datasg segment 3 db ‘ibm ‘ ; 16個字節 0-15 4 db ‘dec ‘ ; 16-31 5 db ‘dos ‘ ; 32-47 6 db ‘vax ‘ ; 48-63 7 datasg ends 8 9 codesg segment 10 start: ; 因為要將每行的每個單詞改為大寫,所以我們需要寫兩層循環 11 mov ax,datasg 12 mov ds,ax 13 mov bx 14 mov cx,4 15 s:mov cx,3 16 mov so,0 ; 這個要寫在外面 17 s0: 18 mov al,[bx+si] 19 add al,11011111B 20 mov [bx+si],al 21 inc si ; 如果是將bx+1的話,就會1,2,3,13,14,15,...這樣,所以我們要用si/di寄存器 22 loop s0 23 24 add bx,16 25 loop s 26 27 mov ax,4c00H 28 int 21H 29 30 codesg ends 31 end start
我們可以采用把cx的值放進其他寄存器中,但寄存器是有限的,當程序過大就不夠用了
1 assume cs:codesg,ds:datasg 2 datasg segment 3 db ‘ibm ‘ ; 16個字節 0-15 4 db ‘dec ‘ ; 16-31 5 db ‘dos ‘ ; 32-47 6 db ‘vax ‘ ; 48-63 7 datasg ends 8 9 codesg segment 10 start: 11 mov ax,datasg 12 mov ds,ax 13 mov bx 14 mov cx,4 15 s:mov cx,3 16 mov dx,cx ;;;;;; 用其他寄存器保存一下 17 18 s0:mov si,0 19 mov al,[bx+si] 20 add al,11011111B 21 mov [bx+si],al 22 inc si 23 loop s0 24 25 add bx,16 26 mov cx,dx ;;;;; 將cx取出 27 loop s 28 29 mov ax,4c00H 30 int 21H 31 32 codesg ends 33 end startView Code
然後我們可以把他放進內存中,內存是可以隨便用的啊,但當循環多的時候,你需要把所以內存位置都記住。這很不方便
1 assume cs:codesg,ds:datasg 2 datasg segment 3 db ‘ibm ‘ ; 16個字節 0-15 4 db ‘dec ‘ ; 16-31 5 db ‘dos ‘ ; 32-47 6 db ‘vax ‘ ; 48-63 7 dw 0 ;;;;; 定義一個字來保存cx的值(64) 8 datasg ends 9 10 codesg segment 11 start: 12 mov ax,datasg 13 mov ds,ax 14 mov bx,0 15 mov cx,4 16 s:mov cx,3 17 mov [64],cx ;;;;;; 放進字單元中保存一下 18 mov si,0 19 s0: 20 mov al,[bx+si] 21 add al,11011111B 22 mov [bx+si],al 23 inc si 24 loop s0 25 26 add bx,16 27 mov cx,[64] ;;;;; 將cx取出 28 loop s 29 30 mov ax,4c00H 31 int 21H 32 33 codesg ends 34 end startView Code
所以我們要使用棧的方式來進行兩層循環的嵌套
這樣做的好處是:多層循環嵌套的話,每一層往裏面push一個值,等它出來的時候pop的值就是那個,我們只需要管理一個棧就好了,不用管其他的。
1 assume cs:codesg,ds:datasg,ss:stacksg 2 datasg segment 3 db ‘ibm ‘ ; 16個字節 0-15 4 db ‘dec ‘ ; 16-31 5 db ‘dos ‘ ; 32-47 6 db ‘vax ‘ ; 48-63 7 datasg ends 8 9 stacksg segment 10 dw 0,0,0,0,0,0,0,0 ;;;;; 定義一個棧段 11 12 codesg segment 13 start: 14 mov ax,datasg 15 mov ds,ax 16 mov ax,stacksg ;;;;; 保存棧段的位置 17 mov ss,ax ;;;;; 賦值給ss 18 mov sp,16 ;;;;; 指向棧頂 19 mov bx,0 20 mov cx,4 21 s:mov cx,3 22 push cx ;;;;;; 入棧 23 mov si,0 24 s0: 25 mov al,[bx+si] 26 add al,11011111B 27 mov [bx+si],al 28 inc si 29 loop s0 30 31 add bx,16 32 pop cx ;;;;; 出棧 33 loop s 34 35 mov ax,4c00H 36 int 21H 37 38 codesg ends 39 end start
匯編語言——更靈活的定位內存地址的方法