在 MASM 中使用 32 位寄存器而不更改默认段定义大小 [英] Using 32 bit registers in MASM without changing the default segment definition size

查看:14
本文介绍了在 MASM 中使用 32 位寄存器而不更改默认段定义大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的代码对于 8086 & 来说太慢了80286 处理器,所以我决定在我的实模式代码中使用 32 位寄存器和指令.

My code is too slow for 8086 & 80286 processors so i've decided to make use of 32 bit registers and instructions in my real mode code.

我知道我真正需要做的就是在个别指令前加上 66h,但是如果您不在汇编文件的最顶部包含 .386 指令,则 MASM 不接受 386 个寄存器.

I know that all I really need to be able to do is prefix indiviual instructions with 66h, but 386 registers aren't accepted by MASM if you don't include the .386 directive at the very top of the assembly file.

这样做后,我发现我的程序不再运行,即使我没有使用任何 386 寄存器.它挂在黑屏上,然后 DOSBox 崩溃.这种行为通常表明我的程序中出现堆栈崩溃和内存损坏.

After doing this, I found that my program no longer functioned, even if i'm not using any 386 registers. It hangs at a black screen and then DOSBox crashes. This is behavior typically indicative of a stack crash and memory corruption in my program.

在 MASM 5.10(我使用的版本)的文档中,我找到了以下信息:如果您在 .MODEL 指令之前使用 .386 指令,则段定义定义了 32 位段.如果要启用具有 16 位段的 80386 处理器,则应在 .MODEL 指令之后给出 .386 指令."

In the documentation for MASM 5.10 (the version I use) I found this information: "If you use the .386 directive before the .MODEL directive, the segment definitions defines 32-bit segments. If you want to enable the 80386 proces­sor with 16-bit segments, you should give the .386 directive after the .MODEL directive."

我很确定这是我的问题,我需要包含一个 .MODEL 指令将确保段保持 16 位.在使用 .386 指令之前,我尝试在我的主程序集文件中包含所有列出的 .MODEL 指令(文档将它们称为最常见的模型).它们都会产生错误,我认为这可能是由于我没有在组成我的程序的其他十几个程序集文件中的任何一个中包含 .MODEL 指令造成的.我只想继续使用默认的 .MODEL,不管它是什么.

I'm pretty sure that's my issue here, I need to include a .MODEL directive that will ensure that segments remain 16-bit. I tried including all of the listed .MODEL directives (documentation refers to them as the most common models) in my main assembly file before using the .386 directive. They all produce errors, which I believe may be caused by the fact that i'm not including the .MODEL directive in any of the other dozen assembly files that make up my program. I just want to continue using the default .MODEL, whatever it may be.

直到现在我才需要使用 .MODEL 指令,文档没有提到默认使用哪个指令,或者在使用 .386 时哪个保持 16 位段完整.

I have never needed to use a .MODEL directive until now, the documentation doesn't mention which is used by default, or which keeps 16-bit segments intact when .386 is used.

.MODEL SMALL、.MODEL MEDIUM 和 .MODEL COMPACT 都会产生许多链接器错误,如下所示: error L2002: fixup overflow at 0016 in segment CODE pos: 1FA Record type:48A8

.MODEL SMALL, .MODEL MEDIUM, and .MODEL COMPACT all produce many linker errors that look like this: error L2002: fixup overflow at 0016 in segment CODE pos: 1FA Record type:48A8

.MODEL LARGE 和 .MODEL HUGE 可以很好地组装和链接,但几帧后我的程序崩溃了,一些垃圾转储到了视频内存中,可能是堆栈崩溃.同样,目前我没有在我的其他十几个程序集文件中的任何一个中包含 .MODEL 指令.

.MODEL LARGE, and .MODEL HUGE assemble and link just fine, but crash my program a few frames later with some garbage dumped into video memory, probably a stack crash. Again i'm not including .MODEL directives in any of my other dozen assembly files at the moment.

我想要的是偶尔能够使用 386 个寄存器和指令,但除此之外,我希望程序的行为与以往完全相同.处理所有段,例如 16 位.

What I want is to occasionally be able to use 386 registers and instructions, but otherwise I want the program to behave exactly the same as it always has. Treating all segments and such as 16-bit.

这是我的主要程序集文件,我不太确定这是哪个型号.大,也许?没有一个段大于 64k,所以可能不会.有一个堆栈段和一个代码段,但有几个数据段.所有这些都是公开的,并在构成程序的程序集文件中共享.

Here is my main assembly file, i'm not quite sure which model this is. Large, maybe? No single segment is larger than 64k, so maybe not. There is a single stack segment and a single code segment, but several data segments. All of which are public and shared throughout the assembly files that make up the program.

