Universidad Nacional de Córdoba Facultad de Ciencias Exactas, Físicas y Naturales

SISTEMAS DE COMPUTACION
Trabajo Recuperatorio Instructivo y Uso de DEBUG

Alumno: Romero, Marco Antonio Profesora: Ing. Silvia Arias

I.E.

Año 2011

los contenidos de la memoria. la forma cómo éstas afectan a las banderas. editar programas en hexa y muchas más cosas. .USO DE DEBUG Posiblemente sea el debug el depurador más rudimentario que existe. Recuérdese que los registros de esta arquitectura son un subconjunto elemental de aquellos presentes en modelos más modernos de la familia '86. S=0. Previamente es necesario darle un nombre al archivo con el comando N. D=0. saltar sobre procedimientos. para editar el contenido de CX. y en el mismo orden tenemos: V=0. además permite ensamblar código elemental usando los mnemotécnicos del 8086. Usando DEBUG es posible observar el comportamiento de las instrucciones. Incluso es posible correr programas cargados en memoria utilizando breakpoints elementales. Por ejemplo. el código de las instrucciones. Esto muestra el contenido de los registros del procesador incluyendo varias banderas: en el ejemplo. nos permite encontrarlo hoy en cualquier máquina DOS o Windows. pero el hecho que desde el principio haya sido provisto con el sistema operativo. y usando el comando R (mostrar registros) nos mostrará algo similar a esto: AX=0000 BX=0000 CX=0000 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000 DS=1332 ES=1332 SS=1332 CS=1332 IP=0100 NV UP EI PL NZ NA PO NC 1332:0100 C3 RET . I=1. Se puede especificar la dirección a partir de la que se desea transferir datos o bien usar el vector por defecto DS:DX. Debug nos presenta el contenido actual del registro y la posibilidad de ingresar un nuevo valor para sustituirlo. Z=0. Con el sistema operativo DOS (MS-DOS = Microsoft Disk Operating System) se incluye un programa para observar el comportamiento de los registros del CPU 80386. Los comandos L y W se utilizan para leer y escribir en archivos de disco. P=0 y C=0 Si ponemos después de la R el nombre de un registro. Arrancando desde una ventana DOS. AC=0. ejecutar paso a paso. hay que poner el comando RCX. es posible modificar su contenido. Muchas tareas elementales pueden realizarse sin otra ayuda que el Debug y por eso vamos a ver algunos comandos básicos. La cantidad de bytes transferida en cada operación es el contenido de BX:CX.

El lector . b) Cuando se invoca (como en el ejemplo) sin argumentos. En las siguientes secciones de hace un breve resumen de los comandos de DEBUG. el contenido de la memoria es arbitrario. obsérvese lo siguiente: a) DEBUG opera bajo DOS.Todos los comandos de DEBUG se invocan usando una sola letra y son los siguientes: 01) A (assemble) 02) C (compare) 03) D (dump) 04) E (enter) 05) F (fill) 06) G (go) 07) H (aritmética hexadecimal) 08) I (input) 09) L (load) 10) M (move) 11) N (name) 12) O (output) 13) Q (quit) 14) R (register) 15) S (search) 16) T (trace) 17) U (unassemble) 18) W (write) En particular.

