8086アセンブリ実験:構造化データアクセスにおけるアドレッシングモードの適用

元のタイトル

ここに画像の説明を挿入
次のプログラムでは、これらのデータが定義されています。

data segment
	db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
	db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
	db '1993','1994','1995'

	dd 16,22,382,1356,2390,8000,16000,24486,50056,97479,140417,197514
	dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000

	dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
	dw 11542,14430,15257,17800
data ends

table segment
	db 21 dup ('year summ ne ?? ')
table ends

プログラムは、データセクションのデータを次の形式でテーブルセクションに書き込み、21年間の1人当たりの収入を計算します(切り上げ)。結果は、次の形式でテーブルセクションにも保存されます。
ここに画像の説明を挿入
ここに画像の説明を挿入

問題解決

C言語の実装

まず、質問の意味を理解し、使い慣れたC言語を使用して、実行する必要のある操作を記述します。

  • 1つ目は、C言語のデータセグメントで、配列を使用して以下を格納します。
char years[21][4] = {
    
    '1', '9', '7', '5', '1', '9', '7', '6',
					 '1', '9', '7', '7', '1', '9', '7', '8',
					 '1', '9', '7', '9', '1', '9', '8', '0',
					 '1', '9', '8', '1', '1', '9', '8', '2',
					 '1', '9', '8', '3', '1', '9', '8', '4',
					 '1', '9', '8', '5', '1', '9', '8', '6',
					 '1', '9', '8', '7', '1', '9', '8', '8',
					 '1', '9', '8', '9', '1', '9', '9', '0',
					 '1', '9', '9', '1', '1', '9', '9', '2',
					 '1', '9', '9', '3', '1', '9', '9', '4',
					 '1', '9', '9', '5'};
int summs[21] = {
    
    16, 22, 382, 1356, 2390, 8000, 16000, 24486,
				 50056, 97479, 140417, 197514, 345980, 590827,
				 803530, 1183000, 1843000, 2759000, 3753000, 4649000, 5937000};
short nes[21] = {
    
    3, 7, 9, 13, 28, 38, 130, 220, 476, 778, 1001,
				 1442, 2258, 2793, 4037, 5635, 8226, 11542, 14430, 15257, 17800}; 
  • 次に、テーブル構造を作成する必要があります。
struct table
{
    
    
	char year[4];
	int summ;
	short ne;
	short ave;
};
struct table T[21];
  • ここで、トピックで実行したいのは、C言語で実装されているテーブルセクションのデータセクションにデータを格納することです。
// C语言描述
int main()
{
    
    
	for (int i = 0; i < 21; i++)
	{
    
    
		for (int j = 0; j < 4; j++)
			T[i].year[j] = years[i][j];
		T[i].ne = nes[i];
		T[i].summ = summs[i];
		T[i].ave = summs[i] / nes[i];
	}
}
  • 以下に、テーブルテーブルの10進形式と16進形式をそれぞれ出力します(後で比較するために使用します)。
	for (int i = 0; i < 21; i++)
	{
    
    
		for (int j = 0; j < 4; j++)
			printf("%c", T[i].year[j]);
		printf("\t%d", T[i].summ);
		printf("\t%d", T[i].ne);
		printf("\t%d\n", T[i].ave);
	}
	for (int i = 0; i < 21; i++)
	{
    
    
		for (int j = 0; j < 4; j++)
			printf("%c", T[i].year[j]);
		printf(" %08x", T[i].summ);
		printf(" %04x", T[i].ne);
		printf(" %04x\n", T[i].ave);
	}

操作の結果は次のとおりです。
ここに画像の説明を挿入
ここに画像の説明を挿入

8086アセンブリの実装

上記の分析では、次のアセンブリコードを使用して上記の関数を実装します
。上記のC言語の説明は、特定のルールに従って、メモリ内のデータをメモリの別の領域にコピーする必要があることを示しています。つまり、CPUは最初にメモリを読み取り、次にデータをメモリに書き込みます。書き込みの前にデータの計算が行われます。

  • コードセグメントの前に、データの処理を支援するためにスタックセグメントが必要です。C言語の説明には、スタックに使用する必要のある2層ループがあります。
stacksg segment
	db 16 dup (0)		;16字节的内存作为栈段
stacksg ends
  • 使用する2つのメモリ領域の操作dses2つのセグメント・レジスタ、その結果、dsデータセグメントのデータ・セグメント・レジスタは、esセグメント・テーブル・レジスタ部、以下のコードの最初のセクションではdsesssセグメントは、3つのデータ・レジスタに格納されています。
