| < Day Day Up > |
|
Assembly language routines can generally be added to C++ programs in two ways: by embedding the assembly language statements directly in a C++ function, and by incorporating an object file created by an assembler in your project. In this section I will show you how to do both for the PC and Macintosh computing platforms.
As with just about any decision you will make in your programming career the one regarding the use of assembly language in your C++ program should not be made willy-nilly. Some things to consider include the following:
Efficient Processor Usage - Old assembly language routines may not use modern processors efficiently. As a rule, new processor versions introduce new instructions. Old versions of assembly language will most certainly not support these new instructions.
Code Optimization - Face it, compilers generate better optimized code than do humans. If your reasons for using assembly include the one 'I can do it better' I recommend letting the compiler have a go at it first.
Portability - Adding assembly to your C++ program will lock it into a specific processor and severely limit your code portability.
Maintenance - As time passes, assembly routines embedded directly in your C++ code will have to be upgraded more frequently than the C++ instructions to take advantage of new processor features.
Many implementation aspects of the C++ language are left to the discretion of the compiler manufacturer, and how each enables the integration of assembly language into your C++ code is one of the most implementation dependent aspects of all. For example, the method used to embed assembly language directly into a C++ function differs in Metrowerks CodeWarrior Release 5 between the PC and the Macintosh versions of the compiler. Your best resource for information regarding the use of assembly within your C++ code resides somewhere in your development environment's documentation.
Assembly code can be embedded directly into the body of a C++ function by using the asm keyword. How the asm keyword is actually employed in your development environment is - you guessed it - implementation dependent. I will start first with a PC version. Example 18.5 gives the code for a header file that declares a function named doubleVal().
Listing 18.5: double.h
1 #ifndef DOUBLE_H 2 #define DOUBLE_H 3 4 int doubleVal(int d); 5 6 #endif
The doubleVal() function takes an integer argument and returns its doubled value. Example 18.6 implements the doubleVal() function with embedded assembly that targets an Intel® processor.
Listing 18.6: double.cpp
1 #include "double.h" 2 3 int doubleVal(int d){ 4 int return_val; 5 asm{ 6 mov eax, d ;move d into the eax register 7 shl eax, 1 ;shift eax bits left by 1 bit 8 mov return_val, eax ;move result into return_val 9 } 10 return return_val; 11 }
There are several important things to note in this example. First, the assembly instruction block is introduced with the asm keyword. Second, local variables and parameter names can be used as necessary in the assembly block. Also, Metrowerks CodeWarrior Release 5 allows the use of either the asm keyword or the _asm keyword.
Example 18.6 can now be used in a Win32 project. This is shown in figure 18-14.
Figure 18-14: Win32 Project Using Inline Assembly Language
The doubleVal() function is used in a main() function and the results of running the project are shown in figure 18-15.
Figure 18-15: Results of Running the Inline Assembly Project
This section will show you how to create a stand-alone assembly language routine, generate an object file, and use it in a C++ project. The target platform used for this demonstration is Win32. The assembly language file is assembled with Microsoft Macro Assembler (MASM) version 6.14 and used in a C++ Win32 project created using Metrowerks CodeWarrior Release 5.
The steps required to create an object file from assembly language and add it to a C++ project are listed below and illustrated in figure 18-16.
Step 1 - Create assembly language file with a text editor and save it with the .asm extension,
Step 2 - Assemble the file to create a Portable Executable/Common Object File Format (PE/ COFF) object file,
Step 3 - Create a C++ project using the development system of your choice,
Step 4 - Create a header file that declares the name of the function contained in the object file. The function declaration must be declared to have extern 'C' language linkage.
Step 5 - Add the object file to the C++ project,
Step 6 - Compile and run the project and do a victory dance!
Figure 18-16: Adding Assembly Object File to C++ Project
Using your favorite text editor create the assembly language file and save it with a .asm extension. Example 18.7 gives the assembly listing for a file named double.asm that implements an assembly procedure named doubleVal.
Listing 18.7: double.asm
1 .586 2 .MODEL flat, stdcall 3 .CODE 4 doubleVal PROC C int_val:DWORD 5 mov eax, int_val 6 shl eax, 1 7 ret 8 doubleVal endp 9 END
The assembly file now needs to be assembled into an object module. To run in a Win32 environment the object file needs to be in the PE/COFF object file format. Failure to generate the proper object file format will result in a link error.
For this example I am using Microsoft Macro Assembler version 6.14 via the command line. The command to assemble the double.asm file will look like this:
ml /c /coff /Fodv.obj double.asm
The results of running this command are shown in figure 18-17.
Figure 18-17: Assembling double.asm with MASM ver. 6.14
Several MASM command line switches are used to obtain the right object module. First, the /c tells MASM to compile only and to not link the resulting file. The /coff switch creates a coff object module. The /Fo specifies the name of the output file. Running the assembler results in a coff object file named dv.obj that is ready to be used in a Win32 C++ project.
Create a Win32 C++ project using the IDE of your choice. The IDE of my choice is Metrowerks CodeWarrior and to it I have added a main.cpp file that calls the doubleVal() function. The code for the main.cpp file is shown in example 18-8.
Listing 18.8: main.cpp
1 #include <iostream> 2 #include "double.h" 3 using namespace std; 4 5 int main( void ){ 6 for(int i=0; i<10; i++){ 7 cout<<doubleVal(i)<<endl; 8 } 9 return 0; 10 }
Create the double.h header file as shown in example 18.9. Since the doubleVal() function was created in assembly language the function declaration must be declared to have extern 'C' language linkage.
Listing 18.9: double.h
1 #ifndef DOUBLE_H 2 #define DOUBLE_H 3 4 extern "C"{ 5 int doubleVal(int d); 6 } 7 8 #endif
Make the header file available to the project in the usual fashion.
When the object and header files have been created you are ready to use the object file, and the function it implements, in a C++ project. Figure 18-18 shows a Metrowerks CodeWarrior Win32 project with the dv.obj file included.
Figure 18-18: Win32 Project Using dv.obj
Figure 18-18 also shows the results of running the project.
The syntax required to use inline assembly in a C++ program targeting the Macintosh™ platform is different from that required to target the PC. The obvious differences between assembly for the PC and assembly for the Macintosh™ will be the names and format of assembly instructions and the names and usages of the PowerPC™ registers. These issues are beyond the scope of this book, however, I do want to show you at least one example of inline assembly targeting the Macintosh™.
I will implement the same doubleVal() function using Metrowerks CodeWarrior Release 5 for the Macintosh™. Example 18.10 gives the code for the double.cpp file.
Listing 18.10: double.cpp PowerPC Version
1 #include "double.h" 2 3 asm int doubleVal(int int_val){ 4 lwz r0, int_val //load int_val into register 0 5 mulli r3, r0, 2 // multiply r0 by 2, store in r3 for return 6 }
Note the differences between the Macintosh™ version of this file and the PC version. The asm keyword is still used but here it must precede the function definition. Local variable names can still be used in the assembly code as well as C++ style comments. Figure 18-19 shows the results of running the Macintosh™ version of the doubleVal() function.
Figure 18-19: Results of Running Macintosh Version of doubleVal()
In this section you have learned how to incorporate assembly language into your C++ projects. The two primary methods of doing so are by including inline assembly instructions within a C++ function, or by creating stand-alone object modules with assembly language and linking those object modules to your C++ projects. Consult your compiler documentation to learn how it supports the asm keyword.
| < Day Day Up > |
|