汇编语言期末复习

汇编语言期末复习
mengnankkzhou题目解答
一 基础知识
1.若CPU的寻址能力是 2^n字节(Byte),那么地址总线宽度为 n 位。
8KB = 2^13byte
所以为13
2.1KB存储器的地址范围, 1KB = 1024个存储单元,地址从0开始编号
所以为0-1023
3.1KB存储器可存储的数据量,1KB = 2^13bit
可存储 2^13 bit
可存储 2^10 Byte
4.常见的转换:::
1KB = 2^10Byte
1MB = 2^20Byte
1GB = 2^30Byte
6.传输1024字节所需次数
若数据总线宽度为 n 位,则每次传输 n/8 字节
所需次数 = 总字节数 ÷ 每次字节数
8086(16位)→ 一次2B → =512 次
80386(32位)→ 一次4B → =256 次
8080:8位 → 1B
8088:8位 → 1B
8086:16位 → 2B
80286:16位 → 2B
80386:32位 → 4B
二 寄存器
1.补充完整:
mov 是赋值指令,不影响标志位。
add 是加法指令,结果存入目标寄存器。
ax 包括 ah(高8位)和 al(低8位)。
指令演示:
| 指令 | 执行后寄存器值 | 说明 |
|---|---|---|
mov ax,62627 |
AX = F4A3H | 62627₁ = F4A3₁₆ |
mov ah,31H |
AX = 31A3H | 修改高 8 位 |
mov al,23H |
AX = 3123H | 修改低 8 位 |
add ax,ax |
AX = 6246H | 3123H + 3123H |
mov bx,826CH |
BX = 826CH | 直接赋值 |
mov cx,ax |
CX = 6246H | AX → CX |
mov ax,bx |
AX = 826CH | BX → AX |
add ax,bx |
AX = 04D8H | 826CH + 826CH = 104D8H → 截断为 04D8H |
mov al,bh |
AX = 0482H | BH → AL(AL = 82H),AH 未变(仍为 04H) |
mov ah,bl |
AX = 6C82H | BL → AH(AH = 6CH) |
add ah,ah |
AX = D882H | AH = 6C + 6C = D8H |
add al,6 |
AX = D888H | AL = 82H + 06H = 88H |
add al,al |
AX = D810H | AL = 88H + 88H = 110H → 截断为 10H |
mov ax,cx |
AX = 6246H | CX → AX |
2.用最多4条指令计算 2⁴
每次 add ax, ax 就是乘以 2,相当于左移 1 位
mov ax,2
add ax,ax ; 2 × 2 = 4
add ax,ax ; 4 × 2 = 8
add ax,ax ; 8 × 2 = 16
3.段地址 0001H 时的寻址范围
实地址 = 段地址 × 16 + 偏移地址
段地址 0001H → 00010H 实起始地址
最大偏移 = FFFFH → 最大地址 = 00010H + FFFFH = 1000FH
所以寻址的范围就是00010H-1000FH
4.要访问实地址 20000H,求段地址 SA 的范围
实地址 = SA × 10H + 偏移
设偏移 = 0 → SA 最小 = 20000H ÷ 10H = 2000H
设偏移最大 = FFFFH → SA 最大 = (20000H - FFFFH) ÷ 10H ≈ 1001H
最小段地址:1001H
最大段地址:2000H
5.
sub ax, ax 用 AX 自己减自己,结果赋给 AX 这样的结果为0
清零首选 xor ax, ax
jmp ax,跳转到 AX 中存储的地址
IP 修改次数:4 次
修改时机:
mov指令加载 → IP++sub指令加载 → IP++jmp指令加载 → IP++jmp执行 → IP ← AX
最后 IP 的值: 0000H
九 跳跃
1.段内转移指令 jmp word ptr [bx+1]
1 | assume cs:code |
jmp word ptr [bx+1] 表示从内存地址 ds:[1] 和 ds:[2] 处读取2字节构成目标偏移地址,CS不变。
要跳到 IP = 0000H,那么 ds:[1~2] = 0000H。
所以只需确保 data 段的第二、三字节是 0。
db 4 dup (0) ; 定义4字节,确保ds:[1]和ds:[2]都是0
2.段间跳跃,jmp dword ptr ds:[0]
1 | data segment |
jmp dword ptr ds:[0] 是段间跳转,执行时:
ds:[0]~[1]→ 被解释为 IP(偏移地址)ds:[2]~[3]→ 被解释为 CS(段地址)
当前指令起始处 IP = 0000H(或 offset start)
当前 CS = cs,跳转目标就是 CS:0
1 | mov [bx], bx ; 相当于 mov [0], 0 |
3.指令 jmp dword ptr es:[1000H],查看内存内容分析跳转结果
2000:1000 BE 00 06 00 00 00 …
1 | mov ax,2000H |
段间跳转,目标是 es:[1000H] 开始的4字节:
低地址两字节(BE 00)→ IP = 00BEH高地址两字节(06 00)→ CS = 0006H
跳转后:CS = 0006H, IP = 00BEH
4.使用 jcxz 查找第一个值为0的字节
1 | code segment |
每次加载一个字节到 CL,然后组成 16 位 CX(CH=0)
如果 CX=0,说明找到了值为0的字节
用 jcxz 检查,找到后跳转到 ok
最终将偏移地址保存在 DX 中
5.使用 loop 查找第一个为0的 byte
1 | code segment |
- loop指令减少 CX 并跳转,直到 CX=0
- 用
cl=[bx]加载内存,若为0,则cx=0,add cx,1变成 1,loop执行后 cx=0,跳出 - 最终偏移值存在
bx中,但已多加一,因此dec bx修正偏移
三
1.内存查看与汇编执行分析(x)
0000:0000 70 80 F0 30 EF 60 30 E2 00 80 80 12 66 20 22 60
0000:0010 62 26 E6 D6 CC 2E 3C 3B AB BA 00 00 26 06 66 88
| 汇编指令 | AX | BX | 说明 |
|---|---|---|---|
mov ax,1 |
0001 | 0000 | AX ← 1 |
mov ds,ax |
0001 | 0000 | DS ← AX,不影响 AX/BX |
mov ax,[0000] |
2662 | 0000 | AX ← DS:0000 = 0x8026(注意是低地址在前) |
mov bx,[0001] |
2662 | E626 | BX ← DS:0001 = 0x26E6(从地址0001开始读两个字节) |
mov ax,bx |
E626 | E626 | AX ← BX |
mov ax,[0000] |
2662 | E626 | AX ← DS:0000 |
mov bx,[0002] |
2662 | D6E6 | BX ← DS:0002 = 0xE6D6 |
add ax,bx |
FD48 | D6E6 | AX = 2662 + D6E6 = FD48 |
add ax,[0004] |
2C14 | D6E6 | AX += DS:0004 = 0x602C → FD48+602C=15D74 → 截断为2C14 |
mov ax,0 |
0000 | D6E6 | 清零 AX |
mov al,[0002] |
00E6 | D6E6 | AL ← E6(AX低字节),AH=0 → AX=00E6 |
mov bx,0 |
00E6 | 0000 | BX 清零 |
mov bl,[000C] |
00E6 | 0026 | BL ← DS:000C = 26H → BX=0026 |
add al,bl |
000C | 0026 | AL=E6+26=10C → 截断为 0C,AX=000C |
2.程序执行追踪 + 汇编流程图(x)
mov ax,6622H
jmp 0ff0:0100H
mov ax,2000H
mov ds,ax
mov ax,[0008]
mov ax,[0002]
| 指令 | AX | BX | CS | IP | DS |
|---|---|---|---|---|---|
mov ax,6622H |
6622 | 0000 | 2000 | 0003 | 1000 |
jmp 0ff0:0100H |
6622 | 0000 | 0FF0 | 0100 | 1000 |
mov ax,2000H |
2000 | 0000 | 0FF0 | 0103 | 1000 |
mov ds,ax |
2000 | 0000 | 0FF0 | 0105 | 2000 |
mov ax,[0008] |
C189 | 0000 | 0FF0 | 0108 | 2000 |
mov ax,[0002] |
EA66 | 0000 | 0FF0 | 010B | 2000 |
3.逆序拷贝程序(使用栈)
将 10000H~1000FH 的 8 个字(16 字节)将 10000H~1000FH 中的 8 个字逆序拷贝到 20000H~2000FH 中。
1 | mov ax,1000H |
栈是从高地址向低地址存储,push 后栈内容为 [0EH], [0CH], ..., [0]
注意 [0] 等都是 ds 段内偏移地址
出栈写入(pop)将 10000H~1000FH 中的 8 个字逆序拷贝到 20000H~2000FH 中。
1 | mov ax,2000H |
DS(Data Segment,数据段寄存器)
指向当前程序使用的数据段基地址,用于访问数据。
SS(Stack Segment,栈段寄存器)
指向当前栈所在的段基地址。
SP(Stack Pointer,栈指针寄存器)
指示当前栈顶(栈顶指针)的偏移地址,结合 SS 寄存器,确定栈顶的线性地址。
1 | mov ax,1000H |
说明数据段 DS 指向段地址 1000H,即内存中以 10000H 为起始的地址区域。
SP 是栈顶偏移量,相对于 SS 指定的段地址。
十
1.利用 retf 实现远跳转
1 | assume cs:code |
1 | mov ax,1000h ; 目标段地址 |
从当前程序跳转到 1000:0000 开始执行。
2.call 段内过程 的本质
1 | 1000:0000 b8 00 00 mov ax,0 |
1 | mov ax,0 |
call s 将返回地址 1000:06 压入栈
pop ax弹出该地址,ax=6
3.机械码
1 | 1000:0000 b8 00 00 mov ax,0 |
执行后,ax的值为多少?
pop ax → ax = 0008h(返回地址)
add ax, ax → ax = 0x10
pop bx → bx = 1000h(段)
add ax, bx → ax = 0x10 + 0x1000 = 0x1010
4.call ax(寄存器间接调用)
1 | 1000:0000 b8 06 00 mov ax,6 |
call ax 相当于 call 0006h,先把返回地址 1000:05 压栈
到 1000:06,执行 pop ax → ax = 0005
5.间接调用 call word ptr ds:[0eh]
1 | call word ptr ds:[0eh] |
已知 [ds:0eh] = 0011h,call跳转到0011h后执行 inc ax 三次
1 | assume cs:code |
- 栈段
stack定义了 8 个 word 空间,共 16 字节(从 0 到 15)。 - 初始化:
ss = stack,sp = 16,即栈顶从偏移0010h开始。 ds = ax = stackcall word ptr ds:[0eh]
查找ds:0eh处的内容,即偏移地址(设为 0011h)
因为 call 是段内调用,所以:
执行
call 0011h:call会将 返回地址 (call 下一条指令地址) = 0011h 压入栈- IP ← 0011h
IP 跳转到 offset=0011h 的位置,接着执行:
1
2
3inc ax
inc ax
inc ax初始 ax = 0 → 1 → 2 → 3
1 | assume cs:codesg |
ss:[0] = 1Ah,即跳转到当前段偏移地址 1Ahss:[2] = cs,即段地址call dword ptr ss:[0]→ 跳转到 cs:1Ah- call 指令将 返回地址 IP=19h 和 CS=cs 入栈:
ss:[4] = csss:[6] = 0019h
进入 s: 标签后:
1 | mov ax, offset s ; ax = 1Ah |
1 | ax = 1 |
十一
写出每条指令执行后,标志位的值:
| 指令 | CF | OF | SF | ZF | PF |
|---|---|---|---|---|---|
sub al, al |
0 | 0 | 0 | 1 | 1 |
mov al,10H |
— | — | 0 | 0 | 1 |
add al,90H |
0 | 0 | 1 | 0 | 1 |
mov al,80H |
— | — | 1 | 0 | 1 |
add al,80H |
1 | 1 | 0 | 1 | 1 |
mov al,0FCH |
— | — | 1 | 0 | 1 |
add al,05H |
1 | 0 | 0 | 0 | 0 |
mov al,7DH |
— | — | 0 | 0 | 0 |
add al,0BH |
0 | 1 | 1 | 0 | 1 |
知识框架
简答题
1.对汇编语言的理解
概念:面向机器的低级语言,使用符号化指令(助记符)
优点:
- 执行效率高(直接操作寄存器/内存)
- 控制力强(可精细操控硬件)
- 有助于理解计算机体系结构
缺点:
- 语法繁琐、代码量大
- 可读性差、维护难度高
- 不可移植,依赖具体 CPU 架构
2.寄存器体系及其使用
| 标志位 | 含义 | 触发条件示例 |
|---|---|---|
| ZF | Zero Flag,零标志 | 运算结果为0时置位1 |
| SF | Sign Flag,符号标志 | 运算结果最高位为1时置位1 |
| CF | Carry Flag,进位/借位标志 | 无符号加法产生进位或减法借位时置1 |
| OF | Overflow Flag,溢出标志 | 有符号运算超出范围时置1 |
| PF | Parity Flag,奇偶标志(低8位偶数个1) | 结果低8位中1的个数为偶数时置1 |
1 | sub al,al → ZF=1, PF=1, SF=0 |
3.程序加载与段:偏移机制
段地址(Segment Address):指内存中一个64KB段的起始地址,由段寄存器(如 CS、DS、SS、ES)给出。
偏移地址(Offset Address):表示该段内的相对地址位置,通常由 IP、BX、SI、DI 等寄存器提供。
物理地址计算公式:
1 | 编辑物理地址 = 段地址 × 16 + 偏移地址 |
4.条件与无条件跳转
jmp/ je/ jne/ jg… 指令格式
近跳转 vs 远跳转 vs 间接跳转
跳转目标:立即数、寄存器、内存
jmp 指令:
jmp 段内跳转:只修改 IP,CS 不变。jmp 段间跳转:同时修改 CS 和 IP
call 指令:
实现子程序调用,会将返回地址入栈,然后跳转到目标地址。
- 近调用(段内):只入栈 IP
- 远调用(段间):先入栈 CS,再入栈 IP
调用完成后跳转到子程序开始位置执行。
ret / retf 指令:
ret:弹出栈顶内容(IP)并跳回(适用于近调用);
retf:弹出两个字节恢复 IP,然后再弹出两个字节恢复 CS,实现段间返回。
5.基本结构
汇编程序的基本结构:由代码段(存放指令)、数据段(存放数据)、栈段(管理栈空间)组成,程序入口标签(如 start:)指明执行起点,end 标记程序结束
段寄存器的作用及设置:CS 指向代码段,DS 指向数据段,SS 指向栈段。设置时先用 mov ax, 段地址,再用 mov 段寄存器, ax 装载段地址。
汇编程序的执行流程:CPU 从 CS:IP 指向位置开始执行指令,执行后 IP 自动加指令长度,跳转指令可修改 CS 和 IP 以改变执行流。
内存访问方式:内存地址由段寄存器和偏移地址组合计算,数据访问用 DS,代码访问用 CS,栈操作用 SS。
汇编指令的基本作用:mov 指令实现数据在寄存器和内存间传送,段寄存器初始化通过先装载到通用寄存器再转移。
6.DOS 如何加载 EXE 可执行程序?
DOS 从内存中找到一块空闲区域,段地址为 SA,偏移为 0000。
在 SA:0 开始的 256 字节内创建 PSP(程序段前缀),用于 DOS 和程序通信。
程序本体加载到 SA+10H:0 处,即从 256 字节后开始执行。
PSP 和程序在物理地址上连续,但逻辑段地址不同。
最后设置 DS=SA,CS:IP=SA+10H:0,准备开始执行程序。
填空题
1.栈操作细节,push/ pop 对 SP、SS 的影响
2.转移指令格式,机器码长度、操作数类型
3.子程序调用,call/ ret 的入栈、出栈顺序
4.标志寄存器,ZF、SF、CF、OF 置位条件,哪些算术/逻辑指令影响哪些标志
程序分析题
1.loop 循环 & CX 计数寄存器变化,loop label 的执行流程——取指、CX–1、ZF检查、跳转,执行次数与初始 CX 的关系
2.子程序/间接跳转跟踪,
call/ jmp reg/ ret 全流程:
- IP 入栈
- CS:IP 更新
- 返回地址弹栈
3.复制程序
1 | assume cs:code |
将 DS:0000(0020:0000)开始的 10 个字节 拷贝到 ES:0000(0021:0000)开始的地址。
mov al, [bx] 表示:从 DS:BX 指向的内存地址中读取一个字节到 AL(间接寻址)
mov es:[bx], al 表示:将 AL 的值存入 ES:BX 指向的内存地址
loop s = dec cx; if cx != 0 then jmp s,循环控制语句,用于固定次数循环
mov ds, ax 和 mov es, ax 是设置数据段和额外段,访问内存前必须设置段寄存器
编程题目
- 基于
loop的计数/求和程序(第5章)
段:偏移 数据搬运 + 栈管理(第6章)
如:从数据段读字符串,压栈→子程序处理→弹栈
1 | assume cs:codesg |
数据从0:0 ~ 0:F(16 字节,8 个字)依次读取,覆盖 CS 段中的初始数据区
原始数据如 0123H,0456H... 将被替换为内存中读取的新数据
效果:程序数据区被外部数据动态更新
1 | assume cs:codesg |
使用 stack 完成数据搬运,相当于:
ax ← ds:[bx] → push → 栈 → pop → cs:[bx]
使用 push/pop 方式达到 数据传送效果
栈顶设为 24h(即 36 十进制)→ 从 cs:0024h 处开始使用栈
栈段的起始位置由 ss = cs 指定,即栈放在当前代码段末尾的空区域
大小写转换(第7章)
- 利用
AL/AH与 ASCII 区别 - 不同寻址方式:立即、直接、寄存器间接
- 利用
将 datasg 段中每个字符串的前 4 个字母转换为大写字母。
1 | assume cs:codesg, ds:datasg, ss:stacksg |
每条字符串偏移分别是:3、13、21、31(跳过编号和点空格)。
upper4 子程序:处理从 [bx] 开始的 4 个字符。
利用了 cmp 和 sub 判断是否是小写字母。
字符串操作指令综合(第8章)
MOVS/LODS/STOS/CMPS/SCAS实现功能
编写程序,将 data 段中:
- 21个年份(每个4字节字符串)
- 21个年收入(每个4字节 dword)
- 21个雇员数(每个2字节 word)
分别搬运进 table 段中(每行16字节),并计算人均收入(dword / word → word,单位:千美元)。
1 | assume cs:codesg, ds:dataseg, es:tablesg |






