「アセンブリ言語」 - 読書ノート - 第 7 章 - メモリ アドレスを見つけるためのより柔軟な方法
7.1 and および or の指示
- and 命令: 論理 AND 命令、ビットごとの AND 演算
mov al, 00001111b
and al, 01010101b
;结果: 00000101b 双方都为1的位为1,其他为0
- or 命令: 論理 or 命令、ビットごとの or 演算
mov al, 00001111b
and al, 01010101b
;结果: 01011111b 只要有1方为1的位就为1,双方都是0的位为0
7.2 ASCIIコードについて
コンピュータはそれを認識するだけです01
。
そのため、人々は多くのルールを定義しています。ASCII
つまり、テキストのエンコード ルール
(小文字など) は、a
でのASCII
エンコードを定義します97
。
したがって、a
読み取りと書き込みのプロセスは次のようになります。
- 書く
- キーボードを押す
a
- プログラムはルール
a
に従ってASCII
コーディングされたものを受け取り、97
97
バイナリに変換して1100001
保存します。(メモリまたはハードディスク)
- キーボードを押す
- 読む
1100001
プログラムは、コンピュータがこれが 10 進数であることを認識するまでメモリから読み取ります。97
- ルールを使用したデコード
ASCII
、97
小文字の表現a
- 描画されることをグラフィックス カードに通知します
a
。(先ほど紹介したのはビデオメモリの書き込み、描き方は表示の作業です)
データ自体は無効であり、プログラムが特定のルールに従ってデータを処理する場合にのみ意味があることがわかります。
別のルール セットを含む別のプログラムがある場合、それが読み取られると、その内容は1100001
まったく異なる意味になります。
7.3 文字形式で与えられるデータ
アセンブリプログラムでは、'......'
文字データは(シングルクォーテーション)の形式で宣言され、コンパイラによって対応するASCII
コードに変換されます。
手順7.1
assume cs:code, ds:data
data segment ; 占16字节
db 'Jerry' ; 4A 65 72 72 97
db 'abc' ; 61 62 63
data ends
code segment
start: mov al, 'a'
mov bl, 'b'
mov ax, 4c00h
int 21h
code ends
end start
コンパイラは文字をASCII
コードに変換します。
7.4 大文字と小文字の変換に関する問題
- コード表を確認してください
ASCII
(ただし、ルールは順守できます)。ASCII
大文字と小文字のコードは関連しています32
。 - 大文字を小文字に変換する場合は、大文字を小文字の +32、小文字を大文字の -32 に変換します。(しかし、
ASCII
デザインは非常に賢いので、現在の大文字を判断する必要はありません) A
との違いはa
1位です6
。00100000b
=20H
=32
01 0 00001
01 1 00001
ビット演算を使用してand 1101 1111
大文字に変換します。(6 番目の位置は 0、他のビットは変更されません)
A:01000001 a:01100001
and 20H:11011111 11011111
-----------------------------
A:01000001 A:01000001
ビット演算を使用して or 0010 0000
小文字に変換します。(ビット 6 は 1、他のビットは変更されません)
A:01000001 a:01100001
or 20H:00100000 00100000
-----------------------------
a:01100001 a:01100001
7.5 [bx+idata] (変数 + 固定オフセット)
idata
:定数を示します。データがメモリからフェッチされ、メモリに送信される
mov ax, [bx+200]
ことを示します。最終的な結果は物理アドレス: content + constantであり、物理アドレスを取得した後、アドレスからコンテンツが取り出されます。((ds)*16+(bx)+200)
ax
[]
bx
200
質問7.1
以下のプログラムを実行後、ax、bx、cxの内容をメモします。
code segment ; ax bx cx ds
start: mov ax, 2000h ; 2000
mov ds, ax ; 2000
mov bx, 1000h ; 1000
mov ax, [bx] ; 00BE
mov cx, [bx+1] ; 0600
add cx, [bx+2] ; 0606
code ends
end start
7.6 [bx+idata] を使用して配列を処理する
idata
: アドレスの受け渡しの理解によれば、idata は配列アドレスに相当します
bx
。 : 配列を走査するときの i に相当する走査量を示します。
データで定義されている最初の文字列を大文字に変換し、2 番目の文字列を小文字に変換します。
assume cs:code;, ds:data
data segment ; 占16字节
db 'jerry'
db 'ABCDE'
data ends
code segment
start: mov ax, data
mov ds, ax
mov bx, 0 ; i = 0
mov cx, 5 ; len = 5
s: mov al, [0+bx] ; 0表示第一个数组的位置 bx表示索引
and al, 11011111b ; 转大写
mov [0+bx], al ; 送回内存
mov al, [5+bx] ; 5表示第二个数组的位置 bx表示索引
or al, 00100000b ; 转小写
mov [5+bx], al ; 送回内存
inc bx ; i++
loop s ; cx--; cx != 0 继续循环,循环结束
mov ax, 4c00h
int 21h
code ends
end start
7.7 SI と DI (送信元アドレス > 宛先アドレス)
si
および はdi
8086CPU の同様の機能を持つbx
レジスタです。
si と di を 2 つの 8 ビットレジスタに分割して使用することはできません。
- 一般的な使用法は、2 つのメモリ間でデータをコピーする場合です。
ds:si はソースを指します
ds:diは宛先を指します
質問7.2
si
と を使用して、文字列をその後ろのデータ領域にコピーしますdi
。welcome to masm!!
assume cs:codesg,ds:datasg
datasg segment
db 'welcome to masm!' ; 占16字节
db '................' ; 占16字节
datasg ends
codesg segment
start: mov ax, datasg
mov ds, ax
mov si, 0 ; 指向第一行字符开头
mov di, 16 ; 指向第二行字符开头
mov bx, 0 ; i = 0 对应字符索引
mov cx, 8 ; len = 8 每次复制一个字,共循环处理8次
s: mov ax, [si+bx] ; 取第一行的第bx个字符
mov[di+bx], ax ; 送到第二行的第bx位
add bx, 2 ; i++ (每次偏移1个字 = 2字节)
loop s ; cx--; cx != 0 继续循环,循环结束
mov ax, 4c00h
int 21h
codesg ends
end start
質問7.3
最適化問題 7.2 コード量を削減します。OR またはORを使用して削減
できます。[bx+idata]
[si+idata]
[di+idata]
assume cs:codesg,ds:datasg
datasg segment
db 'welcome to masm!' ; 占16字节
db '................' ; 占16字节
datasg ends
codesg segment
start: mov ax, datasg
mov ds, ax
mov si, 0 ; i = 0
mov cx, 8 ; len = 8 每次复制一个字,共循环处理8次
s: mov ax, 0[si] ; 取第一行(偏移量0)的第bx个字符
mov 16[si], ax ; 送到第二行(偏移量16)的第bx位
add si, 2 ; i++ (每次偏移1个字 = 2字节)
loop s ; cx--; cx != 0 继续循环,循环结束
mov ax, 4c00h
int 21h
codesg ends
end start
7.8 [bx+si]和[bx+di]
bx+ 変数、より柔軟
たとえば、配列演算:
si: 元の配列を示します (メモリ内の配列の最初の要素のアドレスを指します)
di: ターゲット配列を示します (配列の最初の要素のアドレスを指します) bx:インデックス
を示します。1
サイクルで 2 つの配列を操作すると便利です。
質問7.4
以下のプログラムを実行後、ax、bx、cxの内容をメモします。
; 2000:1000 BE 00 06 00 00 00
assume cs:codesg
codesg segment ; ax bx cx ds si di
start: mov ax, 2000H ;
mov ds, ax ; 2000
mov bx, 1000H ; 1000
mov si, 0 ; 0000
mov ax, [bx+si] ; 00BE
inc si ; 0001
mov cx, [bx+si] ; 0600
inc si ; 0002
mov di, si ; 0002
add cx, [bx+di] ; 0606
mov ax, 4c00h
int 21h
codesg ends
end start
7.9 [bx+si+idata]和[bx+di+idata]
bx+変数+定数、より柔軟な
例: 2 次元配列操作: (オフセットを通じて、行と列の概念が実現されます)
idata: 2 次元配列を表します (配列の最初の要素のアドレスを指します)。メモリ内の配列)
bx: 行を表します (ネストされた for では、for
の最初の層の i) di: 例を表します (ネストされた for の for の 2 番目の層の j に相当します)
質問7.5
以下のプログラムを実行後、ax、bx、cxの内容をメモします。
; 2000:1000 BE 00 06 00 6A 22
assume cs:codesg
codesg segment ; ax bx cx ds si di
start: mov ax, 2000H ;
mov ds, ax ; 2000
mov bx, 1000H ; 1000
mov si, 0 ; 0000
mov ax, [bx+2+si] ; 0006
inc si ; 0001
mov cx, [bx+2+si] ; 6A00
inc si ; 0002
mov di, si ; 0002
add cx, [bx+2+di] ; 8C6A(6A00+226A)
mov ax, 4c00h
int 21h
codesg ends
end start
7.10 さまざまなアドレッシングモードの柔軟な適用
[idata]
直接定位
メモリユニットに使用できるアドレスを表すには定数を使用します。[bx]
间接定位
メモリ ユニットに使用できるメモリ アドレスを表す変数を使用します。[bxtidata]
変数と定数を使用してアドレスを表し、起始地址的基础
変数と间接定位
メモリ ユニットを 1 つで使用できます。[bx+si]
2 つの変数を使用してアドレスを表します。[bx+sitidata]
アドレスは 2 つの変数と 1 つの定数で表されます。
[idata]
から まで[bx+sitidata]
、より柔軟な方法を使用してメモリ ユニットのアドレスを特定することがわかります。これにより、扱っているデータをより構造化された観点から見ることができます。
本質は、最初に中和式の結果を物理アドレスとして[]
計算し、次にそのメモリ部分を指すことです。寄存器
常量
質問7.6
datasg セグメント内の各単語の最初の文字を大文字に変更するプログラム
assume cs:codesg,ds:datasg
datasg segment ; 占16*6=16字节
db '1. file ' ; 占16字节,末尾空格填充
db '2. edit ' ; 占16字节,末尾空格填充
db '3. search ' ; 占16字节,末尾空格填充
db '4. view ' ; 占16字节,末尾空格填充
db '5. options ' ; 占16字节,末尾空格填充
db '6. help ' ; 占16字节,末尾空格填充
datasg ends
codesg segment
start: mov ax, datasg
mov ds, ax
mov bx, 0
mov cx, 6
s: mov al,[bx+3] ; 取 bx行第3列
and al, 11011111b ; 转大写
mov [bx+3], al ; 送回内存
add bx, 16
loop s
mov ax, 4c00h
int 21h
codesg ends
end start
質問7.7
プログラミング、datasgセクションの各単語を大文字に変更してください
このセクションはネガティブな教材であり、2つのループがCXを共有し、無限ループに陥ります。
assume cs:codesg,ds:datasg
datasg segment ; 占16*4=24字节
db 'ibm ' ; 占16字节,末尾空格填充
db 'dec ' ; 占16字节,末尾空格填充
db 'dos ' ; 占16字节,末尾空格填充
db 'vax ' ; 占16字节,末尾空格填充
datasg ends
codesg segment
start: mov ax, datasg
mov ds, ax
mov bx, 0
mov cx, 4 ; 循环4次对应4行
s0: mov si, 0 ; 每行的字符索引从0开始
mov cx, 3 ; 本意是循环3次对应3个字符
; 但是它覆盖了上面“行”的循环计数。
; 两层循环共用同一个cx计数,就崩了。
s: mov al,[bx+si] ; 取 bx行第3列
and al, 11011111b ; 转大写
mov [bx+si], al ; 送回内存
inc si ; 内层循环j++ 指向下一个字符
loop s ; 内层循环
add bx, 16 ; 外层循环i++ 指向下一歫
loop s0 ; 外层循环
mov ax, 4c00h
int 21h
codesg ends
end start
質問7.8
7.7 のバグを修正しました。内側のループが開始されるたびに、外側のループの cx に値を保存し、外側のループのループ命令を実行する前に外側のループの cx の値を復元します。レジスタ dx を使用して cx の値を一時的に保存することができます。改良された手順は次のとおりです。
assume cs:codesg,ds:datasg
datasg segment ; 占16*4=24字节
db 'ibm ' ; 占16字节,末尾空格填充
db 'dec ' ; 占16字节,末尾空格填充
db 'dos ' ; 占16字节,末尾空格填充
db 'vax ' ; 占16字节,末尾空格填充
datasg ends
codesg segment
start: mov ax, datasg
mov ds, ax
mov bx, 0
mov cx, 4 ; 循环4次对应4行
s0: mov dx, cx ; 将外层循环的 cx 值保存在 dx 中
mov si, 0 ; 每行的字符索引从0开始
mov cx, 3 ; 循环3次对应3个字符
s: mov al,[bx+si] ; 取 bx行第3列
and al, 11011111b ; 转大写
mov [bx+si], al ; 送回内存
inc si ; 内层循环j++ 指向下一个字符
loop s ; 内层循环
add bx, 16 ; 外层循环i++ 指向下一行
mov cx, dx ; 用 dx 中存放的外层循环的计数值恢复 cx
loop s0 ; 外层循环
mov ax, 4c00h
int 21h
codesg ends
end start
質問7.9
プログラムで、datasg セグメント内の各単語の最初の 4 文字を大文字に変更します。
assume cs:codesg,ss:stacksg,ds:datasg
stacksg segment ; 占16字节
dw 0,0,0,0,0,0,0,0
stacksg ends
datasg segment ; 占64字节
db '1. display ' ; 占16字节
db '2. brows ' ; 占16字节
db '3. replace ' ; 占16字节
db '4. modify ' ; 占16字节
datasg ends
codesg segment
start:
codesg ends
end start