[ First ]  [ Previous ]  [ Next ]  [ Last ]  [ Manuals ]

 

Chapter 10.

 

Assembly Code Support



This chapter describes support for assembly language programming built into the CodeWarrior® compilers.

This chapter does not discuss the stand-alone assembler available for Win32/x86. For information on the stand-alone assembler, refer to the CodeWarrior Assembler Reference.

The sections in this chapter are:

Much of the general discussion in the first section applies to working with AMD® processors, with the exception of the assembly instructions used for illustration of the principles.


Working With Assembly Code for Win32/x86

This section describes how to use the CodeWarrior compiler's built-in support for assembly language programming, including assembler syntax form and conventions.

This chapter does not document all the instructions available in Win32/x86 assembly language. For information on Win32/x86 assembly language instructions, refer to the Intel Architecture Software Developer's Manual, Volume 2: Instruction Set Reference Manual by Intel® Corporation.

The topics in this section are:


Assembler Syntax

This section describes assembly syntax conventions. The assembly instructions you use are the standard x86 instruction mnemonics. For information on assembly support for AMD processor instructions refer to "Targeting AMD Processors."

This discussion of assembly syntax is broken up into the following sections:


The asm Keyword

To specify that a block of code in your file should be interpreted as assembly language, use the asm keyword. The asm keyword is part of both the ANSI C and C++ standards.


NOTE

To ensure that the C/C++ compiler recognizes the asm keyword, you must manipulate the ANSI Strict and ANSI Keywords Only options in the C/C++ Language settings panel. This panel and its options are fully described in the IDE User Guide or the C Compilers Reference.


Sections marked asm will compile correctly when ANSI Strict is enabled, but enabling ANSI Keywords Only disables them when compiled as C, but not as C++. The alternate form __asm, borrowed from Microsoft® Visual C++, is always supported.


Function-Level asm Syntax

You can write code to specify that an entire function is in assembly language. However, as of this writing, the compiler does not directly support function-level assembly language using the asm keyword in the declaration.

For now, function-level assembly code uses the syntax shown in Listing 10.1, where the __declspec(naked) suppresses the normal compiler prologue and epilogue code.

Function-level asm syntax:


__declspec(naked) void functionname(void)
{
    asm {
        // asm statements
    }
}


Statement-Level asm Syntax

Alternatively, assembly statement blocks within a function are also supported. In other words, you can write code that is both in function-level assembly language and statement-level assembly language.

An example of statement-level code syntax is shown in Listing 10.2.

Statement-level code syntax:


long MyFunc (void)
{
 asm {. . .} // statement blocks are supported
}

Statement-level assembler syntax has the form shown in Listing 10.3.

Statement-level assembler syntax:


asm { one or more instructions }

An asm statement can be used wherever a code statement is allowed.


NOTE

Functions that contain an asm block are only partially optimized, as the function itself will be optimized, but the optimizer will skip any asm blocks of code. See "Inline Assembly and Optimization" for more information.



General Assembly Syntax Format

Keep these tips in mind as you write assembly functions:

Each instruction must end with a new line or a semicolon (;).

Hex constants must be in C-style, not Pascal-style. For example, see Listing 10.5. Hex constant style:


mov eax, 0xABCDEF   // OK
mov eax, $ABCDEF   // ERROR

Support for binary constants is available for Microsoft MASM/Visual C++ syntax for hex and binary constants. The 0b prefix is an extension used by the CodeWarrior IDE for representing binary numbers in constants. These expressions can be written as shown in Listing 10.6. Hex and binary constants:
0aB42h == 0xab42 
10100b == 0b10100

Assembler directives, instructions, and registers are case-insensitive. For example, the two statements shown in Listing 10.7 are both correct. Case-insensitive assembler statements:
mov eax // OK
MOV EAX // OK

The Win32/x86 inline assembler supports nesting asm blocks within a function. Inline assembly code for Win32/x86 uses the syntax shown in Listing 10.8. Nothing else can follow the statement on the same line except a comment or another __asm statement. This form is useful for defining macros that have inline assembly. An asm instruction or block may be used wherever a statement is allowed.

Asm blocks within a function:


asm (single instruction )
asm { multiple instructions}
__asm single instruction
__asm statement __asm statement


NOTE

Variable references by inline assembly instructions used to be forced into memory and could not be allocated to processor registers by the optimizer. This is no longer a limitation. If no instructions reference the address of a variable, it is still a candidate for being placed in a register.


There is one more feature that may prove useful in your code development. You can also use Microsoft-style asm blocks, as in Listing 10.9.

Microsoft-style asm blocks:


void foo
{
  asm { asm mov eax, 1 asm mov eax, 2 }
}
// or, format like the line below
__asm { __asm mov eax, eax __asm mov eax, eax }

You can also use the macro-expansion form shown in Listing 10.10.

Defining __asm Blocks as C Macros:


#define my_asm_block \
 __asm { \
 __asm mov eax, 1 \
 __asm mov eax, 2 \
 }