theStack SEGMENT STACK                                                     

 db 64 dup ('THESTACK') ;512 byte stack  

 theStack ENDS                                                              





 varData SEGMENT PUBLIC                                                                                

 INCLUDE const.inc     ;global constants

 PUBLIC fCntr

 fCntr db 0            ;A frame counter used to delay animations.

 varData ENDS                                                               






 frame SEGMENT PUBLIC                                                       

 db scrArea dup (247d)  ;64,000 byte frame buffer

 frame ENDS                                                                 






 field SEGMENT PUBLIC                                                       

 db 65535 dup ('F')     ;64k buffer that holds up to 32,768 tile indexes

 field ENDS                                                                 







 sprites SEGMENT PUBLIC                                                     

 db 65535 dup ('S')     ;64k buffer for animated spites

 sprites ENDS                                                                                                                           






 code SEGMENT PUBLIC

 EXTRN SET_VGA_256:PROC,INIT_DISK_VARS:PROC,INIT_AREA:PROC,CALC_DELAY:PROC
 EXTRN HANDLE_INPUT:PROC,UPDATE_SPRITES:PROC,DRAW_SPRITES:PROC
 EXTRN DRAW_FIELD:PROC,WRITE_FRAME:PROC,FRAME_DELAY:PROC,EXIT2DOS:PROC
 EXTRN DBG:PROC                    

 assume cs:code,ds:varData                                              

 main PROC                                                                  

 start:                                                                      

    mov ax, varData                            
    mov ds, ax               ;Load the variable segment into ds                                            
    cld                      ;ensure that string operations auto-increment



    call SET_VGA_256         ;Set the video mode to 320x200 256 colors.
    call INIT_DISK_VARS      ;Setup hard drive access variables
    call INIT_AREA           ;Build the area into memory from data files
    call CALC_DELAY          ;calculate the frame delay using the RTC



LOOP_TILL_ESC:
    call HANDLE_INPUT        ;Handle user input.
    call UPDATE_SPRITES      ;bounds check then move the sprites
    call DRAW_FIELD          ;draw the tiles that make up the play field 
    call DRAW_SPRITES        ;draw all currently visible sprites
    call WRITE_FRAME         ;Write the frame buffer to video memory.
    inc fCntr                ;increment the frame counter
    call FRAME_DELAY         ;delay for the specified number of milliseconds
    cmp bp, 1                ;Was the Esc key pressed?
    jne LOOP_TILL_ESC        ;If not, loop back through the main program.
    call EXIT2DOS            ;If so, return to DOS.



 main ENDP                                                                  

 code ENDS                                                                  

 END start            

这里有一个简单的程序,如果使用 .386 就会中断.它应该用粉红色像素填充屏幕,但它却挂在黑屏上并导致 DOSBox 崩溃.

And here's a simple program that breaks if .386 is used. It's supposed to fill the screen with pink pixels, but instead it hangs at a black screen and crashes DOSBox.

.MODEL SMALL
.386

theStack SEGMENT STACK                                                     

db 64 dup ('THESTACK')   

theStack ENDS                                                              




code SEGMENT PUBLIC

assume cs:code,ds:varData                                              

main PROC                                                                  

start:                                                                      

    mov ax, varData                            
    mov ds, ax                   ;Load the variable segment into ds                                            
    cld                          ;ensure that string ops auto-increment



    xor ah, ah                   ;select set video mode function
    mov al, 13h                  ;320x200 256 colors
    int 10h                      ;video mode set 

    mov di, 0a000h               
    mov es, di
    xor di, di                   ;es:di -> vga pixel buffer
    mov ah, 64d
    mov al, ah                   ;ah & al -> pink color index byte
    mov cx, 32000d               ;writing 32,000 words
    rep stosw                    ;fill the screen with pink pixels

ESC_LOOP:
    in al, 60h
    cmp al, 1
    jne ESC_LOOP                 ;delay till escape key is pressed

    mov ax, 40h
    mov es, ax                   ;access keyboard data area via segment 40h
    mov WORD PTR es:[1ah], 1eh   ;set the kbd buff head to start of buff
    mov WORD PTR es:[1ch], 1eh   ;set the kbd buff tail to same as buff head
                                 ;now the keyboard buffer is cleared.
    xor ah, ah                   ;select video mode function
    mov al, 3                    ;select 80x25 16 colors
    int 10h                      ;restore VIDEO back to text mode




 mov ah, 4ch                     ;Terminate process DOS service
 xor al, al                      ;Pass 0 to ERRORLEVEL
 int 21h                         ;Control returns to DOS

 main ENDP                                                                  

 code ENDS                                                                  

 END start                             

推荐答案

您对问题的描述并非 100% 正确,但您的粉红色"示例源是充分解释问题的好例子.

Your description of problem is not 100% correct, but your "pink" sample source in question is good example to explain it fully.

.MODEL 指令与 .CODE、.CONST、.DATA 一起属于 简化 段指令", .DATA?, .FARDATA, .FARDATA?, .STACK.

The .MODEL directive belongs to the "simplified segment directives", together with .CODE, .CONST, .DATA, .DATA?, .FARDATA, .FARDATA?, .STACK.

因此,在工作方式和 16b DOS 可执行文件中使用这些的一种方法是这样的:

So one way of using these in working fashion and 16b DOS executable is like this:

.MODEL SMALL
.386

