The Assembly Programming Master Book

In this section, I present a simple module written in Assembly language. This module contains a procedure that copies one string to another string. This module will be linked to different programs, written in the C and Pascal languages, using the following three translators: Borland C++ 5.02, Visual C++ 7.0, and Delphi 7.0.

Borland C++ 5.0

The function that the program calls from the Assembly module is declared using the extern "C" and stdcall modifiers. Because the module written in Assembly language is translated using TASM, the problem with the underscore character won't arise. The stdcall calling type assumes that the stack is cleared in the called procedure. In the Assembly module, the called procedure must be declared using the PUBLIC directive.

Listing 20.1: Using a procedure from an external module (built using Borland C++ 5.0)

// The COPYC.CPP file #include <windows.h> #include <stdio.h> extern "C"__stdcall COPYSTR(char *, char *); void main() { char s1[100]; char *s2="Hello!"; printf("%s\n", (char *)COPYSTR(sl, s2)); ExitProcess(0); } ; The COPY.ASM file .586P ; This procedure will be called from the external module PUBLIC COPYSTR ; Flat memory model .MODEL FLAT, stdcall _TEXT SEGMENT ; The procedure for copying strings ; Target string [EBP+08H] ; Source string [EBP+0CH] ; Do not account for the target string length COPYSTR PROC PUSH EBP MOV EBP, ESP MOV ESI, DWORD PTR [EBP+0CH] MOV EDI, DWORD PTR [EBP+08H] L1: MOV AL, BYTE PTR [ESI] MOV BYTE PTR [EDI], AL CMP AL, 0 JE L2 INC ESI INC EDI JMP L1 L2: MOV EAX, DWORD PTR [EBP+08H] POP EBP RET 8 COPYSTR ENDP _TEXT ENDS END

 

The modules in Listing 20.1 can be translated using one of the following methods :

Visual C++ 7.0

The C++ code didn't change, in contrast to the source code written in Assembly language. The C translator will automatically add the @8 suffix to the end of the line. In this case, you'll have to abandon customary practice and rely on the MASM translator. To achieve this, you'll have to explicitly specify the parameters in the procedure declaration. After you do this, the translator will carry out part of your job (namely, pass the parameters). In addition, it complements the COPYSTR name with the @8 suffix. I'd like to point out again that when using such a manner of declaration it isn't necessary to explicitly set the EBP register and release the stack. The translator will do this automatically.

Listing 20.2: A module written in Assembly language for compiling and linking using Visual C++ 7.0

; The PROC.ASM file .586P .MODEL FLAT, stdcall PUBLIC COPYSTR ; Flat memory model _TEXT SEGMENT ; Procedure for copying the source string to the target string ; Target string [EBP+08H] ; Source string [EBP+0CH] ; Don't take into account the target string length ; Explicitly specify the parameters COPYSTR PROC str1: DWORD, str2: DWORD MOV ESI, str2 ; DWORD PTR [EBP+0CH] MOV EDI, str1 ; DWORD PTR [EBP+08H] L1: MOV AL, BYTE PTR [ESI] MOV BYTE PTR [EDI], AL CMP AL, 0 JE L2 INC ESI INC EDI JMP L1 L2: MOV EAX, DWORD PTR [EBP+08H] RET COPYSTR ENDP _TEXT ENDS END

 

Explicit specification of parameters in the procedure header produces the following results:

To translate, take the following steps:

  1. Include in the Visual C++ project the object module compiled with ML.EXE.

  2. If you want to include the source code, written in Assembly language, into your project, you'll have to specify the translation method for it. To achieve this, specify the ML.EXE command line.

Delphi 7.0

The Delphi translator introduces some minor nuances into the problem. For the code segment, you must choose the name CODE . Because Pascal interprets strings differently than C language does, I had to take an array of symbols instead one of strings. The Writeln operator, however, is intelligent enough. It has interpreted everything correctly without additional efforts on my part. Note that in this case I used the stdcall directive.

Listing 20.3: Using an object module with a Delphi program

{The COPYD.PAS program that uses an assembler by linking an object module} program Project2; uses SysUtils; {$APPTYPE CONSOLE} {$L 'copy.OBJ'} procedure COPYSTR(s1, s2:PChar); stdcall; EXTERNAL; var s1,s2:array[1..30] of char; begin s2[1] := 'H'; s2[2] := 'e'; s2[3] := 'l'; s2[4] := 'l'; s2[5] := 'o'; s2[6] := '!'; s2[7] := char(0); COPYSTR(addr(s1[1]), addr(s2[1])); writeln(s1); end. ; The COPY.ASM file .586P .MODEL FLAT, stdcall PUBLIC COPYSTR ; Flat memory model CODE SEGMENT ; The procedure for copying the source string to the target string ; Target string [EBP+08H] ; Source string [EBP+0CH] ; Don't account for the target string length COPYSTR PROC PUSH EBP MOV EBP, ESP MOV ESI, DWORD PTR [EBP+0CH] MOV EDI, DWORD PTR [EBP+08H] L1: MOV AL, BYTE PTR [ESI] MOV BYTE PTR [EDI], AL CMP AL, 0 JE L2 INC ESI INC EDI JMP L1 L2: MOV EAX, DWORD PTR [EBP+08H] POP EBP RET 8 COPYSTR ENDP CODE ENDS END

 

To translate this program, prepare an object module (using TASM32) and specify it in the {$L COPY.OBJ} directive. After that, the Delphi translator will do everything automatically.

Категории