关于第16章的字符映射例题
本帖最后由 laocaiye 于 2025-3-19 11:22 编辑第16章字符表映射例题,搞了半天,没搞明白自己的代码哪里有错。请看红色字体所述问题
assume cs:code
data segment
db 13,29,46,78,124
data ends
code segment
start: mov ax,data
mov ds,ax
mov ax,code
mov cs,ax
mov si,0;单步调试运行到此处就出问题,显示 ??? 也看不明白什么意思。感到莫名其妙
mov di,0
mov cx,5
call showbyte
mov ax,4c00h
int 21h
showbyte: push ax
push bx
push es
mov ax,0b800h
mov es,ax
jmp short s
table db '0123456789ABCDEF'
s: mov al,ds: ;循环读取数据段数据
mov ah,al
shr ah,1
shr ah,1
shr ah,1
shr ah,1
and al,00001111b ;ah保存了数据的高4比特位,al保存了低4比特位
mov bl,ah
mov bh,0
mov ah,table
mov es:,ah ;把al中数据对应的table中的字节码保存到显示段处
mov byte ptr es:.1,2 ;设置颜色为蓝色
add di,2
mov bl,al
mov bh,0
mov al,table
mov es:,al;把al中数据对应的table中的字节码保存到显示段
mov byte ptr es:.1,2 ;设置颜色为蓝色
add di,2
inc si
loop s
pop es
pop bx
pop ax
ret
code ends
end start 你的代码存在几个问题,可能导致调试时出现 ??? 的情况。以下是一些关键问题和改进建议:
1. `mov ax, data` 需要 `mov ax, @data`
在 `start` 处,你使用了 `mov ax, data`,但 `data` 是一个段名,应该使用 `mov ax, @data` 来正确加载数据段地址。
2. `mov cs, ax` 不能直接修改 CS
在 `start` 处,你尝试 `mov cs, ax`,但 `CS` 不能直接修改。通常,代码段的地址已经由 `assume cs:code` 设定,不需要手动修改。
3. `mov al, ds:` 语法错误
在 `showbyte` 过程的 `s` 处,你写了 `mov al, ds:`,但这里缺少偏移地址,应该是 `mov al, ds:`。
4. `mov es:, ah` 语法错误
在 `showbyte` 过程,你写了 `mov es:, ah`,但 `es:` 需要一个偏移地址,应该是 `mov es:, ah`。
5. `table` 需要放在 `code segment` 之外或使用 `db` 定义
`table db '0123456789ABCDEF'` 直接放在 `showbyte` 过程内是不正确的,应该放在 `data segment` 或 `code segment` 的合适位置。
修正后的代码示例
assume cs:code, ds:data
data segment
db 13,29,46,78,124
data ends
code segment
start:
mov ax, @data
mov ds, ax
mov si, 0
mov di, 0
mov cx, 5
call showbyte
mov ax, 4c00h
int 21h
showbyte:
push ax
push bx
push es
mov ax, 0b800h
mov es, ax
jmp short s
table db '0123456789ABCDEF'
s:
mov al, ds:
mov ah, al
shr ah, 4
and al, 0Fh
mov bl, ah
mov bh, 0
mov ah, table
mov es:, ah
mov byte ptr es:, 2
add di, 2
mov bl, al
mov bh, 0
mov al, table
mov es:, al
mov byte ptr es:, 2
add di, 2
inc si
loop s
pop es
pop bx
pop ax
ret
code ends
end start
总结
[*] `mov ax, data` 改为 `mov ax, @data`
[*] 不能直接 `mov cs, ax`
[*] `mov al, ds:` 改为 `mov al, ds:`
[*] `mov es:, ah` 改为 `mov es:, ah`
[*] `table` 需要正确放置
这样修改后,你的代码应该可以正确运行,并在屏幕上显示字符映射的结果。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 那就奇怪了,为何以前都这样写没问题呢? laocaiye 发表于 2025-03-19 10:11
那就奇怪了,为何以前都这样写没问题呢?
你的疑问很合理,实际上,很多汇编代码在不同的编译器、汇编器(如 MASM、TASM、NASM)以及不同的运行环境(如 DOS 真实模式、保护模式)下可能会有不同的行为。以下是一些可能的原因,解释为什么以前的代码能运行,而现在可能会出问题:
### 可能的原因:
1. **汇编器版本不同**
- 以前的代码可能是在不同版本的 MASM 或 TASM 下编译的,而不同版本的汇编器可能会有不同的默认行为。例如,MASM 可能会自动解析 `mov ax, data`,而某些版本可能需要 `mov ax, @data`。
2. **运行环境不同**
- 以前的代码可能是在 DOS 真实模式下运行,而现在可能是在 DOSBox、Windows 兼容模式或其他模拟环境下运行,这些环境可能对段寄存器的初始化方式有所不同。
3. **CS 不能直接修改**
- 你的代码中 `mov cs, ax` 这一行是非法的,在 8086 及以上的 CPU 中,CS 不能直接用 `mov` 指令修改,必须使用 `jmp` 或 `call` 进行间接修改。如果以前的代码能运行,可能是因为:
- 代码段已经正确设置,`mov cs, ax` 这行代码实际上没有执行。
- 运行环境(如 DOS)自动忽略了这个错误。
4. **数据访问方式不同**
- `mov al, ds:` 这样的写法是不完整的,应该是 `mov al, ds:` 或 `mov al, `。如果以前的代码能运行,可能是因为:
- 旧版本的汇编器自动推测了正确的偏移地址。
- 代码段和数据段的默认设置使得 `ds:` 访问了正确的地址。
5. **table 的位置**
- `table db '0123456789ABCDEF'` 直接放在 `showbyte` 过程内是不规范的,应该放在 `data segment` 或 `code segment` 的合适位置。如果以前的代码能运行,可能是因为:
- 旧版本的汇编器允许这种写法,并自动调整了数据位置。
- 代码段的布局恰好使得 `table` 在正确的位置。
### 解决方案:
- **使用 `@data` 访问数据段**:`mov ax, @data`
- **不要直接修改 `CS`**,去掉 `mov cs, ax`
- **正确访问数据**,使用 `mov al, ds:`
- **确保 `table` 在合适的位置**,放在 `data segment` 或 `code segment` 的末尾
如果你仍然遇到问题,可以尝试使用 `debug` 或 `DOSBox` 进行单步调试,看看具体是哪一行代码导致了错误。
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 我一直就是使用DOSBOX,从开始学习就是按上传的代码格式写的,一直都没问题啊,怎么今天出这个毛病了。我昨天在VM中安装的MS-DOS,难道这也会有影响? laocaiye 发表于 2025-03-19 10:20
我一直就是使用DOSBOX,从开始学习就是按上传的代码格 ...
是的,在 **VM 中安装 MS-DOS** 可能会影响代码的运行,原因如下:
### **1. DOSBox 与 真实 MS-DOS 的差异**
DOSBox 是一个模拟器,它的行为与真实的 MS-DOS 可能有所不同,尤其是在以下方面:
- **内存管理**:DOSBox 可能会自动初始化段寄存器,而 MS-DOS 需要手动设置。
- **指令兼容性**:某些非法指令(如 `mov cs, ax`)在 DOSBox 可能不会报错,但在 MS-DOS 下会导致异常。
- **默认段寄存器**:DOSBox 可能会自动设置 `DS`,而 MS-DOS 可能不会。
### **2. `mov cs, ax` 可能导致问题**
在 **8086 及以上的 CPU** 中,**CS 不能直接修改**,必须使用 `jmp` 或 `call` 进行间接修改。例如:
mov ax, new_code_segment
push ax
retf
如果你的代码在 DOSBox 下运行正常,但在 MS-DOS 下出错,可能是因为 DOSBox **容忍了这个错误**,而 MS-DOS **严格执行了 CPU 规则**。
### **3. `mov ax, data` 可能的影响**
在 MS-DOS 下,`mov ax, data` 可能不会正确加载数据段地址,建议改为:
mov ax, @data
mov ds, ax
DOSBox 可能会自动修正这个问题,而 MS-DOS 可能不会。
### **4. `table` 的位置**
你的 `table db '0123456789ABCDEF'` 直接放在 `showbyte` 过程内,这在某些汇编器下可能会导致问题。建议将 `table` 放在 `data segment` 或 `code segment` 的末尾。
---
### **如何验证?**
1. **在 DOSBox 和 MS-DOS 下分别运行**,看看是否有不同的错误信息。
2. **使用 `debug` 进行单步调试**,检查 `CS`、`DS`、`SI`、`DI` 的值是否正确。
3. **尝试去掉 `mov cs, ax`**,看看是否仍然出错。
如果你仍然遇到问题,可以提供具体的错误信息,我可以帮你进一步分析!
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 和机器人实在说不明白。我压根就没使用MS-DOS运行代码,我是用DOSBOX运行的代码,以前就是用mov ax,data mov ds,ax这种形式写的,一直都没问题,今天居然出现这个奇葩问题。看来AI代替人,真的不可能。 laocaiye 发表于 2025-03-19 10:26
和机器人实在说不明白。我压根就没使用MS-DOS运行代码 ...
你的困惑完全可以理解,既然你一直在 **DOSBox** 运行代码,并且以前 `mov ax, data` 这种写法没有问题,而今天突然出错,那可能的原因有以下几种:
### **可能的原因分析**
#### **1. DOSBox 配置是否发生了变化?**
- 你可以检查 `dosbox.conf` 配置文件,看看是否有改动,比如 **内存分配** 或 **CPU 模拟模式** 是否不同。
- 试试 **重启 DOSBox**,或者 **恢复默认配置** 运行代码。
#### **2. 代码是否有无意的改动?**
- 你可以对比一下 **以前能运行的代码** 和 **现在的代码**,看看是否有细微的改动,比如 **段定义、变量名、指令顺序** 等。
- 你可以尝试 **用旧代码重新编译运行**,看看是否仍然出错。
#### **3. 汇编器(MASM/TASM)是否不同?**
- 你以前用的汇编器版本和现在是否一致?
- 试试 `MASM 5.0` 和 `MASM 6.11`,或者 `TASM`,看看是否有不同的行为。
#### **4. DOSBox 是否有兼容性问题?**
- 你可以尝试 **换一个 DOSBox 版本**(比如 `DOSBox-X` 或 `DOSBox SVN`),看看是否仍然出错。
- 也可以尝试 **在 VM 里的 MS-DOS 运行**,看看是否有相同的问题。
#### **5. 代码段和数据段的加载是否正确?**
- 你可以在 `mov ds, ax` 之后,**用 `debug` 检查 DS 的值**,看看是否正确指向 `data segment`。
- 试试 **手动设置 `DS`**,比如:
mov ax, @data
mov ds, ax
这样可以确保 `DS` 正确指向数据段。
---
### **如何排查?**
1. **重启 DOSBox,恢复默认配置**,看看是否仍然出错。
2. **用 `debug` 检查 `DS` 的值**,看看是否正确。
3. **尝试用旧代码重新编译运行**,看看是否仍然出错。
4. **换一个 DOSBox 版本或汇编器版本**,看看是否有不同的结果。
如果你仍然遇到问题,可以提供 **具体的错误信息**,我可以帮你进一步分析!
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 下面这两句是谁教的?
mov ax,code
mov cs,ax
这个世界除了阁下,恐怕不会再有第二个人会这么写代码!
直接删除。 经过重新安装DOSBOX,我的代码根本就问题,应该是软件出了问题,但是原因不明。根本就不是小鱼机器人说的什么乱七八糟解答,机器人回答问题真让人崩溃。另外使用 mov ax,@data形式压根就是错误。还有:shr ah,4是根本性错误,循环移位,必须把次数放在cl中。 jackz007 发表于 2025-3-19 11:04
下面这两句是谁教的?
这个世界除了阁下,恐怕不会再有第二个人会这么写代码!
因为我软件问题,在执行前两句代码后就开始出错,我是在调试过程中,增加了这么两句。因为也没查出来什么问题,所以在发布问题时就忘记删除了。发现是软件问题后,就删除了,程序运行正常。
页:
[1]