Pregunta

Actualmente estoy escribiendo algunos procedimientos en lenguaje ensamblador. Como dice alguna convención, cuando quiero volver algún valor a la persona que llama, por ejemplo un entero, que debe devolverlo en el registro EAX. Ahora me pregunto ¿y si quiero devolver un flotador, un doble, una enumeración, o incluso una estructura compleja. Cómo devolver este tipo de valores?

Me puede pensar en volver una dirección en el EAX que apunta al valor real en la memoria. Pero, ¿es la forma estándar?

Muchas gracias ~~~

¿Fue útil?

Solución

Es todo depende de ti, si la persona que llama es su código. Si la persona que llama no está bajo su control, usted tiene que seguir su convención, ya sea existente o desarrollar su propia convención juntos.

Por ejemplo, en la plataforma x86 cuando aritmética de punto flotante es procesada por instrucciones FPU, el resultado de una función se devuelve como el valor superior de la pila de registros FPU. (Si usted sabe, registros x86 FPU están organizados en una "pila circular" de clases). En ese momento no es ni float ni double, es un valor almacenado con precisión FPU interna (que podría ser más alta que float o double) y es responsabilidad de la persona que llama para recuperar ese valor desde la parte superior de la pila FPU y convertirlo en lo el tipo que desea. De hecho, así es como funciona una instrucción FPU típicos: toma sus argumentos de la parte superior de la pila FPU y empuja la parte trasera resultado en la pila FPU. Mediante la implementación de la función de la misma manera que emula esencialmente una instrucción de FPU "complejo" con su función -. Una manera bastante natural para hacerlo

Cuando aritmética de punto flotante es procesada por instrucciones SSE, la posibilidad de optar SSE registro para el mismo propósito (uso xmm0 al igual que lo utiliza EAX para enteros).

En estructuras complejas (es decir, los que son más grandes que un registro o un par de registros), la persona que llama normalmente pasar un puntero a un búfer reservado a la función. Y la función sería poner el resultado en la memoria intermedia. En otras palabras, bajo el capó, las funciones nunca "retorno" objetos de gran tamaño, sino que construyen en un búfer de memoria de llamadas proporcionada.

Por supuesto, usted puede utilizar este método de "memoria intermedia" para devolver los valores de cualquier tipo, pero con valores más pequeños, es decir, valores de tipo escalar, es mucho más eficiente utilizar registros de una posición de memoria. Esto se aplica, por cierto, a las estructuras pequeñas también.

Las enumeraciones son por lo general sólo un envoltorio conceptual sobre algún tipo entero. Por lo tanto, no hay diferencia entre el retorno de una enumeración o un número entero.

Otros consejos

Un doble debe ser devuelto cuando el artículo primero de la pila.

Aquí es un C ++ ejemplo de código (x86):

double sqrt(double n)
{
    _asm fld n
    _asm fsqrt
}  

Si prefiere administrar manualmente la pila (ahorro de algunos ciclos de CPU):

double inline __declspec (naked) __fastcall sqrt(double n)
{
    _asm fld qword ptr [esp+4]
    _asm fsqrt
    _asm ret 8
}

Para los tipos de complejos, debe pasar un puntero, o devolver un puntero.

Cuando usted tiene preguntas acerca de convenciones de llamada o lenguaje ensamblador, escribir una función simple en lenguaje de alto nivel (en un archivo separado). A continuación, tiene su compilador generar un lenguaje ensamblador lista o haga que su pantalla depurador "intercalada asamblea".

No sólo la lista le dirá cómo los implementos compilador de código, pero también le mostrará las convenciones de llamada. Mucho más fácil que anuncio a S. O. y por lo general más rápido. ; -)

C99 tiene un complejo de tipo de datos interno (_Complex). Así que si usted tiene un compilador compatible C99, usted podría compilar una función que devuelve un complejo y compilar este a ensamblador (por lo general con una opción de -S). Allí se puede ver la convención que se toma.

Normalmente se usaría la pila

Si usted está planeando hacer interfaz con C u otro lenguaje de alto nivel, por lo general usted aceptaría la dirección de un búfer de memoria como un argumento a su función y devolver su valor complejo poblando ese búfer. Si este es el montaje de solo, entonces se puede definir su propia convención de utilizar cualquier conjunto de registros que desea, aunque por lo general tan solo te hacerlo si tiene una razón específica (por ejemplo, el rendimiento).

scroll top