Hello.

I have been wondering if there were any guidelines I could go by if someone were to ask me to write an Assembly program for their C/C+/C++ program or whatever. I'm not sure what is accepted and rejected and would like to know what I can and can't do should I attempt to write an assembly program for someone who programs in C but doesn't know a thing about assembly.

Thanks,

keantoken
Posted on 2007-08-31 19:06:14 by keantoken
Typically, the only way for the C programmer to understand ASM, is for them to know it already or go to someone who does know it for interpretation.

However, to answer your question, you generally have two routes to take. Inline Assembly and modules.

The first, Inline Assembly, is supported in all the major C compilers. However, the (default) syntax can differ based on the compiler you are using. It also can get quite annoying having ASM syntax spread out through your high-level source code... especially when it breaks the compiler's process of streamline optimization.

The second, modules, are simply done by linking your C object files with your ASM object files... making note to properly decorate and address GLOBAL and EXTERNAL variables/functions. This is probably the better way as you can keep to one ASM syntax, that you do like, and still get everything to work. Moreover, you could provide a basic "include" file with said GLOBALS and EXTERNS, the same concept as a C header and even a C programmer should understand... throw in some comments about how the functions/variables work and you're good to go.
Posted on 2007-08-31 19:40:06 by SpooK
keantoken,

I think you are trying to ask "How might I go about writing a funtion to which a C program may call?".

If that's the case, here's a few tips to point you in the right direction...

The C Calling Convention stipulates that these registers must be preserved: EBX, ESP, EBP, ESI, and EDI. They can be used, but you must restore their original values before your procedure returns to C. Any 32-bit or smaller return value is returned in EAX. A 64-bit return value is returned in EAX:EDX, EAX has the low-order 32-bit, and EDX has the high-order ones. Parameters to your procedure will be pushed on to the stack in reverse order, and it is your callers responsibility to pop them.

The Standard Calling Convention, the one Win32 uses, is essentially the same, except your procedure would remove the parameters, rather than it's caller.

I'm not a 100% sure on this one, but I think for C to be able to call your procedures, they must begin with an underscore, as in _MyAssemblyProc.

So, keeping all this in mind, this is how your procedure might look for standard C:

_MyAssemblyProc:

   push ebp ; save callers stack frame
   mov ebp, esp ; your stack frame is in ebp
   push ebx   ; save critical registers
   push esi
   push edi

   ; you could sub, esp <num> for locals here

   ; do your procedure's stuff here

   pop edi  ; restore critical registers
   pop esi
   pop ebx
   mov esp, ebp ; no need to add, esp <num> to discard locals
   pop ebp  ; restore callers stack frame
   ret  ; caller takes care of params

This is how your procedure might look for Windows calling:

_MyAssemblyProc:

   push ebp
   mov ebp, esp
   push ebx
   push esi
   push edi

   ; do your procedure's stuff here

   pop edi
   pop esi
   pop ebx
   mov esp, ebp
   pop ebp
   ret 8   ; return and pop 2 params off the stack
Posted on 2007-08-31 19:40:55 by TheAbysmal
Ah, thanks!

So EAX is for a return status (fail, ERRR, etc.) and/or can be used as a variable? Or is it just for return status? Sorry, I know second to nothing about C.

Can the stack also be used to transport variables?

So how do you go about declaring global and external functions and what's the difference between them?

Sorry if I'm asking a lot of questions, but if I can figure this out then I can write a tutorial for Assembly programmers who don't want to bother learning C just yet. Plus I'll be able to do a whole lot more and I can show the community what I'm good for.

- keantoken
Posted on 2007-08-31 22:51:30 by keantoken
I'm not a 100% sure on this one, but I think for C to be able to call your procedures, they must begin with an underscore, as in _MyAssemblyProc.


I don't believe they have to start with an underscore, it's just common practice to identify globals from normal functions at a glance. I do know that certain versions of LibC have an _ and others don't, which is why the LibC.mac for NASM32 had an _UNDERSCORE_ switch. Depending on what version of libc you were required to add -D_UNDERSCORE_ to the command line to build sources. But other versions of libc didn't have a beginning _ to their functions like printf, puts, and the rest. So it's most certainly not forced on you, it's probably a style thing.

So EAX is for a return status (fail, ERRR, etc.) and/or can be used as a variable? Or is it just for return status? Sorry, I know second to nothing about C.


C programmers will expect you to return either an error code or the result of your processing.

Can the stack also be used to transport variables?


That's primarily what programmers use it for.

So how do you go about declaring global and external functions and what's the difference between them?


That depends solely on what assembler you are using. Different assemblers have different directives for declaring global procedures.

Sorry if I'm asking a lot of questions, but if I can figure this out then I can write a tutorial for Assembly programmers who don't want to bother learning C just yet. Plus I'll be able to do a whole lot more and I can show the community what I'm good for.


Good luck with that! :D

Regards,
Bryant Keller
Posted on 2007-09-01 00:59:01 by Synfire
The underscore has to do with name mangling - standard C symbols in .obj files are prepended with an underscore (which means the _reserved names in your platform end up as __reservered). There's also STDCALL calling convention (the default used in windows) which has different name mangling, nameling name@parmsize , where parmsize is the byte count of parameters.

MASM's PROC statement, supporting calling convention declaration, does the name mangling automatically; for FASM/NASM/YASM/etc you have to do it manually, or find/make some macro.

Forget about inline assembly, it tends to inhibit some optimizations in some compilers, the syntax is compiler dependent, and it's largely unavailable for 64bit compilers (well, for MSVC x64 anyway :)). Anything worth writing in assembly is worth writing as an external assembly module.
Posted on 2007-09-01 03:17:53 by f0dder