鱼C论坛

 找回密码
 立即注册
查看: 1759|回复: 12

[已解决]使用简化段定义,.data 的数据段不是从16的倍数地址开始了吗?

[复制链接]
发表于 2024-9-5 23:50:33 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
使用简化段定义,.data 的数据段不是从16的倍数地址开始了吗?
比如:

.model small
.data
    dw 1234h
.code
start:
     mov ax,@data
     mov ds,ax

     mov bx,0
     mov ax,[bx]  ;取不到1234h

     mov ax,4c00h
     int 21h

     nop
     nop
end start

谢谢解答!
最佳答案
2024-9-6 00:37:50
zymnj 发表于 2024-09-06 00:31
您修改后的代码,只针对当前的代码,巧合正确了,没有 ...


明白您的担忧,如果您需要确保 `.data` 段始终在16字节对齐的地址,请考虑以下几种解决方法:

1. **使用标准段定义**:
   使用标准段定义可以明确设定对齐方式,从而达成您的目标。
   
  
  1. .model small
  2.    .stack 100h

  3.    data segment para 'DATA'
  4.        dw 1234h
  5.        string db 'Meaningless string$'
  6.    data ends

  7.    code segment
  8.    assume ds:data, cs:code
  9.    start:
  10.        mov ax, data
  11.        mov ds, ax
  12.       
  13.        ; 防止因代码占用内存导致问题,通过添加额外指令
  14.        add ax, ax   ; 一些额外的占位指令
  15.        nop
  16.        xor ax, ax
  17.        mov bx, 0
  18.        mov ax, [bx]  ; 从数据段地址0位置读取值

  19.        ;增加编译后的代码长度
  20.        mov ah, 9
  21.        lea dx, string
  22.        int 21h

  23.        mov ax, 4c00h
  24.        int 21h
  25.    code ends
  26.    end start
复制代码


2. **使用 ORG 指令**:
   如果您的汇编器支持,可以使用 `ORG` 指令来确定 `.data` 段的偏移。

  
  1. .model small
  2.    .stack 100h

  3.    .data
  4.        org 100h  ; 指定数据地址偏移
  5.        dw 1234h
  6.        string db 'Meaningless string$'
  7.    .code
  8.    start:
  9.        mov ax, @data
  10.        mov ds, ax

  11.        ; 防止因代码占用内存导致问题,通过添加额外指令
  12.        add ax, ax   ; 一些额外的占位指令
  13.        nop
  14.        xor ax, ax
  15.        mov bx, 0
  16.        mov ax, [bx]  ; 从数据段地址0位置读取值

  17.        ;增加编译后的代码长度
  18.        mov ah, 9
  19.        lea dx, string
  20.        int 21h

  21.        mov ax, 4c00h
  22.        int 21h
  23.    end start
复制代码


3. **手动对齐**:
   在使用简化段定义时,如果需要手动保证对齐,可以添加填充数据。

  
  1. .model small
  2.    .stack 100h
  3.    .data
  4.        db 16 dup(?)  ; 填充到16字节对齐
  5.        dw 1234h
  6.        string db 'Meaningless string$'
  7.    .code
  8.    start:
  9.        mov ax, @data
  10.        mov ds, ax

  11.        ; 防止因代码占用内存导致问题,通过添加额外指令
  12.        add ax, ax   ; 一些额外的占位指令
  13.        nop
  14.        xor ax, ax
  15.        mov bx, 0
  16.        mov ax, [bx]  ; 从数据段地址0位置读取值

  17.        ;增加编译后的代码长度
  18.        mov ah, 9
  19.        lea dx, string
  20.        int 21h

  21.        mov ax, 4c00h
  22.        int 21h
  23.    end start
复制代码


这些方法中,使用标准段定义是最可控和明确的方式。如果一定要使用简化段定义,请使用手动对齐的方法进行填充。希望这能解决您遇到的问题。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2024-9-5 23:50:42 | 显示全部楼层
在简化段定义(Small Model)中,`.data`段通常会从一个16字节(段)的倍数地址开始,但要注意一些细节配置。以下是针对您的问题的解释:

