Consulta sobre condiciones y saltos

Iniciado por zonahurbana, 17 Mayo 2014, 05:40 AM

0 Miembros y 1 Visitante están viendo este tema.

zonahurbana

Bueno, luego de haber aprendido un poco más acerca de las instrucciones y direccionamiento conseguí escribir un programa para graficar una circunferencia y hacer que esta se desplace... y funcionaba perfectamente hacia la derecha e izquierda.
El problema es que luego de agregar desplazamientos hacia otros lados me apareció este error:
CitarRelative jump out of range by 002Bh bytes

Conseguí solucionarlo agregando saltos intermedios pero el programa no está tan claro como antes justamente por agregar esos "medios saltos", ¿existirá otra forma de manejar ese error?
Tal vez alguien quiera recibir mi código para ayudarme a ver cómo evitar saltos tan largos :S

Gracias de antemano.
Nunca dejar de aprender es importante, más allá del ritmo que se siga ...

Vaagish

CitarTal vez alguien quiera recibir mi código para ayudarme a ver cómo evitar saltos tan largos :S

Mejor pone el codigo aca,, usa las etiquetas correspondientes.. es mas probable conseguir una solucion asi..

Suerte! Saludos!

zonahurbana

Quise evitar poner el código porque cierta vez me pasó que publiqué mi desarrollo en un foro y "ciertos compañeros" resultaron plagiándolo y cambiándolo ligeramente... felizmente el profesor no lo notó  :silbar:

Logré solucionarlo de 2 formas...
la 1ra es usando "saltos intermedios" como ya mencionaba inicialmente,
y la 2da fue conviertiendo los "saltos provocados por condiciones", por "condiciones que llaman a procedimientos" (es decir cambié muchos JNZ por CALL).

De hecho me ha llevado bastante tiempo hacer esa conversión para que todo funcione entre procedimientos, ya que algunas cosas no podían simplemente cambiarse, o bien resultaban generando bucles infinitos. Usé varios RET para lidiar con eso. Y como todo funciona bien me parece que no hay restricción en los CALL, es decir, pueden invocarse procedimientos que se encuentrán muy lejos del lugar de donde se invoca.

Lo que aún no estoy seguro es qué ocurre si nunca escribo RET en un procedimiento, ya que la estructura normal tengo entendido que es esta:
Código (asm) [Seleccionar]
NOMBRE PROC NEAR
  ; Código
  RET
NOMBRE ENDP


Si no uso RET la secuencia de ejecución ya no se devuelve al lugar de donde se invocó el procedimiento NOMBRE, entonces acaba la ejecución de ABC?
Considerando que ABC es un procedimiento que invoca a NOMBRE.

O continúa ejecutando los procedimientos que están debajo de NOMBRE como producto de no haber encontrado RET?

O tal vez eso resulta en un error porque no encontró RET y encontró ENDP  :-X

Gracias, y espero que puedan ayudarme nuevamente con esta duda.
Nunca dejar de aprender es importante, más allá del ritmo que se siga ...

cpu2

Cita de: zonahurbana en 17 Mayo 2014, 21:41 PMLo que aún no estoy seguro es qué ocurre si nunca escribo RET en un procedimiento

Pues que no volverias al offset que debes. Mejor te explico como funciona call y ret.

Call lo que hace es hacer un push y un jump, "pushea" el siguiente offset que esta despues de el, y luego hace el jump en el offset que le indicaste.

Ret es lo contrario hace un pop y luego el jump que le hace volver donde te quedaste, despues del call. Puedes substituir el ret con algo como esto, siempre y cuando no haigas "pusheado" mas cosas, si no tendrias que incrementar el stack.

Código (asm) [Seleccionar]
jmp *(%rsp)

;

push %rax
jmp *8(%rsp)


No se como seria en MASM.

Un saludo.

P.D: A por cierto se me olvido explicarte como puedes substituir call, bueno seguramente te haces una idea.

zonahurbana

