Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a Hello World library function in assembly and calling it from C#

Let's say we use NASM as they do in this answer: how to write hellow world in assembly under windows.

I got a couple of thoughts and questions regarding assembly combined with c# or any other .net languages for that matter.

First of all I want to be able to create a library that has the following function HelloWorld that takes this parameter:

  • Name

In C# the method signature would looke like this: void HelloWorld(string name) and it would print out something like

Hello World from name

I've searched around a bit but can't find that much good and clean material for this to get me started. I know some basic assembly from before mostly gasthough.

So any pointers in the right direction is very much apprechiated.

To sum it up

  • Create a routine in ASM ( NASM ) that takes one or more parameters
  • Compile and create a library of the above functionality
  • Include the library in any .net language
  • Call the included library function

Bonus features

  • How does one handle returned values?
  • Is it possible to write the ASM-method inline?

When creating libraries in assembly or c, you do follow a certain "pre defined" way, the c calling convetion, correct?

like image 976
Filip Ekberg Avatar asked May 18 '10 11:05

Filip Ekberg


3 Answers

Something like this should get you a working DLL:

extern _printf

section .text
global _hello
_hello:
    push ebp
    mov ebp, esp

    mov eax, [ebp+12]
    push eax
    push helloWorld
    call _printf
    add esp, 8
    pop ebp
    ret

export _hello

helloWorld: db 'Hello world from %s', 10, 0

You then just need to call the 'hello' function using P/Invoke. It doesn't clean up after itself, so you need to set CallingConvention to Cdecl; you also need to tell it you're using ANSI strings. Untested, but it should work fine.

using System.Runtime.InteropServices;

namespace Test {
    public class Test {
        public static Main() {
            Hello("C#");
        }

        [DllImport("test.dll", EntryPoint="hello", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
        public static extern Hello(string from_);
    }
}
like image 141
Serafina Brocious Avatar answered Oct 26 '22 23:10

Serafina Brocious


I will first cover basic guidelines for doing what you want.. then I will try to explain how to do the Hello World example.

The first step would be writing a function, and making dll out of it. Function in assembly should adhere to one of calling standards, stdcall is the most common one (you can read more about stdcall and other calling standards here) An example of creating an dll with asm can be found here

The second step would be to import the method in a managed language using P/Invoke. You can read more about it here

And that's it..

Now for your mentioned example, you will need to make an asm function that takes all the input parameters and passes it to some other function that knows how to print to stdout (printf from standard c lib as mentioned above, or using winapi calls like here)

After that you'll need to import the dll to C#, as described above. Things you should take special care about are, character encoding for strings and clean up of data. They are all mentioned in the 3rd link I provided (marshaling text section).

Bonus part:

  • Handling of returned values depends on the calling conventions used
  • It is not possible to write inline assembly with C#. However you can write them with Managed C++.
like image 25
Ivan Avatar answered Oct 27 '22 00:10

Ivan


This is a very good question and deserves a vote from me. In relation to your question, the only way this can be done as Cody has pointed out his assembler routine, is to build a DLL based on that, and from there to use p/Invoke using interops such as

[DllImport("mylib.dll")]

etc. However, unfortunately, due to the nature of the C# or any other language for that matter, the CLR runtime environment is using the managed code. It would be awkward in having the CLR or the assembler to set up the stack frame, registers, then cross jumping from native world to the managed world. That would be a hairy job to do, but if anyone has seen that kind of thing, please leave a comment at the end of my answer and I will amend this answer accordingly.

And therefore, to my knowledge, there is no way to inline an assembler routine, by assembler, in that context, using system registers such as eax, ebx, stack frames etc, into a CLR code, just like the sample of code that Cody above has supplied in his answer. It would have held true with C/C++ in this case:

void foo(void){
   _asm{
     xor ecx, ecx
     mov eax, 1
     ....
   }
}

It would be nice to do that from the CLR perspective like this in order to optimize code further, in theory at least but that would be an insurmountable job for the CLR to actually host that kind of thing like this, there is one exception... it can be done with Managed C++ compiler which can do this, but NOT from VB.NET/C# anyway:

private void mycsfunction(string s){
    // Managed code ahoy
    StringBuilder sb = new StringBuilder(s);
    ......
    _asm{
        push ebp
        mov ebp, esp
        lea edx, offset sb
        ....
        mov eax, 1
        pop ebp
    }
}

However, while on the subject, it can be done to generate IL code to native assembler, now, as I write this, I am not 100% sure if this can be done in the reverse, See here for a detailed description of how this can happen

But however, the only way of working on CLR assembly is handwriting the IL code and compiling it instead, that is, the assembler of the CLR runtime, directly, in very much the same way as native assembler can be called by native (read NON-CLR binaries), see this article here on how to accomplish this also.

like image 29
t0mm13b Avatar answered Oct 27 '22 00:10

t0mm13b