元のタイトル
次のプログラムでは、これらのデータが定義されています。
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つのメモリ領域の操作
ds
、es
2つのセグメント・レジスタ、その結果、ds
データセグメントのデータ・セグメント・レジスタは、es
セグメント・テーブル・レジスタ部、以下のコードの最初のセクションではds
、es
、ss
セグメントは、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桁、必須ax
、dx
2つのレジスタ。
完全なアセンブリコード:
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進数、下図はデータ表現領域です。
データ比較により、アセンブラの計算結果が正しいことがわかります。