![]() |
中国DOS联盟-- 联合DOS 推动DOS 发展DOS --联盟域名:www.cn-dos.net 论坛域名:www.cn-dos.net/forum |
| 游客 | 登录 | 注册 | 会员 | 搜索 | 中国DOS联盟 |
|
中国DOS联盟论坛 现在时间是 2026-08-07 16:19 |
共 48,041 主题排行 / 350,128 发帖 / 今日 3 篇 / 48,252 会员排行 |
| 网络日志(Blog) » 【Redtek】 个人网志(学习笔记) |
| 可打印版本 29,503 / 130 |
| 第46楼 redtek | 发表于 2006-12-20 01:12 |
| 金牌会员 发帖 1,147 积分 2,902 | |
|
【80x86汇编语言学习笔记】 根据测试,当调用了16位DOS程序以后,CMD 便被切换到了英文(美国)代码页:437,中文便无法显示了。
所以在代码中调用 Debug 来达到间接运行汇编代码功能后,当 Debug 退出后就进入了437代码页,给需要显示中文批处理带来麻烦。 如何既运行 16位 DOS 程序(如:Debug、Edit.com……等)还能正常显示中文呢? 解决办法如下: 这样,再运行16位程序以及调用Debug完成特殊任务时,CMD窗口视觉上的大小不变、且正常显示中文。 (此刻不可以再输入中文了-CMD 输入法无效) [ Last edited by redtek on 2006-12-19 at 12:22 PM ] 附件 2.GIF (10.17 KiB) |
|
| 第47楼 redtek | 发表于 2006-12-21 03:21 |
| 金牌会员 发帖 1,147 积分 2,902 | |
|
【80x86汇编语言学习笔记】 ) 这几天汇编语言学习总结:
学习汇编之前: 先学 Debug 基本使用等知识,可节省 70% 的入门时间。 否则,学习的陡峭曲线非常高,如再遇到一本破书又无师指导,很难坚持下去并自学入门。 开始学习汇编: 只学用得到的指令,用到再学,学的时候再找,会越学越深。 对汇编书或资料的选择: 选择错了书如是自学,等同于拜了小人为师,不仅付出10倍努力且还不得旨领。 往往这个时候就知难而退,有多少想学习汇编的人从此又放弃了。 什么汇编的书是好书? 一般的教学书均是归纳、总结、分类的次序书写,这种书不适书入门,适合学术。 要选择循序渐进的书做入门的书,往往一个概念得不到非常简明的解释,很可能又偏入岐途。 先有简单一个例子,或是按照从简到深的能力一点点推进的书,是好书。 没有 Debug 例子只有完全的理论的书是坏书。 要讲到事物本质的书是好书: 如:CPU是怎么执行指令的? 为什么段地址*16+偏移量……为什么要乘16?要它所有推出来的步骤…99%的书都没有。 高电平与低电平是如何代表指令的? 一个读内存单元的动作CPU与地址总线、数据总线、控置总线是如何配合工作的? 计算机中所有的设备(外设等)到底是怎么样的布局?如何工作的?(很多书都略掉了……) 这些本质上的东西如果略掉,只留下指令应该怎么写,又不给出本质,那么学也白学。 指令都是次要的,本质原理是最重要的。 如果完全自学,没有学校教、没有老师教,没有论坛可以请教,只有一台计算机、一些书,那么完全自学汇编的唯一要求 就是这本书要非常好,要讲本质并讲透,不断的想、编…… 否则数十倍的努力去看那些破书并耗掉上百个小时,也不如好书里的一句话讲透了本质受用你一生的指点。 ) 如何学好汇编? 刚学几天,不知道。 唯一感触非常多的就是,学的过程基础知识不能跳,表面上跳过去了后面也能看一部分,但到头来一定白学,还要回来。 这点我是真的感触到了,并且回过头来再重看、重学的时候对汇编的兴趣会丢掉一半…… ) 以上个人学习汇编几天的总结,权当瞎说~:) |
|
| 第48楼 redtek | 发表于 2006-12-21 03:52 |
| 金牌会员 发帖 1,147 积分 2,902 | |
|
【80x86汇编语言学习笔记】 从现在开始如果汇编基础知识不过关,就不再往后学。直到所有测试全部通过并理解以后再向后学习。
) 汇编语言基础知识测试 1、1个CPU的寻址能力为8KB,它的地址总线宽度为? 答: 8KB的寻址能力范围是: 0 ~~ 8191 B n个二进制位的寻址能力的宽度是 2的n次方,所以 2的x次方=8192KB。 求得cpu的寻址能力为8kb,它地址总线宽度为 13。 即 2的13次方为 8192B(8192/1024=8KB) 2、1KB的存储器有多少个存储单元?存储单元的编号从多少到多少? 答:1KB的存储器有 1024 个存储单元,一个存储单元可存 8 个 bit,就是8个二进制位。 存储单元的编号是从0起始的,所以是 0 ~~ 1023。 3、1KB的存储器可以存储多少个bit,多少个byte? 答:1kb=1024B,可存 (1024B*8bit) 8192bit。 还可以存 1024 个 Byte。 4、1GB、1MB、1KB分别是多少 byte ? 答:1GB =(1024b * 1024KB)mb * 1024mb = 1073741824 Byte 1MB = 1048576 Byte 1KB = 1024 Byte 5、8080、8088、80286、80386地址总线宽度分别为16、20、24、32根,它们寻址能力为_KB、_MB、_MB、_GB。 答:8080 为:64KB 8088 为:1MB 80286 为:16MB 80386 为:4GB 6、8080 8088 8086 80286 80386的数据总线宽度为8 8 16 16 32根,则它们一次可以传送的数据分别为多少B? 答:8080 为:256B 8088 为:256B 8086 为:65536B 80286 为:65536B 80386 为:4294967296B 7、从内存中读取1024字节的数据,8086至少要读多少次?80386至少要读多少次? 答:8086 CPU数据总线宽度是 8,即每次只能传递 8 bit 数据。1024字节需要读1024次。 80386 CPU数据总线宽度是32,每次传递 32 bit 数据,1024字节需要读256次。 8、在存储器中,数据和程序以什么形式存放? 答:数据和程序以二进制形式存放~:) [ Last edited by redtek on 2006-12-20 at 03:42 PM ] |
|
| 第49楼 redtek | 发表于 2006-12-21 05:04 |
| 金牌会员 发帖 1,147 积分 2,902 | |
|
【80x86汇编语言学习笔记】 寄存器汇编指令练习:
[ Last edited by redtek on 2006-12-20 at 04:06 PM ] |
|
| 第50楼 redtek | 发表于 2006-12-21 05:20 |
| 金牌会员 发帖 1,147 积分 2,902 | |
|
【80x86汇编语言学习笔记】 程序段中指令执行练习:
最后当执行 ADD AX,BX后,发生“溢出”,16位寄存器只能存放4位16进制数据。 试验2:
以上学习完了简单的加指令:ADD 测试: 只能使用学过的(MOV、ADD)这两条汇编指令,最多使用4条指令,编程计算2的4次方。 结果10H(10进制的 16)。 [ Last edited by redtek on 2006-12-20 at 06:12 PM ] |
|
| 第51楼 redtek | 发表于 2006-12-21 07:39 |
| 金牌会员 发帖 1,147 积分 2,902 | |
|
【80x86汇编语言学习笔记】 ( 16位CPU结构与物理地址计算 )
CPU结构特性: 运算器一次最多可以处理16位的数据; 寄存器的最大宽度为16位; 寄存器和运算器之间的通路为16位。 8086CPU有20位地址总线,可能传送20位地址,达到1MB的寻址能力。 8086CPU又是16位结构,在内部一次性处理、传输、暂时存储的地址为16位。 从8086CPU的内部结构来看,如果将地址从内部简单地发出,那么它只能送出16位的地址,表现出的寻址能力只有64KB。 8086CPU采用一种在内部用两个16位地址合成的方法来形成一个20位的物理地址。 在 8086PC机中,存储单元的地址用两个元素来描述:段地址和偏移地址。 可根据需要,将地址连续、起始地址为16的倍数的一组内存单元定义为一个段。 形容一个地址的标准讲法~:) (1) 数据存在内存 2000:1F60 单元中; (2) 数据存在内存的 2000 段中的 1F60 单元中。 检测练习: 1、给定段地址为 0001H,公通过变化偏移地址寻址,CPU的寻址范围从哪里到哪里? 答: 0001H * 16 = 10H (段) 偏移量为16位,寻址范围为:0 ~~ FFFFH 段地址 * 16 + 偏移地址=物理地址 所以,CPU的物理寻址范围是: 10H ~~ 10FFFFH 2、有一数据存放在内存 20000H 单元中,现给定段地址为 SA,若想用偏移地址寻到此单元。SA应满足的条件是: 最小为?最大为? 答:范围取值过程: -------------------------------------- 1001H * 16 + FFF0H = 20000H …… …… 1FFEH * 16 + 20H = 20000H 1FFFH * 16 + 10H = 20000H 2000H * 16 + 0H = 20000H -------------------------------------- 根据以上同理,已知:1000H * 16 + 10000H = 20000H 会发生16位溢出 推出计算公式如下: ( 20000H - FFFFH ) / 16 + 1H = 为 SA 段地址最小取值 所以,SA 最小取值为: 1FFEH SA 最大取值为: 2000H 偏移量最小取值为: 0H 偏移量最大取值为:FFF0H 偏移量每次递增为: 10H 本想这道题不做了,昨天是绕进去了~:) 今天早上做的时候发现这道题得做,虽然做完了觉得简单。 做的过程中……一会儿16进制、一会儿又是10进制,来回来去的算…… 当做完以后,发现了很多细节以及运算上以前没有注意到的地方。 深感基础必须扎实!基础越是扎实,后面的路就走得越远~:) 查看内存中的内容 根据资料给出:PC机主板上的ROM中写有一个生产日期,在内存 FFF00H~~FFFFFH 的某几个单元中, 请找到这个生产日期并试图改变它。 根据上面的计算原理,将物理内存地址“拆”成 段地址:偏移量 所表示的地址,使用Debug操作如下:
[ Last edited by redtek on 2006-12-21 at 03:14 PM ] |
|
| 第52楼 redtek | 发表于 2006-12-22 04:40 |
| 金牌会员 发帖 1,147 积分 2,902 | |
|
【80x86汇编语言学习笔记】 寄存器与内存访问
存放一个字型数据(16位)的内存单元,由两个地址连续的内存单元组成。 高地址内存单元中存放字型数据的高位字节,低地址内存单元中存放字型数据的低位字节。 任何两个地址连续的内存单元,N号单元和N+1号单元,可以将它们看成两个内存单元, 也可以看成一个地址为N的字单元中的高位字节单元和低位字节单元。 DS,通常用来存放要访问数据的段的地址。 例如:要读取 10000H 单元的内容,可以用如下的程序段进行: 上面是读物理地址 10000H 单元内容,按 “段地址:偏移量” 来访问就是 1000:0000 因为其物理地址的计算为: 1000H*16+0000=10000H ,这个计算由CPU交给加法器来完成。 8086CPU不支持将数据直接送入段寄存器的操作(如: MOV DS,1000),这是非法指令。 所以只能按上面代码的间接用寄存器来进行中转操作。 测试:将 AL 中的数据送入内存单元 10000H 以上是字节型数据的传送。 字的传送 8086CPU是16位结构,有16根数据线,一次性可以传送16位的数据。 也就是说,可以一次性传送一个字。只要在 mov 指令中给出 16位的寄存器就可以进行16 位数据的传送了。 以下是字的传送练习与内存分析: 寄存器与段间数据传送 “MOV 段寄存器,内存单元” 数据传送分析
[ Last edited by redtek on 2006-12-21 at 09:33 PM ] |
|
| 第53楼 redtek | 发表于 2006-12-22 10:58 |
| 金牌会员 发帖 1,147 积分 2,902 | |
|
【80x86汇编语言学习笔记】 物理地址 = 段地址*16 + 偏移量
根据上面原理灵活运用计算物理地址的方法,来用不同的段地址与偏移量取“同”一数据:
[ Last edited by redtek on 2006-12-21 at 10:01 PM ] |
|
| 第54楼 redtek | 发表于 2006-12-22 23:34 |
| 金牌会员 发帖 1,147 积分 2,902 | |
|
【80x86汇编语言学习笔记】 栈
push ax 的执行由下面两步完成: 1、SP=SP-2,SS:SP指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶; 2、将ax中的内容送入 SS:SP 指向的内存单元处,SS:SP 此时指向新栈顶。 两个寄存器: 段寄存器 SS 和 寄存器 SP,栈顶的段地址存放在 SS 中,偏移地址存放在 SP 中。 任意时刻, SS:SP 指向栈顶元素。 push 和 pop 指令对栈的操作以及为栈设置空间
编程:(1)将 10000H ~~ 1000FH 这段空间当作栈,初始状态栈是空的; (2)设置 AX=001AH,BX=001BH; (3)将 AX、BX中的数据入栈; (4)然后将AX、BX清零; (5)从栈中恢复AX、BX原来的内容。
上面标注绿色的指令是清零指命,利用 XOR 的性质清零,速度快于 MOV AX,0000 …… MOV AX,0 也可以清零,但其机器码占用了3个字节,如果想让编译出来的程序节省一个字节,则不用这个命令。 经过分析,可以看到下面红色的部分为机器码,占用了3个字节。(能省一个字节就省)
再看一下SUB (减)指令: SUB AX,AX 也可以让AX寄存器清零。 下面是 SUB 操作,红色部分是SUB的机器码:
再试验一下 XOR (或)指令: XOR AX,AX 将 AX 寄存器内容清零
上面的清零的机器码只占用了2个字节。 一段内存,可以既是代码的存储空间,又是数据的存储空间,还可以是栈空间,也可以什么都不是。 关键在于CPU中寄存器的设置,即: CS IP SS SP DS 的指向。 如果寄存器知识没有学好,很可能往下学习就是寸步难行~:) [ Last edited by redtek on 2006-12-22 at 04:40 PM ] |
|
| 第55楼 redtek | 发表于 2006-12-23 06:46 |
| 金牌会员 发帖 1,147 积分 2,902 | |
|
现在开始学着写第一个程序~:)
坚持着学就学下来了,越学越难,越难越学。如果没有坚持下来,等于浪费生命~:) 想想阿香婆是怎么熬辣酱的,哈哈…… 从刚学到现在,按书上的深度来讲,连入门都没有到~:) 不管,接着往前走~:) |
|
| 第56楼 redtek | 发表于 2006-12-23 08:08 |
| 金牌会员 发帖 1,147 积分 2,902 | |
|
【80x86汇编语言学习笔记】 汇编语言程序从写出到最终执行的过程
1) 编写汇编源程序 2) 对源程序进行编译连接 3) 执行 在汇编语言源程序中,包含两种指令: 汇编指令,伪指令。 写第一个代码
编译过程:(Masm 5.0)
可执行文件:
跟踪刚才编译的 1.exe 可执行文件过程:
头晕,PSP…… 操作系统的外壳…… 程序是如何执行的? 1) 在DOS中直接执行 1.exe 时,是正在运行的 command ,将 1.exe 中的程序加载入内存; 2) command 设置 CPU 的 CS:IP 指向程序的第一条指令(即程序的入口),从而使程序得以运行; 3) 程序运行结束后,返回到 command 中, CPU 继续运行 command。 可执行程序被加载的过程: 1) 找到一段起始地址 SA:0000 的容量足够的空闲内存; 2) 在这段内存区的前 256 个字节中,创建一个称为程序段前缀(PSP)的数据区,DOS要利用PSP来和被加载程序进行通信; ---------内存--------- //////// //////// sa: ------------------------ PSP ------------------------ SA + 10H:0 CS:IP 程 序 ------------------------ 3) 从这段内存区的 256 字节处开始(在PSP的后面),将程序装入。 程序的地址被设为 SA + 10H : 0 ; 空闲的内存区从 SA:0 开始, 0~~255 字节为 PSP,从 256 字节处开始存放程序。 为更好地区分 PSP 和程序,DOS一般将它们划分到不同的段中,所以有这样的地址安排: 空闲内存区: SA : 0 PSP区: SA : 0 程序区: SA + 10H : 0 注意: PSP区和程序区虽然物理地址连续,却有不同的段地址。 4) 将该内存区的段地址存入 DS 中,初始化其他相关寄存器后,设置 CS:IP 指向程序入口。 PSP 占 256(100H)字节,所以程序的物理地址是:SA*16+0+256=SA*16+16*16+0=(SA+16)*16+0 可用段地址和偏移地址表示为:SA+10:0。 理解:设 DS=129E ,问 PSP 地址? 和程序的地址是多少? 程序加载后,DS中存放着程序所在的内存区的段地址,这个内存区的偏移地址为0,则程序所在的内存区的地址为 DS:0 程序地址: 129E*16+0+256=129E0+100H=12AE0H(物理地址)=12AE:0=CS:0(相对地址) PSP 地址: 129E:0 但是,上面求程序所在地址(非物理地址)可以如下变通: 求物理地址: 129E*16相当于(129E0),而加256相当于(加100H), 129E0H 100H --------------------- + 12AE0H 但求 段:偏移量 地址方式,则还要再去一个0(相当于除16),所以应如下变通: 129EH + 10H = 12AE:0000 这样就求出了: 段地址:偏移量 上面就是程序是如何分配程序地址的计算原理的过程~:) 怎么可以“直观”的看到PSP的“标置”?PSP的头两个字节是 CD 20
编译成 .exe 文件,用 Debug 调试代码
因为栈空间分配大小的原因,编译成 .exe 文件后在 MS-DOS 6.22 下调试正常,在Windows CMD 内调试出错,增加栈空间即可。 [ Last edited by redtek on 2006-12-23 at 09:05 AM ] |
|
| 第57楼 redtek | 发表于 2006-12-23 22:44 |
| 金牌会员 发帖 1,147 积分 2,902 | |
|
【80x86汇编语言学习笔记】 汇编指令描述方式
内存单元的描述 mov ax, 将一个内存单元的内容送入ax,这个内存单元的长度为2字节(字单元),存放一个字,偏移地址为0,段地址在ds中。 描述练习 1) ax中的内容为0010H,描述它 (ax)=0010H 2) 2000:1000 处的内容为 0010H (21000H)= 0010H 3) mov ax, (ax)= ((ds)* 16 + 2) 4) mov ,ax ((ds)* 16 + 2)= (ax) 5) add ax,2 (ax)=(ax)+ 2 6) add ax,bx (ax)=(ax)+(bx) 7) push ax (sp)=(sp)- 2 ((ss)* 16 + (sp))= (ax) 8) pop ax (ax)=((ss)* 16 + (sp)) (sp)=(sp)+ 2 为什么要这样描述? 这种描述方式可以更深的理解指令的物理内存操作原理和所有过程,它是理解更多内容与原理的必须基础。 [ Last edited by redtek on 2006-12-23 at 10:06 AM ] |
|
| 第58楼 ccwan | 发表于 2006-12-24 00:10 |
| 金牌会员 发帖 1,160 积分 2,725 来自 河北廊坊 | |
|
redtek笔耕不辍,我来鼓励一下!
|
|
| 第59楼 redtek | 发表于 2006-12-24 01:58 |
| 金牌会员 发帖 1,147 积分 2,902 | |
|
多谢ccwan兄不断鼓励~:)
|
|
| 第60楼 redtek | 发表于 2006-12-24 02:16 |
| 金牌会员 发帖 1,147 积分 2,902 | |
|
【80x86汇编语言学习笔记】 循环指令与编译器
下面代码 Masm 5.0 编译通过~:)
但是,如果要使用 ADD 指令计算几好百个次方,是不是要输出几百个指令? 可以用 Loop 循环指令模拟一下,这东东稍微有点儿像批处理里的 Goto 语句,哈哈…… 先一步一步慢慢来,先分析上面代码编译之后的样子~:) 象 “ASSUME CS:CODE” 与 “CODE SEGMENT” 等都是汇编伪指令,CPU不认识,它由 Masm 编译器编译时“转化”。
下面使用循环计算2的12次方
Loop 是循环,S:是循环标号, mov cx,11 ,每次循环一次cx寄存器值被递减。 执行顺序:执行到 Loop 时,CX值先减1,然后如果判断不为0,则跳转到标号。 它是如何跳转到标号的?它会修改 IP 的指向,cpu 执行 CS:IP 所指向的指令,然自就“返回”了标号处。 在Debug中跟踪Loop指令
上面代码中的棕色代码与汇编源代码中的伪指令的区别。 绿色代码为执行Loop时的跳转与 IP 的指向。 看循环指令结果时,也可以使用 Debug P 指令来跟踪最后的结果。 下面是计算 123 * 236
如果下面这样写结果也一样正确: mov cx,236 s: add ax,123 但,相当于循环了 236 遍,如果 mov cx,123 ,则相当于只循环了123遍,速度稍快一些。 在Debug中跟踪下面编译的代码
可以看到,Loop指令的每一步是如何工作的……
如果(cx)=(cx)-1 ,当(cx)=0时: 因为(cx)=0,Loop指令不跳转。向下执行。 [ Last edited by redtek on 2006-12-23 at 05:27 PM ] |
|
| 上一页 1 2 3 4 5 6 7 … 9 下一页 |
|
[ 联系联盟系统管理团队 -
中国DOS联盟 -
标准版 ] Sponsored by ifanr Inc | © 2001–2023 |