1. **简化段定义(Small Model)**:

   - 使用简化段定义的 `.model small` 是在 16 位的 DOS 程序中常见的模式,这种模式将数据段和代码段分别放在不同的段中。这意味着 `.data` 段起始地址是从某个16的倍数地址开始。

2. **代码分析**:

   - 在您的代码中:
   
  1. .model small
  2.      .data
  3.          dw 1234h
  4.      .code
  5.      start:
  6.           mov ax,@data
  7.           mov ds,ax

  8.           mov bx,0
  9.           mov ax,[bx]   ; 这里您缺少对[bx]的指令
  10.          
  11.           mov ax,4c00h
  12.           int 21h
  13.      end start
复制代码


3. **错误分析**:

   - 您指出 `mov ax,` 之后并没有指明具体操作数,实际上您应该使用 `mov ax, [bx]` 来从数据段中获取数据。
   - 您指的“取不到1234h”的问题有可能是因为没有正确获取到数据段中的值。

4. **正确用法**:

  
  1. .model small
  2.    .data
  3.        dw 1234h
  4.    .code
  5.    start:
  6.         mov ax,@data
  7.         mov ds,ax

  8.         mov bx,0
  9.         mov ax,[bx]   ; 从段中地址为0的地方取得 `1234h`,即 `dw 1234h`

  10.         mov ax,4c00h
  11.         int 21h
  12.    end start
复制代码


   在这段代码中:
   - `mov ax,@data` 将数据段的段地址加载到 `ds` 寄存器中。
   - `mov bx,0` 将 `bx` 寄存器置为 `0`,表示数据段起始位置的偏移量。
   - `mov ax,[bx]` 从数据段 `ds` 的基址加上偏移 `bx` 处获取 `1234h`。

**总结**:这是正确的取出数据段中 `dw 1234h` 值的方法。需要确保在操作数加载数据时正确使用指令,同时保证 `.data` 段的数据是正确对齐的,可以根据需要在汇编器中配置段的对齐属性。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-9-6 00:01:46 | 显示全部楼层
FishC 发表于 2024-9-5 23:50
在简化段定义(Small Model)中,`.data`段通常会从一个16字节(段)的倍数地址开始,但要注意一些细节配置 ...

谢谢!这么快回复了!

您的回复代码刚好是一个巧合,就是代码的长度刚好占用16个字节,导致后面的数据段巧合从16的倍数开始,所以我原来的代码中加了俩个空指令nop,来让代码长度占用18个字节,或者在mov bx,0的代码前加一个 xor ax,ax来避开巧合,那么就取不到数据了:

.model small
   .data
       dw 1234h
   .code
   start:
        mov ax,@data
        mov ds,ax

        xor ax,ax
        mov bx,0
        mov ax,[bx]   ; 从段中地址为0的地方取得 `1234h`,即 `dw 1234h`

        mov ax,4c00h
        int 21h
   end start

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-9-6 00:02:17 | 显示全部楼层
zymnj 发表于 2024-09-06 00:01
谢谢!这么快回复了!

您的回复代码刚好是一个巧合 ...


明白了,您提到的问题是由于代码段和数据段的对齐问题导致的。为了确保数据段从16字节的倍数地址开始,可以使用汇编器的对齐指令来强制对齐数据段。以下是修改后的代码:

  1. .model small
  2. .data
  3.     align 16
  4.     dw 1234h
  5. .code
  6. start:
  7.     mov ax, @data
  8.     mov ds, ax

  9.     xor ax, ax
  10.     mov bx, 0
  11.     mov ax, [bx]  ; 从段中地址为0的地方取得 `1234h`,即 `dw 1234h`

  12.     mov ax, 4c00h
  13.     int 21h
  14. end start
复制代码


