80x86汇编编程-1(续)

官方信息技术老师·13 页·深入(追求细节与边界)·0 次浏览·3 天前
80x86汇编寄存器寻址

80x86汇编编程-1(续)

看清寄存器、寻址方式与段机制如何协同,掌握实模式地址拼接的边界

按 空格/→ 演示下一步

1 / 13 页

全部页面点击任意一页,跳回舞台从这页播放

80x86汇编寄存器寻址

80x86汇编编程-1(续)

看清寄存器、寻址方式与段机制如何协同,掌握实模式地址拼接的边界

1第 1 页 · 80x86汇编编程-1(续)

汇编编程示例-递归调用

求 n! 时数学上拆成 n × (n-1)!,这叫递归。C 里 factorial(n-1) 是「自己调自己」,汇编里没这魔法——靠 call 反复压栈,每层独立栈帧。

递归的汇编本质
自己调自己就是 call 指令反复压栈,每层都有独立栈帧
栈帧管理
push ebp / mov ebp,esp 开栈;leave / ret 退栈复原
参数与返回值
参数从右往左压栈,[ebp+8] 取首参;返回值走 EAX
必须设终止条件
靠 cmp / je 实现递归出口,否则无限递归撑爆栈空间
俄罗斯套娃拆装对应 →递归调用栈帧

每次「自己调自己」就是拆开套娃再装回去;最里层就是终止条件

2第 2 页 · 汇编编程示例-递归调用

汇编编程示例-文件处理-1

递归操作的是内存里的数据,程序一关就消失。文件操作解决「持久化」——汇编靠 DOS 中断 INT 21h 完成这整套服务。

INT 21h 中断
DOS 提供的文件服务总入口,AH 寄存器放功能号选中具体操作
文件句柄
打开或创建文件后 DOS 返回的「编号凭据」,后续读写都要用它指认文件
五大核心功能号
3Ch 建文件、3Dh 打开、3Fh 读取、40h 写入、3Eh 关闭
文件指针
读写当前位置,默认从文件头开始;功能 42h 可移动指针到任意位置
图书馆借阅流程对应 →汇编文件操作

句柄=借书证,INT 21h=服务台,读写=翻页抄录,关闭=还书销证

3第 3 页 · 汇编编程示例-文件处理-1

汇编编程示例-文件处理-2

上一页用 INT 21h 完成了打开、顺序读写、关闭文件。但实际中常常要「跳到指定位置再读」、改文件属性,或者删除、重命名——这些进阶操作才是文件处理-2 的目标。

文件指针移动 seek
INT 21h AH=42h,移动读写指针到任意字节偏移,实现随机访问
文件属性操作
INT 21h AH=43h,读取或设置只读、隐藏、系统、归档等属性位
删除与重命名
AH=41h 删除文件(不可恢复);AH=56h 改名或跨目录移动
书中的书签对应 →文件指针移动

书签插在哪,下次就从哪里继续;不必像顺序读那样从头一页一页翻

4第 4 页 · 汇编编程示例-文件处理-2

汇编编程示例-文件处理-3

前两页的3Fh/40h只能顺序读写——要拿到第100条记录,难道要把前面99条全读完再跳过?本页用文件指针实现随机定位。

顺序访问的代价
每次都从当前位置往后读,要跳到远端就得逐字节推进
文件指针概念
系统为每个打开的文件维护一个读写位置计数器
移动指针的系统调用
INT 21h AH=42h,按字节偏移直接重定位指针
起始位置三选一
AL=0 从文件头、AL=1 从当前位置、AL=2 从文件尾
偏移量在 DX:AX
高 16 位放 DX,低 16 位放 AX,组合成 32 位偏移
翻书找某一页对应 →文件指针随机定位

翻书直接跳到第N页≠一页一页翻;AL=0从封面开始数,AL=2从封底倒数

偏移量=DX×216+AX\text{偏移量} = DX \times 2^{16} + AX
5第 5 页 · 汇编编程示例-文件处理-3

汇编编程示例-文件处理-4

前面学过用 INT 21h 打开、读写、关闭文件。但读大文件时每次都从开头顺序扫描太慢——这一页要掌握文件指针的移动,实现随机访问。

文件指针
相当于阅读时夹的书签,标记下一次读写的起始位置
随机访问
直接跳到文件中任意位置读写,免去顺序扫描
移动指针
调用 INT 21h 功能号 42h 改变读写位置
三种定位
相对文件头、当前位置、文件尾做偏移
翻书查某段内容对应 →文件随机访问

书签=文件指针;翻到指定页=按偏移定位,三种翻法对应三种基准

6第 6 页 · 汇编编程示例-文件处理-4

Vid汇编编程示例-文件处理

前几页都是从文件头顺序读——但若只想拿文件中第1000字节的数据,难道要把前面999字节全读一遍再丢掉吗?显然有更聪明的办法。