La sintaxis es: C <bloque> <dirección> <bloque> es la dirección de inicio y fin de un bloque o. Se presupone que la longitud de ambos bloques es la misma. DS:. ENTER (E) Este comando permite cambiar los contenidos de localidades específicas de memoria. La sintaxis es: . ES:. La sintaxis es: A <dirección> Prácticamente cualquier mnemotécnico es soportado por DEBUG. ASSEMBLE (A) El comando A se usa para introducir mnemotécnicos de ensamblador y que éstos se traduzcan directamente a lenguaje de máquina en memoria. COMPARE (C) Este comando compara y reporta diferencias entre los contenidos de dos bloques de memoria. 1987. <dirección> es el inicio de otro bloque. 1. "USING ASSEMBLY LANGUAGE" de Allen L. Wyatt. Una excepción es que DEBUG no puede diferenciar entre NEAR y FAR returns. incluyendo los especificadores de "override" de segmento (CS:. 1. la dirección de inicio y la longitud del bloque.1.Interesado en detalles puede consultar. DUMP (D) Este comando despliega el contenido de una serie de localidades de memoriaLa sintaxis es: D <dirección1> <dirección2> Ambas direcciones son opcionales. 1.3. si se preceden con "L". la 2a es la dirección de fin. 1. QUE Corporation.4. La 1a es la dirección de inicio de despliegue. por ejemplo. asume que RET es "near" y RETF es "far".2. SS:).

permite ejecutar el código cargado en memoria. Por ejemplo: E 100 'Buenas Tardes' Establece el patrón "42 75 65 6E 61 73 20 54 61 72 64 65 73" en memoria a partir de la localidad 100H. la serie se repite hasta llenar el bloque.E <dirección> <cambios> <dirección> es el inicio de los cambios y <cambios> es una lista opcional de los cambios deseados. También permite establecer puntos de quiebre (breakpoints) que son direcciones en las que se detiene la ejecución del programa. 1. Si <valor de relleno> representa menor bytes que los que se necesitan para llenar el bloque. FILL (F) Este comando llena un bloque de memoria con un valor específico o una serie de valores. Si se está depurando un programa. GO (G) Este comando ejecuta el código en memoria. <valor de relleno> es(son) el(los) valor(es) con los que debe de llenarse el bloque. Por ejemplo. Si se activa la barra espaciadora DEBUG pasa a la siguiente localidad. La sintaxis es: . la dirección de inicio y la longitud del bloque. Cuando no se especifica <cambios> se entra en un modo especial en el que DEBUG despliega los valores de <dirección>. los caracteres ASCII deben estar entre comillas simples o dobles. Entonces es posible teclear nuevos valores que reemplacen a los que se muestran. La sintaxis es: F <bloque> <valor de relleno> <bloque> es la dirección de inicio y final o . cualquiera de las siguientes dos líneas llena (con 0s) el bloque DS:00FF: F DS:0000 DS:00FF 0 F DS:0000 LFF 0 1.5.6. si se preceden con "L". Si se teclea "-" DEBUG regresa a la localidad anterior. Los cambios pueden ser especificados en la línea de comandos en cualquier combinación de números hexadecimales o caracteres ASCII.