Entendí la idea de cómo es que funcionan, pero la verdad no entendí el código que escribió :S
Los programas los compilamos con un comando llamado TASM, el profesor nos dijo que era conocido como "Turbo Assembler".
Su código se me hace extraño porque siempre usé una etiqueta luego de JMP y un registro o una variable luego de PUSH.

Cómo sería en el siguiente caso?
Código (asm) [Seleccionar]
BORRAR PROC NEAR
  ; Código sin RET
BORRAR ENDP

GRAFICAR PROC NEAR
  ; Código
  RET
GRAFICAR ENDP


Significa que como no se encontró RET en BORRAR la ejecución pasó por sobre el "BORRAR ENDP" y ejecuto lo de GRAFICAR para luego retornar al lugar desde donde se invocó BORRAR? (ya que CALL BORRAR supuestamente hizo un PUSH y el RET de GRAFICAR tomo ese offset para ir allí).

Muchas gracias por su ayuda.
Nunca dejar de aprender es importante, más allá del ritmo que se siga ...

Vaagish

#5
Yo creo que lo correcto es usar esas funciones.. (Call, con su respectivo Ret) Siempre que la consigna no te diga que no podes hacerlo.. para algo esta..
Si hay algo de donde se aprende mucho es del desensamblador.. ahi uno puede ver realmente los errores.. pero lo mejor es ver como un compilador hace ciertas cosas.. y da muchas ideas ;)

Advertencia - mientras estabas escribiendo, una nueva respuesta fue publicada. Probablemente desees revisar tu mensaje.

Un programa en ASM no se compila, se ensambla.. TASM no es un comando, TASM es el programa que invocas desde la linea de comandos.. (el ensamblador) y le pasas como parametro (al programa TASM) tu codigo en ensamblador,, o sea, ensamblas tu codigo.. Seguramente siempre usaron jmp's para aprender el funcionamiento.. pero a mi parecer es mas correcto usar funciones.. (las funciones o procedimientos son esos que tenes entre etiquetas.. las que invocas con call)

Suerte!! Saludos!

Eternal Idol

Cita de: zonahurbana en 17 Mayo 2014, 23:05 PMCómo sería en el siguiente caso?
Código (asm) [Seleccionar]
BORRAR PROC NEAR
  ; Código sin RET
BORRAR ENDP

GRAFICAR PROC NEAR
  ; Código
  RET
GRAFICAR ENDP


Significa que como no se encontró RET en BORRAR la ejecución pasó por sobre el "BORRAR ENDP" y ejecuto lo de GRAFICAR para luego retornar al lugar desde donde se invocó BORRAR? (ya que CALL BORRAR supuestamente hizo un PUSH y el RET de GRAFICAR tomo ese offset para ir allí).

Si, se continua ejecutando lo siguiente en memoria (sea una instruccion valida o no, asi que mejor siempre retorna, una funcion por logica lo hace).
La economía nunca ha sido libre: o la controla el Estado en beneficio del Pueblo o lo hacen los grandes consorcios en perjuicio de éste.
Juan Domingo Perón

cpu2

Ya te aclaro la duda @EI, pero yo pense que con mi explicacion ya era obvio, call y ret no son mas que jumps que utilizan el stack, es logico que a la hora de hacer un call si no hay un ret o un jump o lo que sea, el code continuara y pasara por encima de "BORRAR ENDP".

Un saludo.

zonahurbana

Gracias por responder.

Ahora solo me queda una duda teórica...
¿Por qué no es correcto decir que se compila? Es decir, la traducción de un lenguaje de programación a código máquina es justamente el proceso de compilación.
Además me pregunto si lenguajes como C++ o Java son traducidos primero a lenguaje ensamblador y luego recién a código máquina...
Nunca dejar de aprender es importante, más allá del ritmo que se siga ...

cpu2

Te lo explico con mis palabras, compilar es pasar de un lenjuage de nivel alto-medio a ensamblador, por ejemplo gcc tiene una opcion para mostrar el codigo ensamblador que te genera.

Por eso cuando ensamblas un code en ASM esta mal dicho "compilar", ya que no se compila se ensambla directamente, el ensamblador crea el objeto y el linker el binario.

Un saludo.