/assembly-exercise

汇编基础习题集

Primary LanguageAssemblyISC LicenseISC

汇编基础习题集

此仓库中代码为我学习汇编过程中解决过的习题,如果你有其它相关练习打算分享,欢迎提 PR 补充。 你可以将你的解法分享到此仓库中,如果你有此意愿,请 fork 后在 code 目录下新建一个以你名称命名的文件夹,将你的解法放置在该文件夹下,将你的名字添加到此 README 末尾的参与者列表,并提交 PR。如果需要许可声明,请在你的目录下自行添加。

题目来源

环境配置

  • Windows 7 及以上版本:建议使用 DOSBOX,当前最新版本 0.74。需下载 masm.exelink.exedebug.exe。也可以选择 emu8086,但该软件使用的汇编语言标准与 MASM 有差异。DOSBOX 及配套的工具可以从此处下载。安装 DOSBOX 后运行安装目录下的 DOSBox 0.74 Options.bat,在打开的 dosbox-0.74.conf 文件最后加上以下两句。其中 path_to_your_tool 需替换为你的 masm.exe等工具所在的目录。要运行代码,请将代码复制到 path_to_your_tool 目录下,之后启动 DOSBOX,在 DOSBOX 环境下编译、调试。
MOUNT C path_to_your_tool
set PATH=$PATH$;path_to_your_tool
  • Linux/Mac:请访问 DOSBOX 官网的 Download 界面,寻找自己系统对应的版本安装。
  • 编译、链接,以 test.asm 为例。
masm test.asm
link test.obj

习题

建议:在解决问题本身的前提下,应尽量使程序有更好的容错性,能够尽可能处理非常规输入等可能引发异常的情况;应尽量使程序更好地面向用户,优化交互界面。

  • 1、在 ARRAY 数组中依次存储了七个字数据,紧接着是名为 ZERO 的字单元,表示如下:
    (1) 如果 BX 包含数组 ARRAY 的初始地址,请编写指令将数据 0 传送给 ZERO 单元。
    (2) 如果 BX 包含数据 0 在数组中的位移量,请编写指令将数据 0 传送给 ZERO 单元。
ARRAY	DW  23, 36, 2, 100, 32000, 54, 0
ZERO	DW  ?
  • 2、请设置一个数据段 DATASG,其中定义以下字符变量或数据变量。
    (1) FLD1B 为字符串变量:personal computer;
    (2) FLD2B 为十进制数字节变量:32;
    (3) FLD3B 为十六进制数字节变量:20;
    (4) FLD4B 为二进制数字节变量:01011001;
    (5) FLD5B 为数字的ASCII字符字节变量:32654;
    (6) FLD6B 为10个零的字节变量;
    (7) FLD7B 为零件名(ASCII码)及其数量(十进制数)的表格:
    PART1 20
    PART2 50
    PART3 14
    (8) FLD1W 为十六进制数字变量:FFF0;
    (9) FLD2W 为二进制数的字变量:01011001;
    (10) FLD3W 为 (7) 零件表的地址变量;
    (11) FLD4W 为包括5个十进制数的字变量:5, 6, 7, 8, 9;
    (12) FLD5W 为5个零的字变量;
    (13) FLD6W 为本段中字数据变量和字节数据变量之间的地址差。

  • 3、假设程序中的数据定义如下:

    PARTNO	DW		?
    PNAME	DB		16 DUP (?) 
    COUNT	DD		?    
    PLENTH	EQU	$-PARTNO 

请问 PLENTH 的值为多少?它表示什么意义?

  • 4、有符号定义语句如下,问 L 的值是多少?
BUFF	DB   1, 2, 3,123
EBUFF	DB   0
L		EQU  EBUFF - BUFF
  • 5、假设程序中的数据定义如下:
    (1) 用一条 MOV 指令将 LNAME 的偏移地址放入 AX 。
    (2) 用一条指令将 CODE_LIST 的头两个字节的内容放入 SI 。
    (3) 用一条伪操作使 CODE_LENGTH 的值等于 CODE_LIST 域的实际长度。