En este caso <buffer> es opcional. Si no se suministra la combinación <numdisco> <sectorini> <numsector> DEBUG presume que se desea leer un archivo. 1. que es el código de interrupción. Se lee el dato y se despliega en pantalla. 1. La sintaxis es: H <valor1> <valor2> Como resultado de lo anterior. Go inicia con la dirección contenida en CS:IP. Si no se especifica <inicio>. DEBUG reemplaza el código en las direcciones de quiebre por el valor hexadecimal CC.8. Debe usarse el comando N (ver más adelante) para especificar el archivo a leer. Si DEBUG llega a CC todos los puntos de quiebre son restituidos.). LOAD (L) Este comando se usa para cargar un archivo o sectores de disco a memoria.7. 1=B. los registros se despliegan (como con el comando R [véase adelante]) y se usan para la ejecución. INPUT (I) Este comando "jala" un byte de un puerto. <quiebre10> <inicio> es la dirección de inicio de ejecución. No se pueden leer más de 80H (128) sectores. <quiebre1> hasta <quiebre10> son direcciones opcionales de paro del programa. <sectorini> es el sector de disco absoluto (en hexadecimal) a leer. Para lograr los quiebres. DEBUG regresa dos valores: la suma y la resta de los argumentos en hexa..9. 2=C. etc. <numdisco> es el número (opcional) del disco de donde se leerá la información (0=A. La sintaxis es: L <buffer> <numdisco> <sectorini> <numsector> <buffer> es la dirección en donde se carga la información. Aritmética Hexadecimal (H) Este comando ejecuta restas y suma hexadecimales.G =<inicio> <quiebre1> <quiebre2> . Éste se carga en CS:0100.. . <numsector> es la cantidad de sectores a leer. 1. La sintaxis es: I <puerto> <puerto> es la dirección del puerto a leer.

La expresión tal cual se tecleó se almacena en CS:0081. IP. DX. precedida por el número de bytes tecleados.1. 1.5. PC o F.1. La sintaxis es: O <puerto< <valor> <valor> es el byte hexadecimal a escribir en <puerto>. CS. MOVE (M) Este comando mueve un bloque de memoria de una localidad a otra.). NAME (N) Este comando se usa para especificar el nombre del archivo usado por los comandos LOAD y WRITE. DI.11. ES. DS. El bloque de origen y la dirección destino pueden traslaparse.13.14. 1. SP. QUIT (Q) Este comando se usa para salir de DEBUG.10. IP y PC son sinónimos. La sintaxis es: M <bloque> <dirección> <bloque> es como arriba (ver 2. 1. REGISTER (R) Este comando despliega los registros del CPU y los valores de las banderas. 1. SS. OUTPUT (O) Este comando pone un byte en el puerto especificado.12. CX. BX. <nomarch2> es la especificación de archivo que será colocada en CS:006C. . <dirección> es la dirección destino. SI. BP. La sintaxis es: R <registro> <registro> es el nombre opcional y puede ser alguno de los siguientes: AX. La sintaxis es: N <nomarch1< <nomarch2> <nomarch1> es la especificación de archivo completa que será "parseada" y colocada en el bloque de control en CS:005C.

1.1. TRACE (T) Este comando permite ejecución paso-a-paso de las instrucciones de máquina. La sintaxis es la siguiente: U <alcance> <alcance>. es ya sea un par de direcciones de inicio y fin o. WRITE (W) Este comando se usa para escribir un archivo a sectores individuales de disco a disco. <numsector> es la cantidad de sectores a leer. SEARCH (S) Este comando permite buscar en un bloque de memoria una secuencia específica de valores. La sintaxis es: T =<inicio> <cuenta> <inicio> es la dirección de inicio de la traza <cuenta> es el número de instrucciones a trazar 1. Después de cada instrucción se muestra el estado de los registros. UNASSEMBLE (U) Este comando decodifica los valores de un grupo de localidades de memoria a mnemotécnicos de 8086. <sectorini> es el sector de disco absoluto (en hexadecimal) en donde empieza la escritura. 1. que es opcional. La sintaxis es: W <buffer> <numdisco> <sectorini> <numsector> <buffer> es la dirección de donde se carga la información.16. etc. 1=B. si se precede con "L". <valor_a_buscar> es(son) el(los) valor(es) que deseamos buscar en el bloque. La sintaxis es: S <bloque> <valor_a_buscar> <bloque> se define como antes (ver la sección 1_1).).17. <numdisco> es el número (opcional) del disco en donde se escribirá la información (0=A.15. Si no se suministra la combinación <numdisco> <sectorini> <numsector> DEBUG presume que el inicio . 2=C. la dirección de inicio y la longitud del área a desensamblar.18. No se pueden escribir más de 80H (128) sectores.

En este caso <buffer> es opcional.4543 mov bx. Debe usarse el comando N (ver arriba) para especificar el archivo a escribir.de archivo es CS:100. pero la cuarta ocupó 4 bytes y la INT 20 sólo ocupó 2 bytes. Ejemplo: N <nomarchivo> <cr> BX:CX <--. Para sacar algo a pantalla. pero en la 202 (AX ocupó la 200 y 201) . Sabemos que los códigos ASCII son E=45h y C=43h.4345 mov [200]. 5) Cuando hacemos mov ax. sean direcciones o datos. 2) A medida que vamos ingresando el programa. Por ahora sólo queremos practicar de manera que abramos una ventana DOS y escribamos DEBUG (enter).idem para BX. Nos proponemos hacer que ECCE sea escrito en memoria.2000 <cr> W <cr> PROGRAMA A MODO DE EJEMPLO: Usaremos el Debug para ensamblar un programa que realice algo tan útil como dejar en alguna parte de la memoria el nombre de nuestra escuela ECCE.finalizar y salir a Debug . de manera que nuestro programa puede lucir así: a 100 1322:0100 1322:0103 1322:0106 1322:0109 1322:010D 1322:010F Al apretar "enter" una vez más.ax mov [202]. Antes de escribir BX:CX debe ajustarse al número de bytes que desean grabarse. Podemos ver algunas curiosidades del listado anterior: 1) Debug asume que los números que le damos. debemos leer el tutorial de +gthorne (Greythorne the Technomancer).cargamos BX con "CE" en ASCII . W no puede escribir a archivos con la extensión EXE o HEX. 4) Aunque nada se ha hablado de la INT 20. 3) Las tres primeras instrucciones MOV ocuparon de memoria de programa 3 bytes cada una. son hexadecimales. Debug nos devuelve su prompt "-" y ya estamos listos para nuestro próximo comando. es lo que por el momento usaremos para terminar el programa.bx int 20 . nos va devolviendo la dirección de almacenamiento de la próxima instrucción que escribiremos.cargamos el registro AX con el dato 4543 (EC en ASCII) .ponemos AX en la dirección de memoria 200 . que será nuestro paso siguiente. en el offset 200h de nuestro segmento de datos DS.

