Programando en 64bits I PDF Imprimir E-mail
Escrito por Guan   
Lunes, 04 de Abril de 2011 09:22

Bueno lo prometido es deuda, en este artículo voy a intentar explicar las cosas mas significativas que han cambiado en la programación de 64bits y como el jwasm versión 2.05 nos permite trabajar como si la programación de 32bit se tratara.

Lo primero es el cambio en los registros. Los registros de 64bits empiezan con la letra 'r' por lo que tenemos: rax, rbx, rcx, rdx, rdi, rsi, rip, rbp, rsp. Además de estos se han incorporado una serie de registros nuevos también de 64bits, r8, r9, r10, r11, r12, r13, r14 y r15.

 

 

Por su puestos, tenemos acceso a las partes bajas de los registros como antes:

rax       <= 64bits

eax      <= 32bits

ax        <= 16bits

al / ah  <= 8 bits

 

Para el caso de los registros nuevos el acceso es

r8           <= 64 bits

r8d         <= 32 bits

r8w         <= 16 bits

r8b          <= 8 bits (el byte menos significativo)

 

La devolución de las funciones se realiza por el registro rax o si es un número real por el registro xmm0.

Uno de los grandes cambios es la convección de llamada, ya no se usa el stdcall sino el fastcall.

En fastcall los 4 primeros parámetros se pasan por registros, y los siguientes por pila, de tal forma que:

 

1º Argumento <= rcx

2º Argumento <= rdx

3º Argumento <= r8

4º Argumento <= r9

 

Seguimos contando cosas nuevas, y es que el programador de la función es el encargado de pasar a la pila el valor de estos primeros argumentos que son pasados por registro, esto argumentos son los llamados "Shadow variables". El programador al llamar a una función SIEMPRE debe de reservar espacio en la pila para estos argumentos, aun cuando la función no reciba argumentos, y es también el responsable de liberar ese espacio de la pila cuando se retorna de la función.

Desde el punto de vista de la creación de una función, todo lo que sería reserva de espacio para las variables locales, así como la memoria necesaria para alojar los parámetros de las funciones que se van a llamar dentro de la función, es lo que se conoce como marco de pila (stack frame)

Esto en MASM64 se debería de tratar usando las macros:

 

.ALLOCSTACK

.ENDPROLOG

.PUSHFRAME

.PUSHREG

.SAVEREG

.SETFRAME

 

Un ejemplo extraído del MSDN

; ml64 frmex2.asm /link /entry:frmex2 /SUBSYSTEM:CONSOLE

_text SEGMENT

frmex2 PROC FRAME

push rbp

.pushreg rbp

sub rsp, 010h

.allocstack 010h

mov rbp, rsp

.setframe rbp, 0

.endprolog ; modify the stack pointer outside of the prologue

sub rsp, 060h ; we can unwind from the following AV because of the frame pointer

mov rax, 0

mov rax, [rax] ; AV!

add rsp, 060h

add rsp, 010h

pop rbp

ret

frmex2 ENDP

_text ENDS

END

 

Como pueden ver si lo comparamos con la programación de 32bits esto es un poco lio.

Otro problema que se presentan en los SO de 64 a partir del Vista (solo he trabajado en 64bits en Windows desconozco esto bajo linux) es que antes de llamar a una función/API, la pila debe de estar alineada a un tamaño de QWORD, en caso contrario el programa corre el riesgo de romper por una excepción.

 

Pues bien todo esto, y los problemas con las macros del ml64.exe, lo soluciona el compilador jwasm mediante el uso de la directiva option. Usando option frame:auto nos ahorramos el tener que preocuparnos con los problemas de alineamiento de pila y el stack frame, el compilador lo hace por nosotros.

 

Y usando option win64:1 el copilador asigna el valor de los registros correspondientes que se usan para pasar los argumentos en una función a las Shadow Variables por nosotros.

 

Con esto ya estamos ante un entorno de trabajo parecido al que teníamos al trabajar bajo 32bits.

Una cosa mas a tener en cuenta en los 64bits, es que hay ciertos registros llamados "inalterados". Estos registros no deben de variar su valor tras salir de una función, estos registros son: rdi, rsi, rbx, r12, r13, r14 y r15

Para eso en la declaración de las funciones podemos poner

 

function proc uses rdi

...

function endp

 

Con esto rdi es guardado en la pila al inicio y retoma su valor al salir. Según los registros que usemos en nuestras funciones los deberemos de salvar para evitar posibles excepciones.

 

Equivalente a lo que hemos comentado pasa con los registros para el uso de la coma flotante. Si la función a crear utiliza parámetros reales, los registros a usar son:

XMM0 <= 1º Argumento

XMM1 <= 2º Argumento

XMM2 <= 3º Argumento

XMM3 <= 4º Argumento


Y si tocamos alguno de los registros XMM en nuestro código, los que deben de conservar su valor son: XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14 y XMM15


Faltaría hablar de la gestión de excepciones la cual ha cambiado completamente, pero es un tema que a la fecha del presente artículo aun no controlo, eso lo veremos mas adelante en un futuro post.

Última actualización el Miércoles, 06 de Abril de 2011 11:34
 

Comentarios 

 
0 #2 guan 04-05-2012 20:24
Hola Yury,

Revisa mi artículo sobre jwasm, ahí tienes los enlaces al kit de programación que uso para trabajar en asm de 64bits.
 
 
0 #1 yury euceda 04-05-2012 09:53
Muchas gracias Guan, me será muy útil todo lo que expones en tus artículos... Me gustaría saber cuáles son las herramientas y librerias para poder desarrollar programas en ensamblador de 64 bits en entorno windows 7 64 bits? Me ayudas por favor?
 

Escribir un comentario


Código de seguridad
Refescar

Artículos relacionados

Idioma

Spanish English French German Italian Portuguese Russian