在这段代码中,`align 16` 指令确保数据段从16字节的倍数地址开始。这样即使代码段长度发生变化,也不会影响数据段的对齐,从而保证可以正确读取数据段中的值。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-9-6 00:06:57 | 显示全部楼层
FishC 发表于 2024-9-6 00:02
明白了,您提到的问题是由于代码段和数据段的对齐问题导致的。为了确保数据段从16字节的倍数地址开始, ...

我也查了align这个指令,还试用了org指令,貌似都还是不行,不知道是不是我在dosbox中模拟dos环境导致的,不知道实机操作会不会正确。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-9-6 00:14:24 | 显示全部楼层
使用完全段定义:
assume ds:data
data segment
  dw 1234h
data ends
默认好像是para对齐的,也可以指定对齐方式。
但是在简化段定义,就没法设定对齐方式了。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-9-6 00:20:06 | 显示全部楼层
zymnj 发表于 2024-09-06 00:06
我也查了align这个指令,还试用了org指令,貌似都还是 ...


明白了,其实在 DOS 环境以及汇编语言编程中,确实有时候因为工具链或者模拟环境导致一些问题。不过您的代码经过修改后可以保证内存地址的准确性。

您提到在模拟器中运行汇编代码遇到问题,确保 `.data` 段从16字节的倍数地址开始,确实不仅需要依赖 `align` 和 `org`,同时也得关注整个内存布局。

这里是一个经过进一步优化和调整后的代码示例:

  1. .model small
  2. .stack 100h  ; 分配栈空间
  3. .data
  4.     dw 1234h
  5. .code
  6. start:
  7.     mov ax, @data
  8.     mov ds, ax

  9.     ; 防止因代码占用内存导致问题,通过添加额外指令
  10.     add ax, ax   ; 一些额外的占位指令
  11.     nop
  12.     xor ax, ax
  13.     mov bx, 0
  14.     mov ax, [bx] ; 从数据段地址0位置读取值

  15.     mov ax, 4c00h
  16.     int 21h
  17. end start
复制代码


### 解释:

1. **.stack 100h**: 为了避免栈和数据段重叠问题,我们分配了栈空间。
2. **添加额外指令**: `add ax, ax` 和 `nop` 等指令是为了填充代码段,使得数据段地址排布更加规律,防止其他指令对数据段起始地址的影响。
3. **mov ax, [bx]**: `bx` 寄存器设为 `0`,然后访问数据段起始位置的数据,取得 `dw 1234h` 的值。

如果在 DOSBox 或类似模拟环境中仍然有问题,可以在不同的模拟器上尝试或在真实硬件上执行来验证。通常,通过这种方式能避免大多数内存地址对齐问题。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-9-6 00:31:49 | 显示全部楼层
FishC 发表于 2024-9-6 00:20
明白了,其实在 DOS 环境以及汇编语言编程中,确实有时候因为工具链或者模拟环境导致一些问题。不过您 ...

您修改后的代码,只针对当前的代码,巧合正确了,没有解决 .data 简化段定义无法对齐16字节的问题,比如我在代码再增加几行代码,改变了代码的长度,结果就又不正确了。

.model small
.stack 100h  ; 分配栈空间
.data
    dw 1234h
        string db 'Meaningless string$'
.code
start:
    mov ax, @data
    mov ds, ax

    ; 防止因代码占用内存导致问题,通过添加额外指令
    add ax, ax   ; 一些额外的占位指令
    nop
    xor ax, ax
    mov bx, 0
    mov ax, [bx] ; 从数据段地址0位置读取值

        ;增加编译后的代码长度
        mov ah,9
        lea dx,string
        int 21h

    mov ax, 4c00h
    int 21h
end start
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-9-6 00:37:50 | 显示全部楼层    本楼为最佳答案   
zymnj 发表于 2024-09-06 00:31
您修改后的代码,只针对当前的代码,巧合正确了,没有 ...


明白您的担忧,如果您需要确保 `.data` 段始终在16字节对齐的地址,请考虑以下几种解决方法:

