laocaiye 发表于 2025-3-19 09:57:03

关于第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

FishC 发表于 2025-3-19 09:57:23

你的代码存在几个问题,可能导致调试时出现 ??? 的情况。以下是一些关键问题和改进建议:

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-3-19 10:11:07

那就奇怪了,为何以前都这样写没问题呢?

FishC 发表于 2025-3-19 10:11:22

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 小助理,如未能正确解答您的问题,请继续追问。

laocaiye 发表于 2025-3-19 10:20:33

我一直就是使用DOSBOX,从开始学习就是按上传的代码格式写的,一直都没问题啊,怎么今天出这个毛病了。我昨天在VM中安装的MS-DOS,难道这也会有影响?

FishC 发表于 2025-3-19 10:20:48

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 小助理,如未能正确解答您的问题,请继续追问。

laocaiye 发表于 2025-3-19 10:26:51

和机器人实在说不明白。我压根就没使用MS-DOS运行代码,我是用DOSBOX运行的代码,以前就是用mov ax,data   mov ds,ax这种形式写的,一直都没问题,今天居然出现这个奇葩问题。看来AI代替人,真的不可能。

FishC 发表于 2025-3-19 10:27:04

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 小助理,如未能正确解答您的问题,请继续追问。

jackz007 发表于 2025-3-19 11:04:03

下面这两句是谁教的?
mov ax,code
mov cs,ax
      这个世界除了阁下,恐怕不会再有第二个人会这么写代码!
         直接删除。

laocaiye 发表于 2025-3-19 11:21:46

经过重新安装DOSBOX,我的代码根本就问题,应该是软件出了问题,但是原因不明。根本就不是小鱼机器人说的什么乱七八糟解答,机器人回答问题真让人崩溃。另外使用 mov ax,@data形式压根就是错误。还有:shr ah,4是根本性错误,循环移位,必须把次数放在cl中。

laocaiye 发表于 2025-3-19 14:17:51

jackz007 发表于 2025-3-19 11:04
下面这两句是谁教的?

      这个世界除了阁下,恐怕不会再有第二个人会这么写代码!


因为我软件问题,在执行前两句代码后就开始出错,我是在调试过程中,增加了这么两句。因为也没查出来什么问题,所以在发布问题时就忘记删除了。发现是软件问题后,就删除了,程序运行正常。
页: [1]
查看完整版本: 关于第16章的字符映射例题