Luego cargamos "CE" en BX y lo dejamos en la 202. Tanto AX como BX han sido meros vehículos para cargar la memoria con datos y sólo a los efectos didácticos porque también está permitido : MOV word ptr [200]. encerramos la dirección entre corchetes [].4543 . de modo que no ganamos espacio poniéndola en lugar del más elíptico procedimiento de cargar AX y con éste escribir en 200. pero las líneas que siguen hacia abajo son alguna cosa que estaba en memoria. y en nuestro programa sólo hemos usado 0Fh bytes (15 en decimal). ya que Debug desensambla por defecto los 20h primeros bytes desde la dirección indicada (o desde la que esté apuntando). Por lo general los valores no coinciden de una a otra PC.4543 MOV BX. El listado es más largo. Son los códigos de operación (opcodes) que es lo que en definitiva se almacena en memoria y lo que nuestro Pentium debe interpretar y ejecutar. Nuestra lógica es muy simple: cargamos el ASCII "EC" en AX y lo dejamos en la dirección 200. Debug compiló nuestro programa ingresado en assembly y produjo ese código binario con representación hexadecimal para que el Pentium lo interprete. en una columna entre la dirección y el listado en lenguaje assembly puso unos números hexadecimales.4345 MOV [200]. sin importar cómo escribimos nuestro código) 1322:0100 1322:0103 1322:0106 1322:0109 1322:010D B84345 BB4543 A30002 891E0202 CD20 MOV AX. Es muy importante saber distinguir entre la dirección y el valor almacenado en esa dirección de memoria. salvo que las instalaciones de software sean idénticas y en ambas estén corriendo previamente al DEBUG los mismos programas. Observemos: Debug no deja de sorprendernos. Veamos cómo se ve nuestro programa usando el comando desensamblar: -u 100 (desensamble a partir de la CS:100) (Nótese que Debug listará usando sólo mayúsculas. .BX INT 20 NOTA: el valor de 1322 (el contenido del registro CS) es válido para la PC donde se escribió este ensayo.referencia al contenido de una posición de memoria.AX MOV [202]. cargar la word de memoria 200 directamente con el dato 4543 Esta instrucción ocupa 6 bytes. El prefijo "word ptr" es para que el procesador sepa que lo que moveremos a 200 es una word y no un byte o double-word.

Corramos el programa con el comando G.AX Ejecutemos el comando D 200 para ver qué hay en la memoria: hasta ahora 00 de la dirección 200 a la 203. Repitamos el comando F 200 23F 00 para dejar nuevamente en cero la memoria y ejecutemos nuestro programa paso a paso. Debug nos debe informar: El programa ha finalizado con normalidad.4345 es la próxima instrucción. Hemos guardado AX en la dirección 200 y por lo tanto debería haber un 4543 ("EC" en ASCII) en las direcciones 200 y 201. pero como ya se ha dicho. Todo ok. Para estar seguros.F 200 23F 00 con lo que le indicamos a Debug que debe llenar el bloque de memoria que comienza en 200 y termina en 23F con "00". vamos a llenar este espacio con ceros usando el comando . Como deseamos leer claramente nuestro nombre ECCE. Lo relevante es: AX=4543 e IP=0103 1322:0103 BB4543 MOV BX. porque hasta aquí sólo hemos cargado los registros AX y BX.BX es la próxima instrucción.45 a partir de la 200 (miremos además en la columna ASCII del Debug. Para ello usamos el comando D 200. 1322:0109 891E0202 MOV [0202]. en donde claramente nos dice CEEC) y están al revés. Nos debe decir que IP apunta a 0100: 1322:0100 B84345 MOV AX. Primero el comando R. Qué habrá pasado? Será que hemos escrito BX en 200 y AX en 202?. Verifiquemos con el comando D 200: . Esperábamos los hexa 45. Debemos ver las cuatro primeras filas del listado con los datos en 00. escribamos nuevamente el comando D 200. Usemos al Debug para depurar.4543 -T (comando para ejecutar una sola instrucción).43. Veamos si nuestras siglas brillan en las posiciones 200 a 203 con el comando D 200. Para nuestro caso CS vale 1322. Hagamos otro T. tenemos que ver qué hay en la posición de memoria 200. Ejecutemos con T: 1322:0106 A30002 MOV [200].Antes de correr el fabuloso programa que hemos escrito. Bien! todo resulto correcto.43. Estamos listos para correr nuestro programita. Con el comando R nos aseguramos que CS:IP esté apuntando al inicio de nuestro programa (o sea a CS:0100). que nos muestra la basura que hay en nuestra RAM desde DS:0200 hasta DS:027F. puede que en otra PC tenga otro valor.

4345 1322:0103 MOV BX. debemos rescribir nuestro programa para que en AL se almacene la primera letra ("E") y en AH la segunda ("C")... a la porción más baja del registro (AL) la almacena en la dirección de memoria más baja (200) y a la porción más alta del registro (AH) la almacena en la dirección de memoria más alta (201). Tengo "CE" en lugar de "EC". debemos acostumbrarnos a leer los registro (y a cargarlos.......... QUE PASO???? Está al revés.. y lo mismo para BX: a 100 1322:0100 MOV AX. CE.. Por lo tanto.. .1322:0200 43 45 00 00 . Resulta que lo que leemos en AX como "EC". Y el procesador hace algo sumamente lógico. en la realidad lo debemos asumir como: En AL tengo un 43 ("C") y en AH un 45 ("E")... Todo parece bien pero no funciona? Pero está bien tal como lo hizo Intel.4543 (enter) nuevamente para salir del comando A. ahí fue donde nos equivocamos!) desde la porción más baja hacia la más alta. que nos quedó apuntando a la mitad del programa: RIP (enter) nuestro comando IP 0109 respuesta de Debug :100 (enter) este valor lo ingresamos nosotros para decirle que queremos a IP=0100 Ejecutamos el programa nuevamente con G y examinamos la memoria con D 200 para ver nuestro sigla ECCE ya en su lugar y en el orden debido.. Si leemos la memoria en sentido de direcciones ascendentes.... Ahora debemos modificar el registro IP...

Sign up to vote on this title
UsefulNot useful