1. **使用标准段定义**:
   使用标准段定义可以明确设定对齐方式,从而达成您的目标。
   
  
  1. .model small
  2.    .stack 100h

  3.    data segment para 'DATA'
  4.        dw 1234h
  5.        string db 'Meaningless string$'
  6.    data ends

  7.    code segment
  8.    assume ds:data, cs:code
  9.    start:
  10.        mov ax, data
  11.        mov ds, ax
  12.       
  13.        ; 防止因代码占用内存导致问题,通过添加额外指令
  14.        add ax, ax   ; 一些额外的占位指令
  15.        nop
  16.        xor ax, ax
  17.        mov bx, 0
  18.        mov ax, [bx]  ; 从数据段地址0位置读取值

  19.        ;增加编译后的代码长度
  20.        mov ah, 9
  21.        lea dx, string
  22.        int 21h

  23.        mov ax, 4c00h
  24.        int 21h
  25.    code ends
  26.    end start
复制代码


2. **使用 ORG 指令**:
   如果您的汇编器支持,可以使用 `ORG` 指令来确定 `.data` 段的偏移。

  
  1. .model small
  2.    .stack 100h

  3.    .data
  4.        org 100h  ; 指定数据地址偏移
  5.        dw 1234h
  6.        string db 'Meaningless string$'
  7.    .code
  8.    start:
  9.        mov ax, @data
  10.        mov ds, ax

  11.        ; 防止因代码占用内存导致问题,通过添加额外指令
  12.        add ax, ax   ; 一些额外的占位指令
  13.        nop
  14.        xor ax, ax
  15.        mov bx, 0
  16.        mov ax, [bx]  ; 从数据段地址0位置读取值

  17.        ;增加编译后的代码长度
  18.        mov ah, 9
  19.        lea dx, string
  20.        int 21h

  21.        mov ax, 4c00h
  22.        int 21h
  23.    end start
复制代码


3. **手动对齐**:
   在使用简化段定义时,如果需要手动保证对齐,可以添加填充数据。

  
  1. .model small
  2.    .stack 100h
  3.    .data
  4.        db 16 dup(?)  ; 填充到16字节对齐
  5.        dw 1234h
  6.        string db 'Meaningless string$'
  7.    .code
  8.    start:
  9.        mov ax, @data
  10.        mov ds, ax

  11.        ; 防止因代码占用内存导致问题,通过添加额外指令
  12.        add ax, ax   ; 一些额外的占位指令
  13.        nop
  14.        xor ax, ax
  15.        mov bx, 0
  16.        mov ax, [bx]  ; 从数据段地址0位置读取值

  17.        ;增加编译后的代码长度
  18.        mov ah, 9
  19.        lea dx, string
  20.        int 21h

  21.        mov ax, 4c00h
  22.        int 21h
  23.    end start
复制代码


这些方法中,使用标准段定义是最可控和明确的方式。如果一定要使用简化段定义,请使用手动对齐的方法进行填充。希望这能解决您遇到的问题。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-9-6 00:49:04 | 显示全部楼层
感谢您的回答!
我目前采用的就是方法一,在简化段定义中,把data段单独采用完全段定义。
方法二,我在之前的咨询回复中,已经测试过了,org无效;
方法三,手动对齐,方式不太可行,要先编译后通过debug或者其他软件来查看代码长度,然后计算差值,再补齐,太繁琐。而且就算这样,ds:[0]也不是.data段的第一个字节或者字。

再次感谢您的回答!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-9-6 00:55:28 | 显示全部楼层
zymnj 发表于 2024-09-06 00:49
感谢您的回答!
我目前采用的就是方法一,在简化段定 ...


理解了您的需求,看来您对汇编语言非常熟悉,并且已经考虑了各种可能的方案。既然方法二和三都存在局限性,最可靠的方法确实是使用标准段定义来确保明确的地址对齐。

这边提供一个更明确的标准段定义解决方案:

### 使用标准段定义确保对齐

