Chapter 12
|
Modified: |
Download
12.3 Linking to C/C++ in Protected Mode
C++ and assembler routines can be used interchangeably, one calling the other, as long as the interfacing protocols continue to be followed.
Caller
- Save any critical registers.
- Push actual parameters onto stack, right to left order.
- Call function.
- Remove parameters from stack.
- Restore any critical registers.
Callee
- Save eBp register.
- Access parameters.
- Restore eBp and eSp.
- Return.
12.3.2 Calling C and C++ Functions
C/C++ to Assembler
To call an Assembler function from C/C++:
Define the prototype as extern in the C/C++ program:
extern "C" int addem(int p1, int p2, int p3); Call Assembler function from C/C++:
int total = addem( 10, 15, 25 ); In Assembler, must define memory model as C, and function name as public:
.586
.model flat, C
.code
addem proc public
Below is a simple example where C++ calls an assembler function and prints the result.
| #include <iostream> using namespace std; int main() { int total = addem( 10, 15, 25 ); cout << "Total = " << total << endl;
return 0; int addem(int p1, int p2, int p3) { return p1 + p2 + p3; } |
| #include <iostream>
using namespace std; extern "C" int addem(int p1, int p2, int p3);int main() { int total = addem( 10, 15, 25 ); cout << "Total = " << total;
return
0; |
.586
.model flat, C
.code
addem proc public, p1:DWORD, p2:DWORD, p3:DWORD
mov eax, p1 ; first argument
add eax, p2 ; second argument
add eax, p3 ; third argument
ret
addem endp
end
|
Question 1 - Give the assembler and C++ for double written in Assembler:
C++ #include <iostream>
using namespace std;void main() {
int total = double( 10 );
cout << total;
}int double(int x) {
return x*2;
}Question 2 - Give the assembler and C++ for double written in Assembler:
C++ #include <iostream>
using namespace std;void main() {
cout << double( x );
int x = 10;
}int double(int &x) {
return x*2;
}
The Irvine text has a Web site with Visual Studio projects, the one above can be downloaded.
Assembler to C/C++
C/C++ function that can be called from Assembler:
In C/C++, specify as extern:
extern "C" print( int x, int y) { cout << x << " " << y << "\n";
}
In Assembler, specify as proto near C:
print proto near C, x : dword, y : dword
In Assembler, invoke:
invoke print, p1, p2
#include |
.586
.model flat, C
print proto near C, x : dword, y : dword
.code
printASM proc public, p1:DWORD, p2:DWORD
invoke print, p1, p2
ret
printASM endp
end
|
Question 3 - Give the assembler and C++ for double written in Assembler:
C++ #include <iostream>
using namespace std;void main() {
double(10);
}
void print(int x){
cout << x;void double(int x) {
print( x*2 );
}
Note
Alternatively to invoke, actual parameters can be pushed onto the stack manually, right-to-left as in:
.586 .model flat, C print proto near C, x : dword, y : dword .code printASM proc public, p1:DWORD, p2:DWORD push p2 push p1 call print add esp, 8 ret printASM endp end
BinarySearch example
Note: eBp is restored automatically prior to ret instruction.
.586
.model flat, C
.code ; int BinarySearch (int A[], int key, int lo, int hi) {
BinarySearch proc public, A:ptr dword, key:dword, lo:dword, hi:dword
mov eAx, lo
.IF eAx > hi ; if (lo > hi) return -1;
mov eAx, -1
ret
.ENDIF
mov eAx, lo ; int mid=(lo+hi)/2;
add eAx, hi
mov eCx, 2
mov eDx, 0
div eCx
mov eBx, A
mov eSi, key
.IF eSi == [eBx+eAx*4] ; if (key == A[mid]) return mid;
ret
.ENDIF
.IF eSi > [eBx+eAx*4] ; if (key > A[mid])
inc eAx
invoke BinarySearch, A, key, eAx, hi ; return BinarySearch(A, key, mid+1, hi);
.ELSE
dec eAx
invoke BinarySearch, A, key, lo, eAx ; else return BinarySearch(A, key, lo, mid-1);
.ENDIF
ret
BinarySearch endp
end
|
#include <iostream>
using namespace std;
extern "C" int BinarySearch (int A[], int key, int lo, int hi);
int X[] = {2, 4, 5, 7, 8, 9, 12, 14, 17, 19, 22, 25, 27, 28, 33};
void main () {
cout << BinarySearch(X, 8, 0, 14);
}
|
High-level language routines generally do not save registers, it is up to the caller to save any registers prior to the call and restore the registers after the call. For example, the following saves and restores eAx:
.586 .model flat, C print proto near C, x : dword, y : dword .code printASM proc public, p1:DWORD, p2:DWORD mov eBx, 5 push eBx push p2 push p1 call print add esp, 8 pop eBx ret printASM endp endQuestion 4 - Give the C++ and Assembler for function Fib.
The standard library for the C language contains many useful functions for file handling, running other process, math, etc.
These functions can be accessed by defining the PROTO for the C function and then INVOKE the function.
The assembler program should include the following:
main proc public
ret
main endp
end
The following Command Prompt example illustrates by copying a file to the screen.
If testing, the C program should be named file.C with a C extension.
Copy the MSVCRT.LIB, by default located at:
- C:\Program Files\Microsoft Visual Studio 9.0\VC\MSVCRT.LIB
Set Visual C environment variables:
- C:"\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"
The Assembly program below can be assembled with the MSVCRT.LIB in the same directory by:
- ml /coff /Zi file.asm /link MSVCRT.LIB /subsystem:console
The C program copies file.C while the Assembler program copies file.asm to the console screen. The commands necessary are:
- Copy the following Assembler program and save as file.asm.
- copy C:"\Program Files\Microsoft Visual Studio 9.0\VC\MSVCRT.LIB"
- C:"\Program Files\Microsoft Visual Studio 9.0\VC\vcvarsall.bat"
- ml /coff /Zi file.asm /link MSVCRT.LIB /subsystem:console
- file
int *fopen( const char *filename,
const char *mode );
int getc( int *stream );
int putchar( int c );
char filename[7] = "file.c";
char mode[2] = "r";
void main(void) {
int *fp = fopen(filename, mode);
int c;
while ((c=getc(fp)) != -1)
putchar(c);
}
|
.586
.model small, c
fopen proto near C,
filename:near ptr dword, mode:near ptr dword
getc proto near C, fileptr : dword
putchar proto near C, char : dword
.data
filename byte "file.asm",0
mode byte "r",0
.code
main proc public
local fp : dword
invoke fopen, addr filename, addr mode
mov fp, eAx
@@while:
invoke getc, fp
cmp Al, -1
jne @@do
jmp @@endwhile
@@do:
invoke putchar, eAx
jmp @@while
@@endwhile:
ret
main endp
end
|