==============================================================================C-Scene Issue #2..oO Interfacing Assembly With C Oo..Moe Elzubeir==============================================================================I did NOT want to write this. So, don't blame me if any of it is writtenbadly, etc. I was forced into submission by Brent, it wasn't my fault ;)Blame him ! Okay, now on with it...[Oh BS ;}... I didn't force you... -ed]I first have to admit to not knowing the AT&T syntax, although I have beenusing Linux for quiet some time now, I still haven't bothered to get to it,and so I end up writing pure C programs, which actually look better to me ;)So, Brent sent me an AT&T syntax tutorial which I haven't read - yet.[Lay-zee... -ed]So, what's the deal ?I assume you own a Microsoft C / Borland C/C++ / Or any other DOS compilerbasically that has an assembly compiler a linker and supports the Intel asmsyntax. That way we're all set and ready. If Brent decides to add anymodifications to this article to make it support the AT&T syntax well andgood, but as I write this, it's only for the Intel syntax. Before we begin, there are two ways or writing asm routines for your Cprogram : a. inline assembly b. separate C and assembly modulesIn this article I am more concerned about the second one (b). Inlineassembly is basically for smaller asm routines, and basically for a programthat will not have a lot of assembly. But, when your the program grows insize and starts carrying a lot of assembly it becomes hard to read andfollow. So, we go for the separate C and assembly modules.Doing inline assembly differs from one compiler to another. So I will notget into that. But, I can just say that in Borland C++ it is done as :----------#pragma inline#include <blabla.h>int main(void) { int i, ho; asm { /* assembly code */ } /* C code */}--------Consult your compiler's manual for more information.There are a few guidelines you must follow :1. You must give a specific segment name to the code segment of your assembly language subroutine. The name may vary from one compiler to another. Microsoft C requires a segment name _TEXT for small/compact memory models, and a segment name with the suffix _TEXT for other memory Models. Other compilers may have CODESEG, or some other more meaningful segment names. BC++ has it called DOSSEG.2. Your C Compiler may require specific names for data segments. That's only if the data is being references outside the code segment. Microsoft C requires that segment to be called _DATA. On the other hand, for BC++ it will be called .DATA.3. You must understand how variables are being passed through the stack [I think someone wrote something about the Stack this issue]. eg. function1(arg1,arg2,arg3,...,argn); argn is being pushed on the stack first, followed up until arg1.4. You must save any registers that your assembly routines may "disturb". Registers such as, CS,DS,SS,BP,SL, and DI. Failing to do so may result in undesirable results. But, you do not need to save the contents of AX, BX, CX, or DX since they are not considered "non-changeable" by C.With those guidelines in mind, we can move on to some examples of simpleinterfacing. ---------------delayer.asm--------------- DOSSEG .MODEL small .486 .CODE PUBLIC C delayerdelayer PROC C NEAR push BP mov BP,SP mov CX,91 ; 91 ticksD1: push CX mov AH,0 ; read time int 1Ah ; get initial ticksD2: push DX ; save tick count mov AH,0 int 1Ah pop BX ; get back to prev count cmp BX,DX ; compare them.. je D2 ; the same ? continue pop CX loop D1 pop BP retdelayer ENDP END----------------delayer.am----------------Now, the C module--------------delayem.c-----------#include <stdio.h>int task();int main(void) { printf("About to delay for 5 seconds. Hit Enter to start.\n"); getch(); printf("Starting delay for 5 seconds...\n"); delayer(); printf("Done!\n"); return(0);}-----------delayem.c--------------Now, to compile this example program, all you need to do is follow thefollowing steps :1. tasm delayer.asm2. bcc -c delayem.c3. tlink c0s delayem delayer,delayem, ,csCommands, options vary from one compiler to another, this applied toBorland C++ (and possibly TC++). Compile it, and try it.Now that we know how to call and create a separate assembly module, you areprobably wondering, what about PASSING arguments,variables, to my assemblyroutine ? Well, very simple, just declare your assembly function in your Cfile. eg int function1(int, char);And then in your assembly code it would look something like :function1 PROC C NEAR f1:WORD,f2:BYTEThe "C" above is a keyword which tells the program to expect arguments to bepassed from right to left via the stack. The procedure (routine) would bedeclared NEAR if you are using a small memory model (of course when doing32-bit programming, you won't have to bother with that any more). If using alarge, huge, etc. memory model, then it should be declared FAR. As for theWORD, BYTE, and DWORD, those are assembly data types, and they can be placeddirectly into the registers. (BYTE 8bit, WORD 16 bit, etc..).The rest would basically look like any other assembly routine.You can download a zipfile of the source for this here.
联系客服