assembly x86 nasm

assembly - ¿Cómo funciona $ funciona exactamente en NASM?



x86 (1)

message db "Enter a digit ", 0xA,0xD Length equ $- message

¿Se usa para obtener la longitud de una cuerda?
¿Cómo funciona internamente?


$ es la dirección de la posición actual antes de emitir los bytes (si los hay) para la línea en la que aparece. La Sección 3.5 del manual no entra en muchos detalles.

$ - msg es como hacer here - msg , es decir, la distancia en bytes entre la posición actual (al final de la cadena) y el inicio de la cadena. ( Consulte también este tutorial sobre etiquetas y directivas NASM como resb )

(Relacionado: la mayoría de los otros ensambladores x86 también usan $ la misma manera, excepto para GAS que usa . ( Punto ). El ensamblador MMIX usa @ , que tiene el significado semántico correcto).

Para comprenderlo mejor, puede ser útil ver qué sucede cuando se equivoca: .com/questions/26897633/… . Esta persona usó

HELLO_MSG db ''Hello, World!'',0 GOODBYE_MSG db ''Goodbye!'',0 hlen equ $ - HELLO_MSG glen equ $ - GOODBYE_MSG

resultando en hlen incluyendo la longitud de ambas cuerdas.

EQU evalúa el lado derecho de inmediato, a un valor constante. (En algunos ensambladores como FASM, equ es una sustitución de texto y debe usar glen = $ - GOODBYE_MSG para evaluar con $ en esta posición, en lugar de evaluar $ en una mov ecx, glen posterior mov ecx, glen instrucción mov ecx, glen o algo así. Pero el NASM evalúa en el lugar; use %define para sustituciones de texto)

Usar $ es exactamente equivalente a poner una etiqueta al comienzo de la línea y usarla en lugar de $ .

El ejemplo del tamaño del objeto también se puede hacer usando etiquetas regulares:

msg: db "Enter a digit " msgend: Length equ msgend - msg Length2 equ $ - msg ; Length2 = Length newline: db 0xA,0xD Length3 equ $ - msg ; Length3 includes the /n/r LF CR sequence as well. ; sometimes that *is* what you want

Puede poner Length equ msgend - msg cualquier lugar, o mov ecx, msgend - msg directamente. (A veces es útil tener una etiqueta al final de algo, por ejemplo, cmp rsi, msgend / jb .loop en la parte inferior de un bucle.

Por cierto, generalmente es CR LF, no LF CR.

Ejemplos menos obvios:

times 4 dd $

se ensambla de la misma manera (pero sin crear una entrada en la tabla de símbolos o entrar en conflicto con un nombre existente):

here: times 4 dd here

En times 4 dd $ , $ no se actualiza a su propia dirección para cada dword, sigue siendo la dirección del inicio de la línea. (Pruébelo en un archivo por sí mismo y reduzca el binario plano: es todo ceros).

Pero un bloque %rep se expande antes de $ , entonces

%rep 4 dd $ %endrep

produce 0, 4, 8, 12 (a partir de una posición de salida de 0 en un binario plano para este ejemplo).

$ nasm -o foo rep.asm && hd foo 00000000 00 00 00 00 04 00 00 00 08 00 00 00 0c 00 00 00

Codificación manual de desplazamientos de salto:

Una call directa normal es E8 rel32 , con el desplazamiento calculado en relación con el final de la instrucción. (es decir, en relación con EIP / RIP mientras la instrucción se está ejecutando, porque RIP contiene la dirección de la siguiente instrucción. Los modos de direccionamiento relativos a RIP también funcionan de esta manera). operando, la dirección del final es $+4 . Por supuesto, podría poner una etiqueta en la siguiente línea y usarla.

earlyfunc: ; before the call call func ; let NASM calculate the offset db 0xE8 dd func - ($ + 4) ; or do it ourselves db 0xE8 dd earlyfunc - ($ + 4) ; and it still works for negative offsets ... func: ; after the call

Salida de desmontaje (desde objdump -drwC -Mintel ):

0000000000400080 <earlyfunc>: 400080: e8 34 00 00 00 call 4000b9 <func> # encoded by NASM 400085: e8 2f 00 00 00 call 4000b9 <func> # encoded manually 40008a: e8 f1 ff ff ff call 400080 <earlyfunc> # and backwards works too.

Si obtiene el desplazamiento incorrecto, objdump colocará la parte simbólica como func+8 , por ejemplo. El desplazamiento relativo en las primeras 2 instrucciones de llamada difiere en 5 porque la call rel32 tiene una longitud de 5 bytes y tienen el mismo destino real, no el mismo desplazamiento relativo. Tenga en cuenta que el desensamblador se encarga de agregar el rel32 a la dirección de las instrucciones de llamada para mostrarle las direcciones de destino absolutas.

Puede usar db target - ($+1) para codificar el desplazamiento para un corto jmp o jmp . (Pero tenga cuidado: db 0xEB, target - ($+1) no está bien, porque el final de la instrucción es en realidad $+2 cuando coloca tanto el código de operación como el desplazamiento como múltiples argumentos para la misma pseudoinstrucción de db ).

Relacionado: $$ es el comienzo de la sección actual , por lo que $ - $$ es qué tan lejos de la sección actual se encuentra. Pero esto solo está dentro del archivo actual, por lo que vincular dos archivos que ponen cosas en .rodata es diferente de tener bloques de dos section .rodata en el mismo archivo fuente. Vea ¿Cuál es el verdadero significado de $$ en nasm ?

Con mucho, el uso más común es times 510-($-$$) db 0 / dw 0xAA55 para rellenar (con db 0 ) un sector de arranque a 510 bytes, y luego agregar la firma del sector de arranque para obtener 512 bytes. ( El manual NASM explica cómo funciona esto )