start:	mov ax,stacksg
		mov ss,ax
		mov ax,datasg
		mov ds,ax
		mov ax,tablesg
		mov es,ax
  • 次のコードはbp、テーブルセグメントを個別にアドレス指定するために使用され、毎回16ずつインクリメントされます(テーブル構造インスタンスのサイズが16バイトであるため)。diデータセグメント内のneデータをアドレス指定するために使用さ、各サイクルは自己です。 -インクリメント。2ずつ増加(各neデータは2バイトを占める);siデータセグメント内の合計データをアドレス指定するために使用し、毎回4ずつインクリメントする(合計はダブルワードデータであり、4バイトを占める);しかし、年データも4バイトであるためsi、bxを使用して各年データの各バイトをループすることで、同時に各年のアドレス指定と見なすことができます。除算を計算するときは、32桁の数値をで割った値に注意してください。 16桁、必須axdx2つのレジスタ。
    完全なアセンブリコード:
assume cs:codesg,ds:datasg,ds:tablesg,ss:stacksg

stacksg segment
	db 16 dup (0)		;16字节的内存作为栈段
stacksg ends

datasg segment
	db '1975','1976','1977','1978','1979','1980','1981','1982','1983'
	db '1984','1985','1986','1987','1988','1989','1990','1991','1992'
	db '1993','1994','1995'
	;以上是表示21年的21个字符串,起始地址datasg:0

	dd 16,22,382,1356,2390,8000,16000,24486,50056,97479,140417,197514
	dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000
	;以上是表示21年公司收入的21个dword型数据,起始地址datasg:84

	dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226
	dw 11542,14430,15257,17800
	;以上是表示21年公司雇员人数的21个word新数据,起始地址datasg:168
	;数据段总大小210字节
datasg ends

tablesg segment
	db 21 dup ('year summ ne ?? ')
				;|0123456789abcdef|
				;|year summ ne ?? |
				; 0    5 7  a  d
tablesg ends

codesg segment

start:	mov ax,stacksg
		mov ss,ax
		mov ax,datasg
		mov ds,ax
		mov ax,tablesg
		mov es,ax

		mov bp,0 				;用于table表寻址,每次循环自增16
		mov si,0 				;用于数据中summ寻址,每次循环自增4
		mov di,0 				;用于数据中ne寻址,每次循环自增2
		mov cx,21
	s:	push cx

		mov bx,si  				;用于数据中year寻址
		push si
		mov si,0
		mov cx,4
	s0:	mov al,ds:[bx+si]
		mov es:[bp+si],al
		inc si
		loop s0
		pop si
								;以上循环实现将年份信息存入table表中

		mov ax,ds:[di+168]
		mov es:[bp+0ah],ax		;table表存入ne
								;C语言描述中的T[i].ne = nes[i]

		mov ax,ds:[si+84]		;双字型数据的低16位
		mov dx,ds:[si+86]		;双字型数据的高16位
		mov es:[bp+5],ax
		mov es:[bp+7],dx		;table表存入summ
								;C语言描述中的T[i].summ = summs[i]

		div word ptr es:[bp+0ah]
		mov es:[bp+0dh],ax		;除法计算,table表存入ave
								;C语言描述中的T[i].ave = summs[i] / nes[i];

		add bp,16
		add si,4
		add di,2
		pop cx
		loop s

		mov ax,4c00h
		int 21h

codesg ends

end start

テスト

最初にdosboxを入力し、masmコマンドを入力してコンパイルします:
ここに画像の説明を挿入
エラーなし、コマンドリンクリンクを入力します:
ここに画像の説明を挿入
生成されたexeファイルを確認した後で
ここに画像の説明を挿入
デバッグし、
ここに画像の説明を挿入
uコマンドをデバッグしてプログラムの終わりを見つけ、cs:ip
ここに画像の説明を挿入
g 04d2:0058を入力しますプログラムを実行し、
ここに画像の説明を挿入
dコマンドを使用して、メモリ内のデータセグメントの格納形式を表示し、
ここに画像の説明を挿入
データストレージの連続性を確認します。
次のdコマンドを使用して、esセグメントレジスタ領域のテーブルテーブルの書き込みステータスを表示すると、次の
ここに画像の説明を挿入
ことがわかります。データはデータに書き込まれており、右側は文字に対応するASCIIコード、左側は16進数、下図はデータ表現領域です。
ここに画像の説明を挿入
ここに画像の説明を挿入
データ比較により、アセンブラの計算結果が正しいことがわかります。

おすすめ

転載: blog.csdn.net/qq_45349225/article/details/115330744