The environment is MS-DOS system.
I have a simple h.asm code for hello world output using dos 9# call
.386
DATA SEGMENT USE16
MSG DB 'HelloWorld!$'
DATA ENDS
CODE SEGMENT USE16
ASSUME CS:CODE,DS:DATA
BEG: MOV AX,DATA
MOV DS,AX
MOV DX,OFFSET MSG
MOV AH,9
INT 21H
CODE ENDS
END BEG
Using MASM command:
masm h.asm
I have got the file h.obj. Then link h.obj
I have got the h.exe file.
Now I want to obtain the .com file of the .exe file using command
exe2bin h.exe
, but the result I received is:
File cannot be converted
What went wrong?
The program exe2bin
requires that the .EXE file you're converting either has an entry point of 0000:0100 or no entry point at all. In the former case the the executable can't have any segment relocations, and the result is normally something that can be loaded by MS-DOS as a .COM file. In addition the .EXE file can't have a stack, and must have a load size 64K or less.
The direct reason why exe2bin
is failing is because you have entry point of something like 0001:0000
, where the segment part is relative to the start of the executable and adjusted by the location in memory where MS-DOS loads the executable. (So for example if MS-DOS loads the executable at 1234:0000, then entry point is 1235:0000.) This isn't suitable for a .COM file since MS-DOS simply copies the .COM file into memory and jumps an offset 0100 in the segment. (So if MS-DOS loads the .COM file at 1234:0000, it jumps to 1234:0100).
Another problem with your executable is that even if it used the correct entry point it also a has a segment relocation. The MOV AX, DATA
instruction references the segment DATA
, and the value of DATA
depends on where MS-DOS loads the executable. This requires a relocation in the executable so MS-DOS knows to modify the value with the correct segment value when it loads it.
To make an executable that will both work with exe2bin
and produce a usable .COM file you need the following things:
ORG 100h
directive at the start of your programORG 100h
directive so that it's located at offset 100h.END
directive so it becomes the entry point.ORG 100h
directive (otherwise it will be discarded by exe2bin
).ORG 100h
directive. In other words everything must live in the same 64K segment.For example, you can turn your program into something can produce a working .COM file by rewriting it like this:
.386
; Requirements implemented
CODE SEGMENT USE16 ; 4.
ORG 100h ; 1.
ASSUME CS:CODE,DS:CODE,ES:CODE,SS:CODE ; 4.
BEG: MOV DX,OFFSET MSG ; 2.
MOV AH,9
INT 21H
MOV AX,4C00H ; exit the program
INT 21H
MSG DB 'HelloWorld!$' ; 4. 5.
CODE ENDS
END BEG ; 3.
Note that I've added an MS-DOS call to exit the program, otherwise your code would've continued to execute instructions after printing the message. In your original executable this would've been random uninitialized data, in the program above it would be the string HelloWorld!$
as interpreted as x86 machine code.
As rcgldr posted you can skip the exe2bin
step and have the linker produce a .COM file directly by using the /TINY
option. The same rules given above for creating a .COM file apply when using this option.