文件指针
系统为每个打开的文件维护的「当前读写位置」标记
移动指针
调用 int 21h 的 42h 号功能把指针跳到任意位置
三种基准
相对文件头、当前位置、文件尾来计算偏移量
随机访问
先 seek 再 read/write,可直接读写文件中任意位置
看书翻到指定页对应 →文件指针定位(seek)

书签标记当前位置,seek 就是移动书签到新位置

7第 7 页 · Vid汇编编程示例-文件处理

汇编编程示例-文件处理-6

前几页处理文件都是从头到尾顺序读写,像听磁带走带。但查数据库、修改文件中间某段、日志回查某行——这些场景需要直接跳到指定位置。这就是随机文件访问。

文件指针
当前读写位置的标记,每次读写后自动后移
指针定位
主动把指针移到文件任意字节位置
定长记录
每条数据字节数相同,可用「序号×长度」算出偏移
典型应用
数据库索引、文件局部修改、日志回查
翻书跳到指定页对应 →随机文件访问

书签定位不用从第一页翻起,指针定位也不用从头读

8第 8 页 · 汇编编程示例-文件处理-6

汇编编程示例-文件处理-7

想象你和同事同时改同一份表格——谁先保存,后保存的就覆盖前一个人的内容。汇编里多个程序访问同一个文件,也会撞上同样的麻烦。

共享模式
DOS 提供 4 种拒绝级别,从完全独占到完全开放
访问模式
以读/写/读写哪种身份打开,读模式写文件会破坏结构
冲突类型
写写冲突最危险,后写覆盖先写的内容,DOS 不报错
锁机制
用打开时的 deny 模式提前拒绝冲突,而非事后补救
文档协作权限对应 →文件共享模式

「只读」= 读模式打开,「禁止编辑」= deny write 模式

9第 9 页 · 汇编编程示例-文件处理-7

汇编编程示例-文件处理-8

上节顺序读文件像从头翻书看小说,但若要直接打开第 500 章,从头翻就不现实。本节讲文件随机访问——把『书签』直接夹到目标位置。

顺序访问的瓶颈
必须从头逐字节读才能到达目标位置,大文件跳转时开销巨大
文件指针
操作系统为每个打开文件维护的读写位置,每读/写后自动后移
Seek 操作
DOS INT 21h AH=42h,移动指针到任意偏移,支持绝对/相对/末尾三种模式
典型应用
数据库索引定位、配置文件分块读写、日志随机回放
书页书签对应 →文件指针

书签停在当前页,翻书后书签跟着走;Seek 就是把书签强行夹到任意页

10第 10 页 · 汇编编程示例-文件处理-8

汇编编程示例-共享库文件

文件处理函数如果每次都写进每个程序,磁盘和内存都吃不消。多个程序想共用同一份 printf 怎么办?这就是共享库要解决的问题。

共享库本质
运行时由动态链接器装入内存,多个进程共用同一份代码
位置无关代码
用相对寻址,代码可被加载到任意内存地址运行
GOT与PLT
GOT存外部符号地址,PLT处理函数调用跳转
动态链接优势
节省内存和磁盘、库升级免重编、可运行时按需加载
公共图书馆借书对应 →共享库

多个程序像读者共用一本书,而非每人复印一份

11第 11 页 · 汇编编程示例-共享库文件

本节要点

  • 递归靠栈帧隔离,EBP/RBP锚定参数与局部变量
  • 文件处理本质是缓冲管理+系统调用约定
  • 共享库要求位置无关代码,GOT/PLT做间接寻址
  • 栈帧不平衡、句柄未关是最常见的崩溃源
延伸主题:中断与异常处理机制内存分页与虚拟地址线程同步原语
12第 12 页 · 本节要点

课后思考

先独立想,再对照参考答案。三题对应三个层次,由浅入深。

1为什么文件处理中调用系统服务后通常要保存/恢复寄存器?文件描述符对应内核中的什么数据结构?

参考答案系统调用不保证保留 EAX/ECX/EDX 等寄存器,所以调用方必须保存现场。文件描述符本质是进程文件描述符表中的索引,关闭后会被复用。

2若用汇编写一个处理大于 2GB 日志文件的工具,lseek 会遇到哪些边界问题?为什么?

参考答案lseek 的偏移是 32 位有符号整数,2GB+ 需分多次 seek 拼接或用 64 位扩展调用;同时要注意 SEEK_SET/SEEK_CUR/SEEK_END 三种模式的语义差别。

3把手写汇编函数做成共享库供 C 调用时,调用约定不匹配会导致什么后果?为什么?

参考答案若汇编用寄存器传参,C 从栈上读到的是垃圾值;若汇编按 stdcall 自己清栈而 C 仍按 cdecl 再清,栈会不平衡甚至崩溃。ABI 是两者必须签的'合同'。

13第 13 页 · 课后思考