For more details on Microsoft-style assembly statement syntax, refer to the documentation that came with your Microsoft tools, or on the web at:


http://msdn.microsoft.com


Supported Directives in Assembly

The CodeWarrior IDE supports the ALIGN, DB, DW, DD, EMIT directives in assembly code, among others:

ALIGN  
align next instruction to next DWORD  
ALIGN n  
align next instruction to n-byte boundry  
ALIGN n,m  
align next instruction to n-byte boundry, if such boundry is within m bytes
DB [byte-value]*  
directly insert bytes into instruction stream  
DD [word-value]*  
directly insert words (2-bytes) into instruction stream  
DW [dword-value]*  
directly insert dwords (4-bytes) into instruction stream  
EMIT byte  
directly insert single byte into instruction stream  
OPTIMIZE  
signals the start of optimization  
NOOPTIMIZE  
signals the end of optimization  

The compiler supports a pair of directives called OPTIMIZE and NOOPTIMIZE. When used, these signal that a block of inline assembly code should be treated as if it came from the compiler and allowed to be both scheduled and peephole optimized. These directives only affect the particular block of code in which they appear.


Creating Labels for Win32/x86 Assembly

A label can be any identifier that you have not already declared as a local variable. The name may start with an at-symbol (@), so foo, @foo, and @1 are legal names. All labels need to end in a colon. An example is shown in Listing 10.11.

Labels for Win32/x86 assembly:


void foo(void)
{
asm {
	x1: mov eax, 2 // OK, has colon
	@x2: mov eax, 2 // OK, has both @ and colon
	x3 mov eax, 2 // ERROR, Needs colon
	}
}


NOTE

The first statement in an assembly function cannot be a label that starts with @.



Using Comments in Win32/x86 Assembly

