tutorial syscall learn language inc assembler nasm

syscall - ¿Cuál es la diferencia entre equ y db en NASM?



nasm x86 (3)

len: equ 2 len: db 2

¿Son lo mismo, produciendo una etiqueta que puede usarse en lugar de 2 ? Si no, ¿cuál es la ventaja o desventaja de cada formulario de declaración? ¿Se pueden usar indistintamente?


La primera es igual, similar a la de C:

#define len 2

en el sentido de que en realidad no asigna ningún espacio en el código final, simplemente establece que el símbolo de len sea ​​igual a 2. Luego, cuando usa len más adelante en su código fuente, es lo mismo que si estuviera usando el constante 2 .

El segundo es define byte , similar a C:

int len = 2;

En realidad, asigna espacio, un byte en la memoria, almacena un 2 allí y establece que len sea ​​la dirección de ese byte.

Aquí hay un código psuedo-assembler que muestra la distinción:

line addr code label instruction ---- ---- -------- ----- ----------- 1 0000 org 1234 2 1234 elen equ 2 3 1234 02 dlen db 2 4 1235 44 02 00 mov ax elen 5 1238 44 34 12 mov ax dlen

La línea 1 simplemente establece la dirección del conjunto en 1234 , para que sea más fácil explicar lo que está sucediendo.

En la línea 2, no se genera ningún código, el ensamblador simplemente carga elen en la tabla de símbolos con el valor 2 . Como no se ha generado ningún código, la dirección no cambia.

Luego, cuando lo usa en la línea 4, carga ese valor en el registro.

La línea 3 muestra que db es diferente, en realidad asigna algo de espacio (un byte) y almacena el valor en ese espacio. Luego carga dlen en la tabla de símbolos, pero le da el valor de esa dirección 1234 lugar del valor constante 2 .

Cuando más tarde use dlen en la línea 5, obtendrá la dirección, la cual tendría que no tener en cuenta para obtener el valor real 2 .


Resumen

NASM 2.10.09 salida ELF:

  • db no tiene ningún efecto mágico: simplemente genera bytes directamente en el archivo de objeto de salida.

    Si esos bytes están frente a un símbolo, el símbolo apuntará a ese valor cuando se inicie el programa.

    Si estás en la sección de texto, tus bytes se ejecutarán.

    El tiempo que usa db o dw , etc., que no especifica el tamaño del símbolo: el campo st_size de la entrada de la tabla de símbolos no se ve afectado.

  • equ hace que el símbolo en la línea actual tenga st_shndx == SHN_ABS valor mágico en su entrada de tabla de símbolos.

    En lugar de enviar un byte a la ubicación del archivo de objeto actual, lo envía al campo st_value de la entrada de la tabla de símbolos.

Todo lo demás se sigue de esto.

Para comprender lo que realmente significa, primero debe comprender los conceptos básicos del estándar ELF y la relocation .

Teoría SHN_ABS

SHN_ABS le dice al vinculador que:

  • La reubicación no debe hacerse en este símbolo.
  • st_value campo st_value de la entrada del símbolo se utilizará directamente como valor

Contraste esto con los símbolos "regulares", en los que el valor del símbolo es una dirección de memoria y, por lo tanto, debe pasar por la reubicación.

Ya que no apunta a la memoria, los símbolos SHN_ABS pueden eliminarse efectivamente del ejecutable mediante el enlazador insertándolos.

Pero aún son símbolos regulares en los archivos de objetos y ocupan memoria allí, y podrían compartirse entre varios archivos si son globales.

Uso de la muestra

section .data x: equ 1 y: db 2 section .text global _start _start: mov al, x ; al == 1 mov al, [y] ; al == 2

Tenga en cuenta que dado que el símbolo x contiene un valor literal, no se debe hacer ninguna referencia [] para él como para y .

Si quisiéramos usar x de un programa en C, necesitaríamos algo como:

extern char x; printf("%d", &x);

y puesta en el asm:

global x

Observación empírica de salida generada.

Podemos observar lo que hemos dicho antes con:

nasm -felf32 -o equ.o equ.asm ld -melf_i386 -o equ equ.o

Ahora:

readelf -s equ.o

contiene:

Num: Value Size Type Bind Vis Ndx Name 4: 00000001 0 NOTYPE LOCAL DEFAULT ABS x 5: 00000000 0 NOTYPE LOCAL DEFAULT 1 y

Ndx es st_shndx , entonces vemos que x es SHN_ABS mientras que y no lo es.

También vea que el Size es 0 para y : db de ninguna manera le dijo que era de un solo byte de ancho. Simplemente podríamos agregar dos directivas db para asignar 2 bytes allí.

Y entonces:

objdump -dr equ

da:

08048080 <_start>: 8048080: b0 01 mov $0x1,%al 8048082: a0 88 90 04 08 mov 0x8049088,%al

Así que vemos que 0x1 se incluyó en la instrucción, mientras que y obtuvo el valor de una dirección de reubicación 0x8049088 .

Probado en Ubuntu 14.04 AMD64.

Docs

http://www.nasm.us/doc/nasmdoc3.html#section-3.2.4 :

EQU define un símbolo a un valor constante dado: cuando se usa EQU, la línea de origen debe contener una etiqueta. La acción de EQU es definir el nombre de etiqueta dado al valor de su (solo) operando. Esta definición es absoluta, y no puede cambiar más tarde. Así por ejemplo,

message db ''hello, world'' msglen equ $-message

define msglen como la constante 12. msglen no se puede redefinir más adelante. Esta tampoco es una definición de preprocesador: el valor de msglen se evalúa una vez, usando el valor de $ (consulte la sección 3.5 para obtener una explicación de $) en el punto de definición, en lugar de evaluarlo donde sea que se haga referencia y use el valor de $ en el punto de referencia.

Ver también

Pregunta análoga para GAS: ¿ Diferencia entre .equ y .word en ARM Assembly? .equiv parece ser el equivalente de GAS cerrado.


equ : tiempo de preprocesador. de forma análoga a #define, pero la mayoría de los ensambladores carecen de un #undef, y no pueden tener nada más que una constante atómica de un número fijo de bytes en el lado derecho, por lo que las listas flotan, se duplican, no son compatibles con la directiva equ de la mayoría de ensambladores.

db : tiempo de compilación. el valor almacenado en db se almacena en la salida binaria por el ensamblador en un desplazamiento específico. equ le permite definir constantes que normalmente tendrían que estar codificadas o requerir una operación mov para obtenerlas. db le permite tener datos disponibles en la memoria incluso antes de que comience el programa.

Aquí hay un nasm demostrando db:

; I am a 16 byte object at offset 0. db ''----------------'' ; I am a 14 byte object at offset 16 ; the label foo makes the assembler remember the current ''tell'' of the ; binary being written. foo: db ''Hello, World!'', 0 ; I am a 2 byte filler at offset 30 to help readability in hex editor. db '' .'' ; I am a 4 byte object at offset 16 that the offset of foo, which is 16(0x10). dd foo

Un equ solo puede definir una constante hasta la más grande que soporta el ensamblador

Ejemplo de equ, junto con algunas limitaciones comunes de la misma.

; OK ZERO equ 0 ; OK(some assemblers won''t recognize /r and will need to look up the ascii table to get the value of it). CR equ 0xD ; OK(some assemblers won''t recognize /n and will need to look up the ascii table to get the value of it). LF equ 0xA ; error: bar.asm:2: warning: numeric constant 102919291299129192919293122 - ; does not fit in 64 bits ; LARGE_INTEGER equ 102919291299129192919293122 ; bar.asm:5: error: expression syntax error ; assemblers often don''t support float constants, despite fitting in ; reasonable number of bytes. This is one of the many things ; we take for granted in C, ability to precompile floats at compile time ; without the need to create your own assembly preprocessor/assembler. ; PI equ 3.1415926 ; bar.asm:14: error: bad syntax for EQU ; assemblers often don''t support list constants, this is something C ; does support using define, allowing you to define a macro that ; can be passed as a single argument to a function that takes multiple. ; eg ; #define RED 0xff, 0x00, 0x00, 0x00 ; glVertex4f(RED); ; #undef RED ;RED equ 0xff, 0x00, 0x00, 0x00

el binario resultante no tiene bytes en absoluto porque equ no contamina la imagen; todas las referencias a un equ se reemplazan por el lado derecho de ese equ.