ds = 076A; ss = 076B; cs = 076C;
X-2; X-1;
ds = 076A; ss = 076B; cs = 076C;
X-2; X-1;
ds = 076A; ss = 076C; cs = 076E;
X -4; X-2;
ds = 076C; ss = 076E; cs = 076A;
X + 2; X + 4;
我的猜想是第四组代码(task1_4.asm)可以正确执行。在将上述4组代码最后的end start
改为end
之后,如果按照编译、链接、执行的顺序依次下来,结果仍然是什么都没有(因为没有对显存进行操作)。在这一过程中,三个步骤除了链接时会警告没有栈段之外(这个警告即使不修改代码也会出现),均不会出现警告。而在自行根据代码执行到上述实验所要求的那一行后,得到的ds、ss的值也相同,即都可以正确执行。唯一不同的在于cs,但是cs:ip
最终指向的内存地址也相同。
其中,有区别的在于,由于没有指定代码段的起始地址,前三个都需要自行计算代码段,然后根据偏移地址用g
命令执行程序。
这可能是因为程序是自顶向下执行,虽然没有从指定的代码段处开始,但是由于数据段和栈段是空的,所以不会影响后面的代码段。在这样的情境下,程序都会执行到终止的指令为止。虽然第四组代码的执行过程可能与修改前一致,但是由于栈段和数据段并没有会修改程序执行的指令,所以这四组代码最终都可以正确执行。
向b800:0f00~b800:0f9f
这连续160字节依次重复填充十六进制数据03 04
。
由于是小端存储,所以十六进制数据0304
代表的十六进制数是0403h
。这一十六进制数占2个字节,如果用循环语句来实现的话,就是要循环80次。
assume cs:code code segment start: mov ax, 0b800h mov ds, ax mov bx, 0f00h mov ax, 0403h mov cx, 80 s: mov [bx], ax add bx, 2 loop s mov ax, 4c00h int 21h code ends end start
由于这一程序是一个整体,那么三个数据段data1 data2 data3
和代码段code
应该是连续存储。前两个代码段长度不到16字节,那么按16字节存储。这样一来三个数据段的地址都明确了。可以让ds指向第一个数据段data1
进行处理。而debug都是将程序从076A:0
开始装入,那么可以认为第一个数据段哦才能够这里开始。
assume cs:code data1 segment db 50, 48, 50, 50, 0, 48, 49, 0, 48, 49 ; ten numbers data1 ends data2 segment db 0, 0, 0, 0, 47, 0, 0, 47, 0, 0 ; ten numbers data2 ends data3 segment db 16 dup(0) data3 ends code segment start: mov ax, 076ah mov ds, ax mov bx, 0 mov cx, 10 s: mov ax, 0 add ax, [bx] add ax, [bx+10h] mov [bx+20h], ax add bx, 1 loop s mov ah, 4ch int 21h code ends end start
assume cs:code data1 segment dw 2, 0, 4, 9, 2, 0, 1, 9 data1 ends data2 segment dw 8 dup(?) data2 ends code segment start: mov ax, data2 mov ss, ax mov sp, 16 mov ax, data1 mov ds, ax mov bx, 0 mov cx, 8 s: mov ax, [bx] push ax add bx, 2 loop s mov ah, 4ch int 21h code ends end start
assume cs:code, ds:data data segment db 'Nuist' db 2, 3, 4, 5, 6 data ends code segment start: mov ax, data mov ds, ax mov ax, 0b800H mov es, ax mov cx, 5 mov si, 0 mov di, 0f00h s: mov al, [si] and al, 0dfh mov es:[di], al mov al, [5+si] mov es:[di+1], al inc si add di, 2 loop s mov ah, 4ch int 21h code ends end start
通过位与运算,将(从左到右)第三位转换为0,从而实现小写字母转换成大写字母
这里数值的作用应该是控制显存中内容的颜色
assume cs:code, ds:data data segment db 'Pink Floyd ' db 'JOAN Baez ' db 'NEIL Young ' db 'Joan Lennon ' data ends code segment start: mov ax, data mov ds, ax mov bx, 0 mov cx, 4 s: mov ax, [bx] or ax, 2020h mov [bx], ax mov ax, [bx+2] or ax, 2020h mov [bx+2], ax add bx, 10h loop s mov ah, 4ch int 21h code ends end start
data
段第一行5个数字,按字符存储,每个字符占1个字节,故一个数字占4个字节,第一行共占用20个字节,每一个数据要分两次移动。第二、第三行按字存储,每个数据固定占2个字节,每一个数据一次即可移动。table
段初始化了5行16字节的空格。本题中用到的除法,除数占1个字即2个字节,共16位,那么被除数就需要占32位,即4个字节,高位放在dx
中,低位放在ax
中,由于被除数也是按字存储,所以dx
初始化为0即可。
对于整个程序的控制是按照逻辑段table
中格式进行。年分和收入需要4个字节,就用bx
控制,循环末自加4。雇员数和人均收入需要2个字节,就用di
控制,循环末自加2。
assume cs:code, ds:data, es:table data segment db '1975', '1976', '1977', '1978', '1979' dw 16, 22, 382, 1356, 2390 dw 3, 7, 9, 13, 28 data ends table segment db 5 dup( 16 dup(' ') ) ; table ends code segment start: mov ax, data mov ds, ax mov bx, 0 mov ax, table mov es, ax mov ax, 0 mov si, ax mov di, ax mov cx, 5 s: mov ax, [bx] mov es:[si], ax mov ax, [bx]+2 mov es:[si]+2, ax mov dx, 0 mov es:[si]+5, dx mov ax, [bx]+20 mov es:[si]+7, ax div word ptr ds:[di]+30 mov es:[si]+13, ax mov ax, [di]+30 mov es:[si]+10, ax add di, 2 add bx, 4 add si, 16 loop s mov ah, 4ch int 21h code ends end start
这里实际上由于题设的代码中收入是按字存储,所以实际上并没有必要在表格中给收入分配4个字节的存储空间,所以我把高两个字节初始化为了0,其他部分可以通过计算证明正确。