Search code examples
windowsassemblymemorydostasm

DOS Console data memory access when 32bit registers are accessible assemblery


I'm working on a project in TASM assembly and I have problems outputing color to specific cells of the DOS console when I use 32 bit registers in assembler (with .386).

Here's an example of how I would normally do that:

BX loc of cell,
AH color / char of cell

mov ah , 01000000b ; Color Red to ah
mov ax,0b800h ; memory location of the console 
mov es,ax ; to es 
mov es:[bx] , ah ; mov data from ah to the cell of bx 

this works but when I do .386 at the start to make it 32 bit this code stops working ... anyone know a way to fix the problem ? SHORT : The code need to set Color to cell . works without .386 and stops working with .386

Code segments :

.386
.Model small
.data 
 ;all my data 
 .code 
  Start:
  ; all the code in there also the output code snippet I showed 
 end start 

Fix by Ped7g : put the line .386 inside the .code segment

Fix by Margaret Bloom : add USE16 modifier to MODEL directive

Both are working. Thanks for the help

tasm 32 bit


Solution

  • If you don't specify the attributes of the code segment(s) explicitly the use of the .386 directive will set the default operand side to 32-bit.

    Quoting the TASM manual:

    Note that you can specify the model modifier in two places, for compatibility with MASM 5.2. If you don't use a model specifier, Turbo Assembler as.sumes the NEARSTACK modifier, and USE32 (if the 80386 or 80486 processor is selected).

    This doesn't mean that you are allowed to use 32-bit registers1 but that the assembler will emit the instructions in a "specular" way.

    All code in an x86 machine has a default operand size.
    When running in 32-bit it is 32 bits, when running in 16-bit it is 16 bits (64-bit is a bit more involved, it is still 32 bits but can be overridden with the REX.W prefix).

    The default operand size determines the default size of the immediate operands, i.e. the number of bytes that follow an opcode of an instruction that expects a value.

    Instructions like mov ax, 0b800h and mov eax, 0b800h are encoded the same way: with the opcode B8.
    After this opcode, it follows the immediate operand of 16 or 32 bits.
    The specific size depends on the default operand size.

    To access the "other" size, i.e. specify a 16-bit version of an instruction in 32-bit code and vice-versa, an operand size override prefix exists (value 66).

    Put on a table

                        +-----------------------------------------+
                        |           Default operand size          | 
    +-------------------+---------------------+-------------------+ 
    |Instruction        |      16             |        32         |
    +-------------------+---------------------+-------------------+
    |                   |                     |                   |
    |mov ax, 1234h      |     B8 34 12        |    66 B8 34 12    |  
    |                   |                     |                   |
    |mov eax, 12345678h |  66 B8 78 56 34 12  |   B8 78 56 34 12  |   
    |                   |                     |                   |
    +-------------------+---------------------+-------------------+
    

    See how mov ax, 0b800h is encoded with 66 B8 when the assembler assumes a default operand size of 32-bit?
    And that when executed in a 16-bit code the 66 B8 is decoded has having a 32-bit immediate?

    This screw up the decoding of subsequent instructions.

    The snipped posted when assembled as 32-bit code but executed as 16-bit code result in:

    00000000  B440              mov ah,0x40
    00000002  66B800B88EC0      mov eax,0xc08eb800
    00000008  26678827          mov [es:edi],ah
    

    How to solve this problem

    Give each code segment the code-size attribute explicitly or set the default one with the MODEL directive.
    For example, if you use a SMALL memory model:

    .MODEL USE16 SMALL 
    

    1 You always are as far as the CPU is concerned, it's just that TASM refuses to assemble instructions not compliant with the processor family chosen.