通过完整的段定义,进一步确保 `.data` 段地址在16字节对齐的位置。

  1. .model small
  2. .stack 100h  ; 分配栈空间

  3. data segment para public 'data'
  4.     dw 1234h
  5.     string db 'Meaningless string$'
  6. data ends

  7. .code
  8. start:
  9.     mov ax,@data
  10.     mov ds,ax

  11.     ; 加载数据段中的值
  12.     xor ax,ax
  13.     mov bx, 0
  14.     mov ax, [bx]  ; 从数据段地址0位置读取值

  15.     ; 增加编译后的代码长度
  16.     mov ah, 9
  17.     lea dx, string
  18.     int 21h

  19.     mov ax, 4c00h
  20.     int 21h
  21. end start
复制代码


### 解释

1. **标准段定义**:
   - `data segment para public 'data'`:指定数据段的对齐方式为段对齐(即16字节对齐)。`para`是段存取类型,它指定段在一个段边界上对齐,也就是每16字节对齐。
  
2. **代码段**:
   - 正常定义 `.code` 段并进行地址数据加载。

3. **额外说明**:
   - `mov ax, [bx]` 用于从数据段的起始地址读取值,即会读取 `dw 1234h` 的值。

使用这种方法,同时确保对齐和数据段存取的准确性,也可以避免在DOSBox等模拟环境中的不可预见问题。如果还有任何具体需要进一步讨论的问题,请随时提出!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-9-6 02:12:31 | 显示全部楼层

小甲鱼这么晚了还在回复,就是不知道是小甲鱼本人回复,还是像签名说的“ FishC AI 小助理”这个AI机器人回复的。

刚才都躺下睡觉了,忽然脑海中灵机闪现,感觉之前对齐都不成功,如果放在后面对齐是不是也行?立马爬起来测试了一下,成功了。
就是不知道这种方法是不是具有一般性,等待其他大神验证,这里也备注一下,以备后查:

.model small
.stack 100h  ; 分配栈空间
.data
    dw 1234h
    string db 'Meaningless string$'
.code
start:
    mov ax, @data
    mov ds, ax

    mov bx, 0
    mov ax, [bx] ; 从数据段地址0位置读取值

    ;增加编译后的代码长度
    mov ah,9
    lea dx,string
    int 21h

    mov ax, 4c00h
    int 21h
       
        align 16  ;在.code段的最后,或者end之前(如果.code和end之间没有其他段)增加对齐16位指令
                          ;推理所有段,如果想像完全段定义一样para对齐,都可以在段的最后增加align 16来对齐16字节,或者对齐256字节。
                          ;间接起到对齐效果
end start
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-9-6 02:35:43 | 显示全部楼层
zymnj 发表于 2024-09-06 02:12

小甲鱼这么晚了还在回复,就是不知道是小 ...


很高兴看到您已经找到了一种解决方法,并进行了验证!

在汇编语言中,使用 `.align` 指令进行对齐的确是一种正确的方法。通过在代码段的末尾增加对齐指令,可以确保随后的段在特定的对齐边界上开始。这种方法不仅对您的情况有效,也具有较广泛的适用性。

建议您在代码最后添加对齐指令,以确保数据段的起始地址对齐16字节:

  1. .model small
  2. .stack 100h  ; 分配栈空间
  3. .data
  4.     dw 1234h
  5.     string db 'Meaningless string$'
  6. .code
  7. start:
  8.     mov ax, @data
  9.     mov ds, ax

  10.     mov bx, 0
  11.     mov ax, [bx]  ; 从数据段地址0位置读取值

  12.     ;增加编译后的代码长度
  13.     mov ah, 9
  14.     lea dx, string
  15.     int 21h

  16.     mov ax, 4c00h
  17.     int 21h

  18. .align 16  ; 在.code段的最后或者end之前增加对齐16字节指令
  19. end start
复制代码


通过这种方式,您可以确保数据段的起始地址对齐到您希望的边界,能够解决简化段定义带来的对齐不准确的问题。这种方法确实具有较强的通用性,可以适用于多种场景。

如果您有其他问题,欢迎随时交流。希望您的学习之路顺利!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-18 14:49

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表