MANIPULAR POSICIONES DE MEMORIA EN UN PROGRAMA ASSSEMBLY
En assembly podemos mover valores de una posición de memoria origen a una posición de memoria destino, siendo esta, una de las actividades mas frecuentes en un programa assembly. Para mover valores de memoria de un register a otro, usamos la instrucción MOV(x) existen 3 variables de este comando dependiendo del tamaño del origen y del destino, estas son:
- MOVL : Mueve un valor de 32 bits. movl %eax, %ebx
- MOVW: Mueve un valor de 16 bits. movw %ax, %bx
- MOVB: Mueve un valor de 8 bits. movb %ah, %bh
NOTA: Las instrucciones anteriores corresponden a una plataforma de 32 bits en una plataforma de 64 bytes, los movimientos de memoria son de 64, 32 y 16 respectivamente
La elección de una de las opciones del comando MOV depende del tamaño de las posiciones o variables que estemos manejando, por ejemplo:
Moviendo valores entre Registers:
movl %eax, %ebx
Moviendo valores entre Regiters y Memoria
location:
.int 10
movl %eax, location
movl location, %ebx
Moviendo valores a un register:
movl $10, %ebx
Moviendo valores a una localizacion de Memoria
location:
.int 0
movb $10, location
Moviendo valores a una localizacion de Memoria indexada (Array)
ArrayIntegers
.int 10,20,30,40,50
movl %eax, ArrayIntegers(0,2,4) //Asigna la posición de memoria del tercer elemento del array (30)
Lo anterior corresponde a la siguiente estructura en assembly
BaseAddress(Offset, Index, Size)
Donde se indican en primer lugar desde que posición se debe iniciar a contar el registro de memoria, el indice que se desea obtener y finalmente el numero total de registros existentes en el array.
Asignación indirecta de valores usando registers
Usando el carácter “$” antes del nombre de una etiqueta toma la dirección de memoria de la variable y no su valor, es decir, lo que en lenguaje C se conoce como un puntero, accedemos a la localización de memoria directamente, por ejemplo
movl $location, %edi: Mueve la localización de memoria de la variable “location” al register %edi
movl $9, (%edi): Establece el valor nueve a la dirección de memoria a la que apunta el register %edi
movl $9, 4(%edi): Establece el valor nueve a la direccion de memoria a la que apunta el register (%edi + 4 bytes de posiciones en memoria)
movl $9, -2(%edi): Establece el valor nueve a la dirección de memoria a la que apunta el register (%edi – 2 bytes de posiciones en memoria)
El los casos anteriores, al estar el register entre paréntesis, se indica que no se debe copiar la dirección de memoria de la variable al register, en lugar de esto, se debe copiar el valor de la variable al valor de la dirección de memoria a la que apunta el register.
Ejemplo de operaciones Mov
#Ejemplo simple que enseña como usar los tipos de datos y las instrucciones MOVx.dataHelloWorld:.ascii «Hello»
ByteLocation: .byte 10 Int32bytes: .int 6 Int16bytes: .short 3 Float: .float 10.10 IntAsArrays: .int 10,20,30,40,50 .bss .comm BufferLargo, 10000 .text .globl _start _start: nop #1. Mov valor a un register. movl $10, %eax #2. Mov valor a una variable de 16 bytes. movw $5, Int16bytes #3. Mover datos entre registers. movl %eax, %ebx #4. Mover datos desde memoria a un register. movl Int32bytes, %eax #5. Mover datos desde un register a memoria. movb $7, %al movb %al, ByteLocation #6. Mover datos en la localizacion de memoria indexada. movl $0, %ecx movl $2, %edi movl $22, IntAsArrays(%ecx, %edi, 4) #7. Se obtiene el valor del register y se asigna a otro. movl $Int32bytes, %eax movl (%eax), %ebx movl $9, (%eax) movl $1, %eax movl $0, %ebx int $0x80 |
Para compilar: as –gstabs -o MovDemo.o MovDemo.s
Para enlazar el programa Objeto con un programa ejecutable: ld -o MovDemo MovDemo.o
Finalmente ejecutarlo: ./MovDemo
Procedemos a depurar con gdb: gdb ./MovDemo
Ahora, en modo de depuración podemos visualizar los valores que tienen cada una de las variables y los registers en cada momento de ejecución, con el fin de ver el desplazamiento de la memoria en cada una de las instrucciones ejecutadas.
Primera instrucción:
#1. Mov valor a un register.
movl $10, %eax
(gdb) info registers
rax 0xa 10
rbx 0x0 0
rcx 0x0 0
…..
Segunda instrucción:
#2. Mov valor a una variable de 16 bytes.
movw $5, Int16bytes
(gdb) x/1dh &Int16bytes
0x6000fe <Int16bytes>: 5
Tercera instrucción:
#3. Mover datos entre registers.
movl %eax, %ebx
(gdb) info registers
rax 0xa 10
rbx 0xa 10
……………
Cuarta instrucción:
#4. Mover datos desde memoria a un register.
movl Int32bytes, %eax
(gdb) info registers
rax 0x6 6
rbx 0xa 10
……………
Quinta instrucción:
#5. Mover datos desde un register a memoria.
movb $7, %al
(gdb) info registers
rax 0x7 7
rbx 0xa 10
…………….
Sexta instrucción:
#6. Mover datos en la localización de memoria indexada.
movl $0, %ecx
movl $2, %edi
movl $22, IntAsArrays(%ecx, %edi, 4)
movl $0, %ecx
(gdb) info registers
rax 0x7 7
rbx 0xa 10
rcx 0x0 0
…………….
movl $2, %edi
(gdb) info registers
rax 0x7 7
rbx 0xa 10
rcx 0x0 0
rdx 0x0 0
rsi 0x0 0
rdi 0x2 2
…………….
movl $22, IntAsArrays(%ecx, %edi, 4)
(gdb) x/5dw &IntAsArrays
0x600104 <IntAsArrays>: 10 20 22 40
0x600114 <IntAsArrays+16>: 50
Séptima instrucción:
#7. Se obtiene el valor del register y se asigna a otro.
movl $Int32bytes, %eax
movl (%eax), %ebx
movl $9, (%eax)
– movl $Int32bytes, %eax
(gdb) print &Int32bytes
$1 = (<data variable, no debug info> *) 0x60010a
(gdb) s
48 movl (%eax), %ebx
(gdb) info registers
rax 0x60010a 6291722
rbx 0xa 10
rcx 0x0 0
rdx 0x0 0
rsi 0x0 0
rdi 0x2 2
#Se ha copiado el valor de la dirección de memoria de la variable al register (0x60010a ).
-movl (%eax), %ebx
rax 0x60010a 6291722
rbx 0x6 6
rcx 0x0 0
rdx 0x0 0
rsi 0x0 0
rdi 0x2 2
#Se ha copiado el valor del register eax al register ebx (el valor es 6).
-movl $9, (%eax)
(gdb) x/1dw &Int32bytes
0x60010a <Int32bytes>: 9
Se ha cambiado el valor de la variable que apunta a la dirección de memoria del register %eax, es decir la variable Int32bytes, el nuevo valor es 9 para la variable Int32bytes, ya que este valor se ha establecido a la dirección de memoria de %eax, que indirectamente es la variable Int32bytes.