2010-05-18 9 views
5

Digamos que usamos NASM como lo hacen en esta respuesta: how to write hellow world in assembly under windows.Creando una función de biblioteca Hello World en el ensamblado y llamándola desde C#

Tengo un par de pensamientos y preguntas sobre el ensamblaje combinado con C# o cualquier otro idioma .net para el caso.

En primer lugar yo quiero ser capaz de crear una biblioteca que tiene la siguiente función HelloWorld que toma este parámetro:

  • Nombre

En C# la firma del método sería looke como esto: void HelloWorld(string name) y sería imprimir algo así como

Hello World desde nombre

He buscado un poco, pero no puedo encontrar tanto material bueno y limpio para que esto me ayude a empezar. Sé un poco de ensamblaje básico de antes, en su mayoría gas sin embargo.

Por lo tanto, cualquier puntero en la dirección correcta es muy apreciado.

para resumir

  • Crear una rutina en ASM (NASM) que tiene uno o más parámetros
  • Compilar y crear una biblioteca de la funcionalidad por encima de
  • incluyen la biblioteca en cualquier NET
  • Llame a la función de la biblioteca incluida

características de la prima

  • valores devueltos ¿Cómo funciona un mango?
  • ¿Es posible escribir en línea el método ASM?

Al crear bibliotecas en ensamblador oc, usted sigue cierta forma "predefinida", la convección de llamada c, ¿correcto?

Respuesta

11

Algo como esto debe obtener una DLL de trabajo:

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 

A continuación, sólo tiene que llamar a la función 'hola' utilizando P/Invoke. No se limpia por sí mismo, por lo que debe establecer CallingConvention en Cdecl; también necesita decirle que está usando cadenas ANSI. No probado, pero debería funcionar bien.

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_); 
    } 
} 
+0

Cdecl almacena el valor de retorno en 'eax' ¿no? Entonces, sería bastante fácil ajustar el ASM para devolver la cadena en lugar de (hacer trampa;) llamar a printf? –

+0

Claro, solo necesita asignar memoria para la cadena, concatenar el valor pasado con la cadena estática, y devolver ese valor en eax. –

0

mi punto de vista, su pregunta es doble:

  1. ¿Cómo se escribe una función utilizando el montaje y la puso en un archivo DLL?
  2. ¿Cómo puedo llamar a una función en una DLL no administrada desde C# administrado?

La respuesta a 2 es usar P/Invocar. Hay mucha documentación y tutoriales disponibles sobre ese tema, p. http://msdn.microsoft.com/en-us/magazine/cc164123.aspx

+0

Estoy pidiendo un ejemplo paso a paso sobre cómo resolver esto. –

3

Primero cubriré las pautas básicas para hacer lo que quiera ... luego intentaré explicarles cómo hacer el ejemplo Hello World.

El primer paso sería escribir una función y hacer que dll fuera de ella. Función en el montaje debe cumplir con uno de los estándares del llamamiento, stdcall es la más común (se puede leer más sobre stdcall y otras normas que llaman here) Un ejemplo de la creación de un archivo DLL con asm se pueden encontrar here

El segundo paso sería debe importar el método en un lenguaje administrado usando P/Invoke. Puede leer más sobre él here

Y eso es todo ..

Ahora por tu ejemplo mencionado, usted tendrá que hacer una función asm que se lleva todos los parámetros de entrada y se lo pasa a alguna otra función que sabe cómo para imprimir en stdout (printf del estándar c lib como se mencionó anteriormente, o usando llamadas winapi como here)

Después de eso, tendrá que importar el dll a C#, como se describe arriba. Las cosas que debe tener especial cuidado son la codificación de caracteres para cadenas y la limpieza de datos. Todos se mencionan en el tercer enlace que proporcioné (sección de texto de referencia).

parte de Bono:

  • Manejo de valores devueltos depende en las convenciones de llamada utilizado
  • No es posible escribir ensamblado en línea con C#. Sin embargo, puede escribirlos con Managed C++.
1

Esta es una muy buena pregunta y merece un voto de mi parte. En relación con su pregunta, la única forma en que esto puede hacerse como Cody ha señalado su rutina de ensamblador, es la construcción de una DLL en base a eso, y de ahí a utilizar p/Invocar usando Interops como

 
[DllImport("mylib.dll")] 

etc. Sin embargo, desafortunadamente, debido a la naturaleza de C# o de cualquier otro lenguaje, el entorno de tiempo de ejecución de CLR usa el código administrado. Sería incómodo tener el CLR o el ensamblador para configurar el marco de la pila, los registros y luego el salto cruzado del mundo nativo al mundo administrado. Sería un trabajo peliagudo, pero si alguien ha visto ese tipo de cosas, por favor deje un comentario al final de mi respuesta y corregiré esta respuesta en consecuencia.

Y por lo tanto, que sepa, no hay forma de alinear una rutina de ensamblador, por ensamblador, en ese contexto, usando registros de sistema como eax, ebx, montones de marcos, etc., en un código CLR, al igual que la muestra del código que Cody arriba ha proporcionado en su respuesta. Hubiera sido verdad con C/C++ en este caso:

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

que sería bueno hacerlo desde la perspectiva de CLR como esto con el fin de optimizar el código aún más, al menos en teoría, pero eso sería una insuperable trabajo para el CLR para alojar ese tipo de cosas, hay una excepción ...se puede hacer con Gestionado compilador de C++ que se puede hacer esto, pero NO de todos modos VB.NET/C#:

 
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 
    } 
} 

Sin embargo, mientras que sobre el tema, se puede hacer para generar el código IL a ensamblador nativo, ahora, mientras escribo esto, no estoy 100% seguro de si esto se puede hacer a la inversa, Ver here para una descripción detallada de cómo esto puede suceder

Pero sin embargo, la única forma de trabajar en el ensamblado de CLR está escribiendo a mano el código IL y compilándolo en su lugar, es decir, el ensamblador del runt de CLR Ime, directamente, de la misma manera que el ensamblador nativo puede ser llamado por nativo (lea los binarios NON-CLR), consulte este artículo here sobre cómo lograr esto también.

+0

Interesante .. Me pregunto si ese inline-asm es algo posible en C++ administrado? –

+0

Puede usar el ensamblador en línea en C++/CLI, aunque/cuando/puede usarlo es complicado. Lo uso para parchar varias funciones en una inyección binaria en el uso de EasyHook, pero es difícil mezclar el ensamblaje en línea y el código administrado. Te recomiendo encarecidamente que no lo hagas a menos que no tengas otra opción. En otra nota, hay una biblioteca que le permite incrustar código nativo en el código JITC para MS.NET, pero no recuerdo el nombre. –