Embedding assembly code into C/C++ programs with Watcom C/C++

Why the _asm keyword is not supported.

Microsoft and Borland have an _asm keyword that is provided with their 
code, that allows in-line assembly code to coexist within a C or C++ 
program.  Instead, Watcom uses a #pragma statement to declare a section 
of assembly code as an auxiliary function.  The developer can specify 
parameters to be passed to this code, which registers they go into, and 
what registers will be modified. Watcom prefers to use this 
implementation, and does not support the _asm implementation, for the 
following reasons:

1. The _asm directive does not tell the code generator what registers 
have been modified.  Therefore, the optimizer cannot exploit maximum 
speed advantages.  Assembly code is usually written for speed-critical 
sections of a program, and having to save and restore all registers when 
calling the routine
would add program overhead where it is least desirable. Microsoft and 
Borland turn off optimizations around assembly code, but Watcom finds 
out which registers are modified to take advantage of maximum 
optimization.

 2. The pragma statement is much more flexible than the _asm statement.  
It allows you to tell the code generator which registers are modified by 
the assembly language.  It also lets you define 'parameters' to your 
routine.  For example, using a pragma, you could do something like the 
following:

#pragma aux foo= "int 21" parm [ah] [ es bx ];

 	then

foo( 1, &p );

 	will automatically put the parameters 1 into ah and &p into es:bx.

You could also call "foo( 2, &q )"

Using the _asm statement, you cannot create generalized inline assembly 
like this.  The examples would have to be coded separately, as follows:

 	ASM( mov ah,1 )
 	ASM( mov es,seg p );
 	ASM( mov bx,offset p );
 	ASM( int 21 );

This would only work if 'p' were a static/extern variable, not an auto.

3. #pragma's are quite easy to create.  The following creates a DOS 
assembly function to set the screen to mode 4:

void mode4( void );
#pragma aux mode4 =	\
	"mov AH,0",	\
	"mov AL,4",	\
	"int 10H"		\
	modify [ AH,  AL ];

This function can be called by using "mode4();" anywhere in a program.

4. The code is kept more portable.  All of the machine dependent code is 
kept in callable auxiliary functions, with an explicit interface.  This 
makes the code very easy to port to other processors, which is 
especially important with the movement toward RISC-based PCs.

5. Pragmas should generally be needed only for specialty processor-
specific functions, such as "lidt" or "out".  In this case, it is easier 
to code the instruction once, and call it using a function.

At this time, the #pragma auxiliary functions will only take 128 bytes 
of code at a time.  For existing programs that use large amounts of 
assembly code, it is recommended that this code be put into a separate 
assembly language file, and be assembled as a function.  The optimizer 
will then expand this code inline, and the developer should notice no 
difference in performance.