.STACK 100h

.DATA
x   DB  1

.CODE
start:
    mov     ax,@DATA
    mov     ds,ax
    movzx   eax,BYTE PTR [x]

    mov     ah,4Ch
    int     21h
END start

仅使用简化指令,.CODE 将定义名为 _TEXT 的代码段,它是 16b 实模式代码段(感谢 .386 指令放在 .MODEL SMALL 指令之后.

Using only the simplified directives exclusively, the .CODE will define code segment named _TEXT, which is 16b real mode code segment (thanks to the .386 directive being put after .MODEL SMALL directive).

您的粉红色"示例不使用简化的段指令,而是完整的指令,那么您必须在代码段定义中指定它用于实模式,就像在下一个固定源中一样,它将首先用粉红色填充屏幕(使用 16b 寄存器),然后在一些带有青色的键之后(在实模式下使用 32b 寄存器).

Your "pink" example doesn't use the simplified segment directives, but full ones, then you must specify in the code segment definition it is for real mode, like in next fixed source, which will fill screen first with pink colour (using 16b registers), and then after some key with cyan colour (using 32b registers in real mode).

我必须将 USE16 添加到 code SEGMENT 指令,以正确设置它,然后生成的 32b 指令以正确的方式为 16b 实模式添加前缀(即与 32b 保护模式不同的另一种方式).

I had to add USE16 to the code SEGMENT directive, to set it up correctly, then the produced 32b instructions are prefixed in correct way for 16b real mode (i.e. the other way than in 32b protected mode).

我确实进一步测试了当您将显式代码段定义与简化的 .CODE 指令混合时会发生什么,令人惊讶的是(对我而言)最终的 .exe 有两个代码段,即使使用 .MODEL SMALL 模型... 所以dotCode"段中的测试程序只能通过FAR调用才能到达.至少 .CODE 段被正确分配为 16b 段,因此生成的程序集按预期工作.

I did further test what will happen when you mix that explicit code segment definition with simplified .CODE directive, and surprisingly (to me) the final .exe has two code segments, even with .MODEL SMALL model... So the test procedure in "dotCode" segment can be reached only through FAR call. At least the .CODE segment is correctly assigned as 16b segment, so the produced assembly works as expected.

固定示例(使用 TASM 4.1 + TLINK 测试,仅使用文件名运行,无选项,应生成 ASM -> OBJ -> EXE 文件):

Fixed example (tested with TASM 4.1 + TLINK, just run with name of file and no options, ASM -> OBJ -> EXE files should be produced):

.MODEL SMALL
.386

theStack SEGMENT USE16 STACK

db 64 dup ('THESTACK')

theStack ENDS

; test of simplified code segment directive
.CODE
testDotCode PROC
    mov     eax,12345678h
    retf
testDotCode ENDP
ENDS

code SEGMENT USE16 PUBLIC

assume cs:code, ss:theStack

main PROC
    call    FAR PTR testDotCode ; test code inside simplified code segment definition
    ; with experiment I find out, that even with ".MODEL SMALL" the TASM+TLINK will
    ; put the testDotCode subroutine into new "_TEXT" code segment!
    ; So only FAR call + retf works to access it.

    cld                         ; ensure that string ops auto-increment
    mov     ax, 13h             ; select set video mode function: 13h 320x200 256 colors
    int     10h                 ; video mode set

    mov     di, 0a000h
    mov     es, di              ; es = VRAM segment

    ; original 16b test code - fill screen with pink
    xor di, di                  ;es:di -> vga pixel buffer
    mov ah, 64d
    mov al, ah                  ;ah & al -> pink color index byte
    mov cx, 32000d              ;writing 32,000 words
    rep stosw                   ;fill the screen with pink pixels

    ; wait for any key
    xor     ah,ah
    int     16h

    ; 32b test code to validate ".386" setup success in real mode
    xor     di, di              ; es:edi -> vga pixel buffer
    mov     eax, 34343434h      ; eax = 4x cyan color
    mov     ecx, 320*200/4      ; full screen fill
    rep stosd                   ; fill the screen with pink pixels

    ; wait for any key
    xor     ah,ah
    int     16h

    ; restore text mode (3)
    mov     ax,3                ; select video mode: text 80x25 16 colors
    int     10h

    mov     ax,4C00h            ; terminate DOS process with 0 ERRORLEVEL
    int     21h
main ENDP

code ENDS

END main

我主要使用此网页作为这些详细信息的来源:http://www.c-jump.com/CIS77/ASM/Directives/lecture.html#D77_0070_code_directive

I used mostly this web page as source for these details: http://www.c-jump.com/CIS77/ASM/Directives/lecture.html#D77_0070_code_directive

不幸的是,这个答案并没有完全替代正确的 TASM/MASM 文档,只是(希望完整)解释导致您的问题的原因.

And this answer is not exhaustive replacement of proper TASM/MASM documentation, unfortunately, just (hopefully complete) explanation what caused your problems.

这篇关于在 MASM 中使用 32 位寄存器而不更改默认段定义大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