NASM Forum > Using NASM
Why doesn't stuff work right in DOS EXEs, but does work right in my DOS COMs?
(1/1)
ben321:
So I took my ASM code for a COM file, which I can create directly in NASM, making sure to start it with ORG 0x100 so that it has the offsets are calculated correctly for a COM file. And I then converted it to an EXE by first removing the ORG statement, and then adding statements to set up 3 sections (code section for the code, then data section for any embedded data in the EXE, and finally a stack section so DOS knows how much stack to allocate).
But there's a problem. The EXE isn't working right. In the case of my test program, it's supposed to display an image. The COM file works perfect for this. The EXE file only displays a corrupted picture. It appears that memory address 0xB8000 (segment 0xB800 offset 0), which SHOULD be the start of 4-color CGA graphics mode, is only the start of the graphics memory for COM files. It seems that when using a DOS EXE, the EXE loader in DOS rearranges the memory mapping for video RAM, so that VRAM no longer starts where it should in the memory address space. How do I fix this?
ben321:
I realized what was wrong now. I had assumed that the DOS EXE loader would have automatically read the data segment address from the EXE into the DS register, but (at least in DosBox, where I was testing my program) it didn't. I had to have my program set the DS register, using "mov ax,data" followed by "mov ds,ax". In COM files this isn't a problem, because everything is in a single segment, code and data.
Frank Kotler:
Hi again ben321,
It has been a very long time since I did DOS files. I wouldn't have remembered whether the OS would set your segment registers or whether you have to do it, but you are correct. This stuff is "supposed to work" and I'm glad you got it to!
Best,
Frank
fredericopissarra:
Ok... On MS-DOS, COM files follows the TINY memory model, where CS=DS=ES. For EXE files any model can be used, so, there are no garantees about DS and ES and they must be initialized. SS is initialized by DOS to use its stack (the linker will warn you: "No stack", but DOS stack is used!). Here's two small programs to show you the registers on entry:
--- Code: ---; SHOW.ASM
; This is a COM executable:
;
; nasm -f bin show.asm show.com
;
bits 16
%macro dword2hexstr 2
lea di,[%1]
mov eax,%2
call dw2hex
%endmacro
%macro word2hexstr 2
lea di,[%1]
mov ax,%2
call w2hex
%endmacro
org 0x100
; Save modified registers
mov [cs:oldESP],esp
mov [cs:oldDS],ds
push cs
pop ds
mov [oldEBX],ebx
mov [oldEDI],edi
; Prepare string
lea di,[_eax]
call dw2hex
dword2hexstr _ebx, [oldEBX]
dword2hexstr _ecx, ecx
dword2hexstr _edx, edx
dword2hexstr _esi, esi
dword2hexstr _edi, [oldEDI]
dword2hexstr _ebp, ebp
dword2hexstr _esp, [oldESP]
word2hexstr _cs, cs
word2hexstr _ds, [oldDS]
word2hexstr _es, es
word2hexstr _ss, ss
word2hexstr _fs, fs
word2hexstr _gs, gs
lea dx,[msg]
mov ah,9
int 0x21
mov ax,0x4c00
int 0x21
; Entry: DS:DI points to buffer,
; AL = hexvalue to convert
; Destroys: BX, DI (advances)
b2hex:
movzx bx,al
shr bx,4
mov bl,[bx+hextbl]
mov [di],bl
inc di
movzx bx,al
and bx,0x0f
mov bl,[bx+hextbl]
mov [di],bl
inc di
ret
w2hex:
xchg al,ah
call b2hex
xchg al,ah
call b2hex
ret
dw2hex:
push eax
shr eax,16
call w2hex
pop eax
call w2hex
ret
hextbl:
db `0123456789ABCDEF`
oldEBX: dd 0
oldEDI: dd 0
oldESP: dd 0
oldDS: dw 0
; EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
; ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000
; CS=0000 DS=0000 ES=0000 FS=0000 GS=0000
msg: db `EAX=`
_eax: db `00000000`
db ` EBX=`
_ebx: db `00000000`
db ` ECX=`
_ecx: db `00000000`
db ` EDX=`
_edx: db `00000000\r\n`
db `ESI=`
_esi: db `00000000`
db ` EDI=`
_edi: db `00000000`
db ` EBP=`
_ebp: db `00000000`
db ` ESP=`
_esp: db `00000000\r\n`
db `CS=`
_cs: db `0000`
db ` DS=`
_ds: db `0000`
db ` ES=`
_es: db `0000`
db ` SS=`
_ss: db `0000`
db ` FS=`
_fs: db `0000`
db ` GS=`
_gs: db `0000\r\n$`
--- End code ---
--- Code: ---; SHOWEXE.ASM
;
; nasm -fobj showexe.asm -o showexe.obj
; tlink -Tde showexe.obj,showexe.exe
bits 16
%macro dword2hexstr 2
lea di,[%1]
mov eax,%2
call dw2hex
%endmacro
%macro word2hexstr 2
lea di,[%1]
mov ax,%2
call w2hex
%endmacro
section _TEXT
..start:
; Save modified registers
mov [cs:oldESP],esp
mov [cs:oldDS],ds
push _DATA
pop ds
mov [oldEBX],ebx
mov [oldEDI],edi
; Prepare string
lea di,[_eax]
call dw2hex
dword2hexstr _ebx, [oldEBX]
dword2hexstr _ecx, ecx
dword2hexstr _edx, edx
dword2hexstr _esi, esi
dword2hexstr _edi, [oldEDI]
dword2hexstr _ebp, ebp
dword2hexstr _esp, [oldESP]
word2hexstr _cs, cs
word2hexstr _ds, [oldDS]
word2hexstr _es, es
word2hexstr _ss, ss
word2hexstr _fs, fs
word2hexstr _gs, gs
lea dx,[msg]
mov ah,9
int 0x21
mov ax,0x4c00
int 0x21
; Entry: DS:DI points to buffer,
; AL = hexvalue to convert
; Destroys: BX, DI (advances)
b2hex:
movzx bx,al
shr bx,4
mov bl,[bx+hextbl]
mov [di],bl
inc di
movzx bx,al
and bx,0x0f
mov bl,[bx+hextbl]
mov [di],bl
inc di
ret
w2hex:
xchg al,ah
call b2hex
xchg al,ah
call b2hex
ret
dw2hex:
push eax
shr eax,16
call w2hex
pop eax
call w2hex
ret
oldESP: dd 0
oldDS: dw 0
section _DATA
hextbl:
db `0123456789ABCDEF`
oldEBX: dd 0
oldEDI: dd 0
; EAX=00000000 EBX=00000000 ECX=00000000 EDX=00000000
; ESI=00000000 EDI=00000000 EBP=00000000 ESP=00000000
; CS=0000 DS=0000 ES=0000 FS=0000 GS=0000
msg: db `EAX=`
_eax: db `00000000`
db ` EBX=`
_ebx: db `00000000`
db ` ECX=`
_ecx: db `00000000`
db ` EDX=`
_edx: db `00000000\r\n`
db `ESI=`
_esi: db `00000000`
db ` EDI=`
_edi: db `00000000`
db ` EBP=`
_ebp: db `00000000`
db ` ESP=`
_esp: db `00000000\r\n`
db `CS=`
_cs: db `0000`
db ` DS=`
_ds: db `0000`
db ` ES=`
_es: db `0000`
db ` SS=`
_ss: db `0000`
db ` FS=`
_fs: db `0000`
db ` GS=`
_gs: db `0000\r\n$`
--- End code ---
Running both:
--- Code: ---C:\Work> show
EAX=00000000 EBX=00000000 ECX=000000FF EDX=00000194
ESI=00000100 EDI=0000FFFE EBP=0000091C ESP=0000FFFE
CS=0192 DS=0192 ES=0194 SS=0194 FS=0000 GS=0000
C:\Work> showexe
EAX=00000000 EBX=00000000 ECX=000000FF EDX=00000194
ESI=00000000 EDI=00000000 EBP=0000091C ESP=C67C1818
CS=01A4 DS=C0C2 ES=0194 SS=01A4 FS=0000 GS=0000
--- End code ---
Don't take for granted DS, ES or SS on EXE files. And don't take for granted SS on COM and EXE files.
And any other GPRs cannot be taken for granted as well.
Navigation
[0] Message Index
Go to full version