Estoy empezando a aprender ensamblador, leyendo un libro que me recomendaron.
El libro se titulo Programming From the Ground Up, es un libro muy conocido.
Primero que todo decir que soy absolutamente nuevo en linux también, y practicamente en programación, así como totalmente nuevo en ensamblador.
El problema que tengo es que el libro lo explica todo para sistemas x86, cuyos registros tienen 32 bits de memoria, y mi ordenador tiene el procesador x64 de 64bits, así como la gran mayoria de nuevos ordenadores, por lo que hay incompatibilidad entre los códigos que explican y los que yo puedo utilizar.
He estado leyendo por internet, y según dice, puedo utilizar normalmente las partes de 32 bits de los registros, ignorando los 32 restantes, escribiendo, por ejemplo, "%eax" en vez de "%rax". Hasta aquí todo bien, no he tenido ningún problema.
Pero el problema viene a la hora de guardar variables en el stack. Para ello no sirve utilizar, por ejemplo, "pushl %eax", sino que hay que utilizar "pushq %rax".
Dicho esto, necesito algo de ayuda. En el libro, se crea la función power (para elevar un numero a un exponente), y se utiliza esta. El ejemplo dado es para 32bits, por lo que se tendrían que hacer algunos cambios. Lo he intentado, pero algo hago mal, puesto que el programa se linkea correctamente, pero cuando lo ejecuto, me dice "violación del segmento". Aquí pongo el codigo original del libro y mi intento de "convertir" a 64 bits.
Código original 32 bits:
Código:
#PURPOSE: Program to illustrate how functions work
# This program will compute the value of
# 2^3 + 5^2
#
#Everything in the main program is stored in registers,
#so the data section doesn’t have anything.
.section .data
.section .text
.globl _start
_start:
pushl $3 #push second argument
pushl $2 #push first argument
call power #call the function
addl $8, %esp #move the stack pointer back
pushl %eax #save the first answer before
#calling the next function
pushl $2 #push second argument
pushl $5 #push first argument
call power #call the function
addl $8, %esp #move the stack pointer back
popl %ebx #The second answer is already
#in %eax. We saved the
#first answer onto the stack,
#so now we can just pop it
#out into %ebx
addl %eax, %ebx #add them together
#the result is in %ebx
movl $1, %eax #exit (%ebx is returned)
int $0x80
#PURPOSE: This function is used to compute
# the value of a number raised to
# a power.
#
#INPUT: First argument - the base number
# Second argument - the power to
# raise it to
#
#OUTPUT: Will give the result as a return value
#
#NOTES: The power must be 1 or greater
#
#VARIABLES:
# %ebx - holds the base number
# %ecx - holds the power
#
# -4(%ebp) - holds the current result
#
# %eax is used for temporary storage
#
.type power, @function
power:
pushl %ebp #save old base pointer
movl %esp, %ebp #make stack pointer the base pointer
subl $4, %esp #get room for our local storage
movl 8(%ebp), %ebx #put first argument in %eax
movl 12(%ebp), %ecx #put second argument in %ecx
movl %ebx, -4(%ebp) #store current result
power_loop_start:
cmpl $1, %ecx #if the power is 1, we are done
je end_power
movl -4(%ebp), %eax #move the current result into %eax
imull %ebx, %eax #multiply the current result by
#the base number
movl %eax, -4(%ebp) #store the current result
decl %ecx #decrease the power
jmp power_loop_start #run for the next power
end_power:
movl -4(%ebp), %eax #return value goes in %eax
movl %ebp, %esp #restore the stack pointer
popl %ebp #restore the base pointer
ret
Mi intento en 64bits , que da el error "violación de segmento" (imagino que es porque intenta acceder a algún lugar de la memoria no reservado para el prgroama, desconozco el motivo) cuando, después de linquear, escribo "./power" en la consola de linux (hay algunos comentarios que he puesto tan solo para aclararme yo):
Código:
.section .data
.section .text
.globl _start
_start:
#ponemos en el stack al numero 3(será el segundo argumento) y al 2(primer #argumento)
pushq $3 #push second argument
pushq $2 #push first argument
call power #call the function
##Devolvemos el stack pointer a donde estaba antes (antes de los argumentos)
addl $8, %esp #move the stack pointer back
pushq %rax #save the first answer before
#calling the next function
pushq $2 #push second argument
pushq $5 #push first argument
call power #call the function
addl $8, %esp #move the stack pointer back
popq %rbx #The second answer is already
#in %eax. We saved the
#first answer onto the stack,
#so now we can just pop it
#out into %ebx
addl %eax, %ebx #add them together
#the result is in %ebx
movl $1, %eax #exit (%ebx is returned)
int $0x80
#PURPOSE: This function is used to compute the value of a number raised to a power.
#INPUT
#First argument : the base number
#Second argument : the power to raise it to
#OUTPUT
# Will give the result as a return value
#THE POWER MUST BE 1 OR GREATER
# %ebx: base number
# %ecx: power
#Local variable: -4(%epb) current result
#%eax: temporary storage
.type power, @function
power:
##Pone el base pointer actual en el stack (el sack pointer %esp se cambia solo)
push %rbp
##Pone el valor del stack pointer en el base pointer
movl %esp, %ebp
##Le quita un word al stack pointer (para guardar una local variable)
subl $4, %esp
#8 es el first argument (porque es el segundo que metemos), 12 es el second (es el primero que metemos en el stack)
movl 8(%ebp), %ebx
movl 12(%ebp), %ecx
#Guardamos la base en la local storage
movl %ebx, -4(%ebp)
##Loop de hacer potencia:
potencia_loop:
##Si el exponente es 1, ya hemos acabado
cmpl $1, %ecx
je exit_loop
##Movemos el resultado actual a %eax
movl -4(%ebp), %eax
##Multiplicamos el resultado actual por la base 1 vez (se guarda en la derecha):
imull %ebx, %eax
##Guardamos el resultado actual en la local storage:
movl %eax, -4(%ebp)
##restamos 1 al exponente:
decl %ecx
jmp potencia_loop
exit_loop:
##mueve la local variable a %eax, que es el parametro de retorno
movl -4(%ebp), %eax
##restablece el stack pointer
movl %ebp, %esp
##pop quita el último valor del stack y lo pone en el registro indicado, es decir el antiguo %epb, y lo ponemos en %ebp (recuperamos el antiguo %ebp)
pop %rbp
##Retornamos a donde nos encontramos antes (adress guardada en el stack), y suma 4 al stack (se deshace de la return adress)
ret
Basicamente mi intento se basa en sustiuir todos los "pushl %exx" por "pushq rxx" y lo mismo con los pop... Obviamente no ha funcionado.
Agradecería que alguien que sepa del tema me pudiera ayudar y resolver esta duda, puesto que hasta que no consiga resolverlo no me quedo tranquilo y no puedo continuar con el libro.
Y cualquier recomendación de cualquier libro/recurso que me pueda ayudar a iniciarme en esto, también será muy agradecido. Gracias!