LNAME		DB  30 DUP (?)
ADDRESS	DB  30 DUP (?)
CITY			DB  15 DUP (?)
CODE_LIST	DB  1, 7, 8, 3, 2
  • 6、试写出一个完整的数据段 DATA_SEG ,它把整数 5 赋予一个字节,并把整数 -1,0,2,5 和 4 放在 10 字数组 DATA_LIST 的头 5 个单元中。然后,写出完整的代码段,其功能为:
    DATA_LIST 中头5个数中的最大值和最小值分别存入 MAXMIN 单元中。

  • 7、按下面的要求写出程序的框架
    (1) 数据段的位置从 0E000H 开始,数据段中定义一个 100 字节的数组,其类型属性既是字又是字节;
    (2) 堆栈段从小段开始,段组名为 STACK ;
    (3) 代码段中指定段寄存器,指定主程序从 1000H 开始,给有关段寄存器赋值;
    (4) 程序结束。

  • 8、写一个完整的程序放在代码段 C_SEG 中,要求把数据段 D_SEG 中的 AUGEND 和附加段E_SEG 中的 ADDEND 相加,并把结果存放在 D_SEG 段中的 SUM 中。其中 AUGENDADDENDSUM 均为双精度数,AUGEND 赋值为 99251 ,ADDEND 赋值为 -15962。

  • 9、试编写一个汇编语言程序,要求对键盘输入的小写字母用大写字母显示出来。

  • 10、编写程序,从键盘接收一个小写字母,然后找出它的前导字符和后续字符,再按顺序显示这三个字符。

  • 11、将 AX 寄存器中的 16 位数分成 4 组,每组 4 位,然后把这四组数分别放在 AL、 BL、 CL和 DL 中。

  • 12、试编写一程序,要求比较两个字符串 STRING1STRING2 所含字符是否完全相同,若相同则显示 MATCH,若不相同则显示 NO MATCH

  • 13、试编写一程序,要求能从键盘接收一个个位数 N ,然后响铃 N 次(响铃的 ASCII 码为 07H )。

  • 14、编写程序,将一个包含有 20 个数据的数组 M 分成两个数组:正数数组 P 和负数数组 N ,并分别把这两个数组中数据的个数显示出来。

  • 15、试编写一个汇编语言程序,求出首地址为 DATA100D 字数组中的最小偶数,并把它存放在 AX 中。

  • 16、把 AX 中存放的 16 位二进制数 K 看作是 8 个二进制的 “四分之一字节”。试编写程序,数一下值为 3 (即 11B)的四分之一字节数,并将该数(即 11B 的个数)在终端上显示出来。

  • 17、试编写一个汇编语言程序,要求从键盘接收一个四位的 16 进制数,并在终端上显示与它等值的二进制数。

  • 18、设有一段英文,其字符变量名为 ENG ,并以 $ 字符结束。试编写一程序,查对单词 SUN 在该文中的出现次数,并以格式 SUN:xxxx 显示出次数。

  • 19、从键盘输入一系列以 $ 为结束符的字符串,然后对其中的非数字字符计数,并显示出计数结果。

  • 20、有一个首地址为 MEM 的 100D 字数组,试编制程序删除数组中所有为 0 的项,并将后续项向前压缩,最后将数组的剩余部分补上 0 。

  • 21、在 STRINGSTRING+99 单元中存放着一个字符串,试编制一个程序测试该字符串中是否存在数字,如有则把 CL 的第 5 位置 1 ,否则将该位置0。

  • 22、在首地址为 TABLE 的数组中按递增次序存放着 100H 个 16 位补码数,试编写一个程序把出现次数最多的数及其出现次数分别存放于 AX 和 CX 中。

  • 23、数据段中已定义了一个有 n 个字数据的数组 M ,试编写一程序求出 M 中绝对值最大的数,把它放在数据段的 M+2n 单元中,并将该数的偏移地址存放在 M+2(n+1) 单元中。

  • 24、在首地址为 DATA 的字数组中存放着 100H 个 16 位补码数,试编写一个程序求出它们的平均值放在 AX 寄存器中;并求出数组中有多少个数小于此平均值,将结果放在 BX 寄存器中。

  • 25、试编制一个程序把 AX 中的 16 进制数转换为 ASCII 码,并将对应的 ASCII 码依次存放到 MEM 数组中的四个字节中。例如,当 (AX)=2A49H 时,程序执行完后, MEM 中的4个字节内容为39H34H41H32H

  • 26、把 0~100D 之间的 30 个数存入以 GRADE 为首地址的 30 字数组中,GRADE+i 表示学号为i+1 的学生的成绩。另一个数组 RANK 为 30 个学生的名次表,其中 RANK+i 的内容是学号为 i+1 的学生的名次。编写一程序,根据 GRADE 中的学生成绩,将学生名次填入 RANK 数组中。(提示:一个学生的名次等于成绩高于这个学生的人数加1。)

  • 27、已知数组 A 包含 15 个互不相等的整数,数组 B 包含 20 个互不相等的整数。试编制一程序把既在 A 中又在 B 中出现的整数存放于数组 C 中。

  • 28、设在 A、B 和 C 单元中分别存放着三个数。若三个数都不是 0,则求出三数之和存放在 D 单元中;若其中有一个数为 0,则把其它两单元也清 0。请编写此程序。

  • 29、试编写一程序,要求比较数组 ARRAY中 的三个 16 位补码数,并根据比较结果在终端上显示如下信息:

  1. 如果三个数都不相等则显示0;
  2. 如果三个数有二个数相等则显示1;
  3. 如果三个数都相等则显示2。
  • 30、从键盘输入一系列字符(以回车符结束),并按字母、数字、及其它字符分类计数,最后显示出这三类的计数结果。

  • 31、已定义了两个整数变量 A 和 B ,试编写程序完成下列功能:

  1. 若两个数中有一个是奇数,则将奇数存入A中,偶数存入B中;
  2. 若两个数中均为奇数,则将两数加1后存回原变量;
  3. 若两个数中均为偶数,则两个变量均不改变。
  • 32、假设已编制好 5 个歌曲程序,它们的段地址和偏移地址存放在数据段的跳跃表 SINGLIST 中。试编制一程序,根据从键盘输入的歌曲编号 1~5,转去执行五个歌曲程序中的某一个。

  • 33、下面的程序段有错吗?若有,请指出错误。

