How to switch between multiple data segments in 8086 assembly?

被刻印的时光 ゝ 提交于 2020-01-05 04:18:04

问题


I'm programming using MASM 6.11 on an old Windows 95 laptop, and I'm having a problem switching between data segments.

For the sake of organization I wanted to use a different data segment to hold all of the variables that are only used by my macros. That different data segment is also placed inside the macro file.

I thought I could specify a different data segment by just MOVing the new segment into DS, but that doesn't seem to be working. I get the following error repeated many times upon assembling.

error A20068: Cannot address with segment register

Here's an example .ASM, and .MAC file showing my program's basic layout.

;********************
; STACK SEGMENT 
;********************

TheStack STACK SEGMENT

 DB 64 DUP ('THESTACK') ;512 bytes for the stack

TheStack ENDS

;********************
; END STACK SEGMENT
;********************

;********************
; DATA SEGMENT 
;********************

Data SEGMENT

var db ?

Data ENDS

;********************
; END DATA SEGMENT 
;********************


;********************
; CODE SEGMENT 
;********************

Code SEGMENT

assume CS:Code,DS:Data

MAIN PROC

    ;set Data to be the Data Segment
    mov ax, Data
    mov ds, ax

    MAC3   

    ;Return to DOS
    mov ah,4ch ;setup the terminate process DOS service
    mov al,0 ;ERRORLEVEL takes 0
    int 21h ;return to DOS

MAIN ENDP

Code ENDS

;********************
; END CODE SEGMENT 
;********************

END Start 

And the .MAC file:

MAC1 MACRO

     mov MacVar1,bx

     ENDM


MAC2 MACRO

     mov MacVar2,cx

     ENDM



MAC3 MACRO

     mov ax, MacData
     mov ds, ax

     MAC1
     MAC2

     mov ax, Data
     mov ds, ax

     ENDM



;********************
; DATA SEGMENT 
;********************

MacData SEGMENT

macVar1 dw ?
macVar2 dw ?

MacData ENDS

;********************
; END DATA SEGMENT 
;********************

回答1:


For the sake of organization I wanted to use a different data segment to hold all of the variables that are only used by my macros.

That sounds like a good way to make your macros less useful and harder to use. As well as destroying performance. What if you want to use a macro with a memory operand?

If you don't actually care about 8086, and just want 16-bit code that can run on a 386 or later, then you could still use this weird idea but with FS or GS segment overrides on instructions inside your macro, instead of changing DS.

Or even use ES for 8086 compatibility, but remember it's used by string instructions.


error A20068: Cannot address with segment register

You didn't say which instructions are generating those.

; this is valid:
mov  ax, imm16
mov  ds, ax

If that's not what your syntax means to MASM, then that's your problem. If mov ax, MacData looks like a load to MASM, that's not good, but IDK why you get an error. Maybe it's trying to implicitly generate segment overrides based on where it thinks different variables are supposed to be?

See the x86 tag wiki for links to assembler manuals and lots of other stuff.


Segmented 16-bit code is not a good way to learn asm in general, IMO. Especially not learning the DOS system call API at the same time, since that's obsolete knowledge that you won't use while looking at the asm of real programs (while debugging or performance tuning). See this answer for more about how I think 16-bit code is a bad way to learn.




回答2:


As Peter Cordes said in his answer what you're doing a terrible idea. If you're going to the effort of programming in assembly language then you should be intelligently laying out your segments in order to minimize the amount of segment switching you need to do. If you ever do get a 8088-based PC then this becomes even more important because of how slow these CPUs were. Your Windows 95 laptop is at least 10 times faster than a 4.77 Mhz 8086 PC and could be 100 times faster.

In any case, your problem is that when you use a label in a memory operand the assembler needs to know what segment register to use for the instruction. You've told it, through the ASSUME directive, that CS points to the Code segment and DS points to the Data segment. However you haven't said what segment register points to the MacData segment, so the assembler doesn't know what segment register to use for the macVar1 and macVar2 operands.

The simple fix would be to change the ASSUME'd DS value when you change DS:

MAC3 MACRO
     mov ax, MacData
     mov ds, ax

     ASSUME DS:MacData

     MAC1
     MAC2

     mov ax, Data
     mov ds, ax

     ASSUME DS:Data

     ENDM

You could also change your memory operands to explicitly tell the assembler which segment register to use. This would let you make your macros more flexible so they don't have assume what DS value the rest of the code is using:

MAC1 MACRO
     mov ds:MacVar1,bx
     ENDM

MAC2 MACRO
     mov ds:MacVar2,cx
     ENDM

MAC3 MACRO
     push ds
     mov ax, MacData
     mov ds, ax

     MAC1
     MAC2

     pop ds
     ENDM


来源:https://stackoverflow.com/questions/39187494/how-to-switch-between-multiple-data-segments-in-8086-assembly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!