You cannot begin comments with a pound sign (#), since the preprocessor uses the pound sign. However, you can use C and C++ comments, and semicolons too. Listing 10.12 shows examples of valid comments.

Comments in Win32/x86 assembly:


mov eax, 8 # ERROR
mov eax, 8 // OK
mov eax, 8 /* OK */
mov eax, 8 ; OK 


Using the Preprocessor in Win32/x86 Assembly

You can use all preprocessor features, such as comments and macros, in the assembler. An instruction can end with a new asm keyword. This is allowed mainly for use in macros such as the example in Listing 10.13, since the preprocessor will expand everything onto one line of code.

Preprocessor use in macros:


#define ASM_MOVE \
    __asm { \
        __asm mov eax, eax \
        __asm mov edx, edx \
    }


Using Local Variables and Arguments in Win32/x86 Assembly

Assembly instructions may refer to local and global variables as operands. They can use the name of a structure, class, or union as an immediate operand that evaluates to the size of the structure. To specify the offset of a member, use the structure, union, or class name qualified with the member name, separated by a dot (.).


Local Variables in MMX Registers

Local variables can now be assigned to MMX registers. Such local variables can be used as operands to MMX and 3DNow! assembly instructions within an asm block. The compiler first assigns the variables to virtual registers, and then later they are assigned to real MMX registers as they are available.

The example in Listing 10.14 shows a variable c that is assigned to an MMX register.

Local variables in MMX registers:


inline long long paddsb(long long a, long long b)
{
	long long c;
	asm {
		movq c, a
		paddsb c, b
	}
	return c;
}

Note that there are some restrictions on this feature. A long long variable will not be assigned to a virtual MMX register if any of the following holds:

1. The address is taken with the & operator.

2. It is used in non-MMX contexts, as the variable c in the first line of Listing 10.15.

3. It is used in any C expression other than an operand to the function return statement.

In addition, note that data objects that correspond to MMX types should be declared as 64-bit integers (long long).

Yet another restriction is that local variables, like the variable c shown here, can be used as operands to MMX instructions but cannot be used in non-MMX contexts. For example, the code in the first line of Listing 10.15 will not work, since the source operand of the mov instruction is not a context in which an MMX register can be used. Note that the code in the last line of Listing 10.15 will work correctly, since an MMX register can serve as the source operand of movd.

Restrictions on local variables in MMX Registers:


mov eax, c
movd eax, c


Inlining Functions Containing Assembly

The x86 compiler is able to inline C/C++-style functions containing inline asm{} blocks. Previously, any functions that contained asm statements could not be inlined by the compiler. Using the inline keyword will now allow the desired operation in these cases.


Inline Assembly and Optimization

The Metrowerks compiler for x86 can efficiently optimize inline asm assembly code. Optimization and assembly code are no longer mutually-exclusive options.

Note that functions must return values using the C return statement. You can't just place the return value in the proper register as you normally would, since the compiler does not see this as a return.


Intrinsic Operations

Intrinsics are specific extensions to the language that allow you to quickly insert blocks of assembly code from your high-level source code.

If the __builtin_ form of an intrinsic is shown, that means that the intrinsic code will be generated even if the inlining of intrinsics is disabled in the settings panels. See "x86 Processor" for more details.

The following types of intrinsics are supported:


Allocation

These are memory allocator intrinsics. This family of functions allocate memory on the local stack. Therefore, the memory is automatically released when the function in which it is allocated exits.

Allocation Intrinsics:

 

Intrinsic
Description
_alloca  
allocate memory  
__alloca  
allocate memory  
alloca  
allocate memory  


Block Memory

These are block memory operations. These all have C-standard equivalent high-level functions you can also use.

Block Memory Intrinsics:

 

Intrinsic
Description
__builtin_memmove  
move memory  
__builtin_memcpy  
copy memory  
__builtin_memcmp  
compare memory  
__builtin_memset  
set memory  
__builtin_memchr  
locate a character in a string  
memmove  
move memory  
memcpy  
copy memory  
memcmp  
compare memory  
memset  
set memory  
memchr  
locate a character in a string  


Wide Character Block Memory

These are block memory operations for wide characters.

Wide Character Block Memory:

 

Intrinsic
Description
__builtin_wmemmove  
move memory  
__builtin_wmemcpy  
copy memory  
__builtin_wmemcmp  
compare memory  
__builtin_wmemset  
set memory  
__builtin_wmemchr  
locate a character in a string  
wmemmove  
move memory  
wmemcpy  
copy memory  
wmemcmp  
compare memory  
wmemset  
set memory  
wmemchr  
locate a character in a string  


Strings

These intrinsics are used for strings. These all have C-standard equivalent functions you can also use.

Strings Intrinsics:

 

Intrinsic
Description
__builtin_strcpy  
string copy  
__builtin_strcmp  
string compare  
__builtin_strlen  
string length  
strcpy  
string copy  
strcmp  
string compare  
strlen  
string length  


Wide Character Strings

These intrinsics are used for wide strings.

Wide Character Intrinsics:

 

Intrinsic
Description
__builtin_wcscpy  
string copy  
__builtin_wcscmp  
string comparison  
__builtin_wcslen  
string length  
wcscpy  
string copy  
wcscmp  
string comparison  
wcslen  
string length  


Floating-Point Math

These instrinsics are for floating-point math operations. These math functions all have equivalent high-level calls in the C Standard library implementations. Refer to math.h for parameter syntax. The file is installed with the CodeWarrior IDE and can easily be found using the Find feature of Windows®.

Floating-Point Math:

 

Intrinsic
Description
__builtin_sin  
take the sine of a number  
__builtin_cos  
take the cosine of a number  
__builtin_tan  
take the tangent of a number  
__builtin_atan  
take the arc tangent of a number  
__builtin_atan2  
take the arc tangent of a number  
__builtin_acos  
take the arc cosine of a number  
__builtin_asin  
take the arc sine of a number  
__builtin_log10  
take the log base 10 of a number  
__builtin_log  
take the log of a number  
__builtin_exp  
computer the exponential of a number  
__builtin_pow  
raise a number to a power  
__builtin_sqrt  
take the square root of a number  
__builtin_fabs  
take the absolute value of a number  
sin  
take the sine of a number  
cos  
take the cosine of a number  
tan  
take the tangent of a number  
atan  
take the arc tangent of a number  
atan2  
take the arc tangent of a number  
acos  
take the arc cosine of a number  
asin  
take the arc sine of a number  
log10  
take the log base 10 of a number  
log  
take the log of a number  
exp  
computer the exponential of a number  
pow  
raise a number to a power  
sqrt  
take the square root of a number  
fabs  
take the absolute value of a number  


x86-Specific Hardware Operations

You can find documentation on the World Wide Web for the intrinsics in Table 10.7, including the following page:


http://msdn.microsoft.com/library/devprods/vs6/visualc/vccore/_crt__outp.2c_._outpw.2c_._outpd.htm

These correspond with the built-in IN/OUT instructions on the x86 processor in byte, word, and double word sizes. They are setup so that if a compile time constant is used, they will turn into the constant forms of the instructions, otherwise they will be the forms using the EDX register.


NOTE

These intrinsics will probably not work from code running in Windows NT®, since most port access is protected. These are most useful for engineers writing drivers that run inside an operating system where direct port access is allowed.


x86 Intrinsics:

 

Intrinsic
_outp  
_outpw  
_outpd  
_inp  
_inpw  
_inpd  

 


Working with Assembly Code for AMD Processors

Most of the same principles apply for x86 assembly syntax as for AMD syntax. However, the available assembly instructions for x86 processors differ from AMD processors.

For information on Advanced Micro Devices, Inc. (AMD) 3DNow! Technology, refer to the 3DNow! Technology Manual, published by AMD (publication # 21928). Also, see "Targeting AMD Processors" for specific information about getting the most from these processors.

 


[ First ]  [ Previous ]  [ Next ]  [ Last ]  [ Manuals ]

Visit the Metrowerks website at: http://www.metrowerks.com
For assistance contact Metrowerks Technical Support at: cw_support@metrowerks.com
Copyright © 2000, Metrowerks Corp. All rights reserved.

Last updated: July 21, 2000