CRAY	PROC
PUSH	AX
ADD	    AX, BX
RET
ENDP	CRAY
  • 34、写一段子程序 SKIPLINES ,完成输出空行的功能。空出的行数在 AX 寄存器中。

  • 35、设有 10 个学生的成绩分别是 76,69,84,90,73,88,99,63,100 和 80 分。试编制一个子程序统计 6069 分,7079 分,8089 分,9099 分和 100 分的人数,分别存放到 S6,S7,S8,S9 和 S10 单元中。

  • 36、编写一个有主程序和子程序结构的程序模块。子程序的参数是一个 N 字节数组的首地址 TABLE,数 N 及字符 CHAR 。要求在 N 字节数组中查找字符 CHAR,并记录该字符出现的次数。主程序则要求从键盘接收一串字符以建立字节数组 TABLE,并逐个显示从键盘输入的每个字符 CHAR以及它在 TABLE 数组中出现的次数。(为简化起见,假设出现次数 ≤ 15,可以用 16 进制形式把它显示出来。)

  • 37、编写一个子程序嵌套结构的程序模块,分别从键盘输入姓名及 8 个字符的电话号码,并以一定的格式显示出来。

    • 主程序 TELIST:
      • 显示提示符 INPUT NAME:;
      • 调用子程序 INPUT_NAME 输入姓名;
      • 显示提示符 INPUT A TELEPHONE NUMBER:;
      • 调用子程序 INPHONE 输入电话号码;
      • 调用子程序 PRINTLINE 显示姓名及电话号码。
    • 子程序 INPUT_NAME
      • 调用键盘输入子程序 GETCHAR ,把输入的姓名存放在 INBUF 缓冲区中;
      • INBUF 中的姓名移入输出行 OUTNAME
    • 子程序 INPHONE:
      • 调用键盘输入子程序 GETCHAR ,把输入的 8 位电话号码存放在 INBUF 缓冲区中;
      • INBUF 中的号码移入输出行 OUTPHONE
    • 子程序 PRINTLINE
      • 显示姓名及电话号码,格式为:
NAME	TEL   
XXX		XXXXXXXX
  • 38、编写子程序嵌套结构的程序,把整数分别用二进制和八进制形式显示出来。
    主程序 BANDO :把整数字变量 VAL1 存入堆栈,并调用子程序 PAIRS ;
    子程序 PAIRS :从堆栈中取出 VAL1;调用二进制显示程序 OUTBIN 显示出与其等效的二进制数;输出 8 个空格;调用八进制显示程序 OUTOCT 显示出与其等效的八进制数;调用输出回车及换行符子程序。

  • 39、假定一个名为 MAINPRO 的程序要调用子程序 SUBPRO,试问:

  1. MAINPRO 中的什么指令告诉汇编程序 SUBPRO 是在外部定义的?
  2. SUBPRO 怎么知道 MAINPRO 要调用它?
  • 40、定义宏指令 FINSUM:比较两个数 X 和 Y (X、Y为数,而不是地址),若 X > Y 则执行 SUM←X+2*Y;否则执行 SUM←2*X+Y

  • 41、把下列C语句的语句改写成功能相同的汇编语言程序片段(其中:变量都为整型变量)。

  k = (k + '1'0xabcd) / 56;
  for (i = s = 0; i < 100; i++) s += data[i]* 2;
  for (s = 0, i = 100; i > 0; i--) s += i *2;
  • 42、把下列C语言的语句改写成等价的汇编语言程序段(不考虑运算过程中的溢出)。其中:变量a、b和c都是有符号的整型(int)变量。
    if (a<1 || b/4 > 10 && c%8==5) {
        a = 20+b++;
        c <<= 2;
    }
    else {
        a = 21-(++c);
        b--;
    }
  • 43、假设内存单元中有三个字 a、b和 c,编写一个程序,它可判断它们能否构成一个三角形,若能,CF 为 1,否则,CF 为 0。

  • 44、假设有二十个无符号字存放在以 Buffer 为开始的缓冲区中,编写一个程序把它们从低到高排序。

  • 45、编写一个程序,它把 CH 和 CL 中的二进制位依次交叉存入 AX 中。

  • 46、编写一个程序,求出从内存单元 1000:0000 开始的 1024 个字的 32 位累加和,并把该值存入程序中的变量 Data 中。

  • 47、用双重循环把下三角乘法表存入从 product 开始的 45 个字节中。

  • 48、表示源程序结束的伪指令是什么?在其后所编写的指令在被汇编吗?

  • 49、汇编语言程序一定会从代码段的第一条指令开始执行吗?如果不是,如何指定程序的入口地址?

  • 50、编写一个程序,它把字符串 String 两端的空格和数字字符删除(字符串以 $ 结束)。

  • 51、编写子程序实现下列功能,参数的传递方式可自行决定(假设所有变量都是字类型)。
    abs(x) = |x|
    f(x) = x^2+ 5x – 8
    strlen(String)

  • 52、为什么要区分IRET指令与RET指令?

  • 53、编写一个控制光标位置和形状的程序,该程序具有以下功能:

    • 可用光标移动键 ↑ 、 ↓ 、 ← 和 → 来移动光标;
    • 当光标已在第 0 列,且按 ← 键时,光标定在上一行的最后一列;若已在屏幕的左上角,则光标不动,且给出响铃;按 → 键时的边界处理类似;
    • 当光标在第 0 行,且按 ↑ 键时,则光标不动,且给出响铃;按 ↓ 键时的边界处理类似;
    • 按 Home 或 End 键,则光标移到当前行的行首或行尾;
    • 若按下数字或字母键,则把该字符从当前位置依次显示到屏幕顶(在新位置显示字符时,原位置的符号被抹去);
    • Esc 键,程序结束。
  • 54、假设显示器的显示模式设定为 12H ,编写实现下列功能的程序:

    • 在屏幕中间从上到下显示一条明亮的蓝色线,线宽为1个像素;
    • 在屏幕底下横向画一条绿色线,线宽为 2 个像素;
    • 在屏幕上垂直显示 16 种颜色,每种颜色宽 40 个像素;
    • 设定屏幕背景为白色,在屏幕中间画一条青色线,线宽为 10 个像素。
  • 55、编写程序,检测计算机是否已安装了鼠标,并以显示Yes/No来表示检测结果。

  • 56、编写程序,显示鼠标的按键,若按左键,显示 Left ,若按右键,显示 Right ,按 Esc 键,程序结束。

  • 57、编写一个程序,在图形模式下,打开鼠标,并显示鼠标的位置。

  • 58、编写一个程序,显示驱动器 C 根目录下所有 EXE 文件(提示:用通配符"*.exe"来查找与此匹配的文件名,找到后,显示之)。

  • 59、编写一个程序,显示驱动器 C 根目录下的所有子目录。

  • 60、编写一个程序,设置指定目录下的所有文件为只读文件。

  • 61、编写一个程序,创建一个隐含文件 Data.TXT

  • 62、编写一个程序,把键盘上输入写入文件 File.dat 中,类似以下 DOS 命令:

COPY con File.dat
  • 63、编写一个宏,它产生 n 条 NOP 指令,其中n是宏的形式参数。

  • 64、编写只有一个形式参数的宏PRINT,其具体功能如下(提示:用 IFB 或 IFNB 语句来测试是否有参数):

  • 若引用时带有参数,则在屏幕上显示其参数字符,如:PRINT 'A',则显示字符 'A';

  • 若引用时不带实参,则显示回车和换行,如:PRINT

  • 65、编写一个在屏幕上连续显示 Welcome… 的信息,要求显示颜色和显示位置都是随机的。在新位置显示时,原位置的信息抹去。当按任意键时,程序结束运行。

  • 66、从键盘输入一个表示年份的正整数(1 ~ 65535),然后判断其是否为闰年。若是,则输出 Yes,否则,输出 No

  • 67、编写一个带命令行参数的程序 Words ,输出指定正文文件中的单词,假设单词为连续的字母串。比如:words file.txt,显示文件 file.txt 中的每个单词

  • 68、编写一个建立双向链表的程序,每接受一个整数,链表增加一个结点,当遇到负数时,结束链表结点的增加,然后从表尾向前输出各结点中的数值。

  • 69、编写一个带命令行参数的程序 Calc ,其命令行参数是一些整数,程序输出它们之和。如果某参数为非法整数,则忽略之。比如:Calc 120 +34 -56,则程序显示 98。

  • 70、在 68 的基础上,在不考虑运算符优先级的情况下,实现一个可进行算术四则运算(只有加、减、乘和除,没有括号等)的计算器。

  • 71、编写一个简单的加密程序,它把一个文件中的所有字母字符按下列规律进行转换,非字母的字符保持不变。转换规律:'A' → 'Z','B' → 'Y',……。

  • 72、编写一个程序,它可显示 BMP 的图形文件。

  • 73、编写一个程序,它可显示 JPG 的图形文件。

  • 74、编写一个程序,求出 2 ~ 100 之内的所有素数。

  • 75、假设从变量 Buff 开始存放了 200 个字,编写一个程序统计出其正数、0和负数个数,并把它们分别存入 N1N2N3 中。

  • 76、给定一个正数 n >= 1 存放在 num 字变量,试编写递归子程序计算 FIB(n),结果保存到 RESULT 变量中。

  • 77、一个学生的信息包括姓名、班级、学号、成绩,其中成绩需要精确到一位小数。是编写程序实现以下功能(提示,应该从上至下规划程序结构,划分各个子程序的功能和调用关系):

    • 可以录入学生成绩(十进制形式)
    • 可以按要求(如学号或成绩)进行排序显示
    • 可以统计平均成绩
    • 可以统计不及格、60 ~ 70、70 ~ 80、 80 ~ 90、 90 ~ 100 各分数段的人数

参与者列表

感谢以下成员对此习题集做出的分享和贡献!

License

All codes in this repository are licensed under the terms you may find in the file named "LICENSE" in this directory.