PA1

 

PA1.1

 

 

1. Implementar la estructura CPU_state utilizada para simular registros

Actualmente en nemu \ include \ cpu \ reg.h.

Todos sabemos que los registros de la CPU son memoria compartida, por lo que se necesita la unión (recuerdo que hay una respuesta en Internet, así que no hablaré de eso)

Después de la implementación:

2. Pregunta de pensamiento: en la función cmd_c (), cuando se llama a cpu_exec (), se pasa el parámetro -1. ¿Sabe qué significa esto?

cput_exec () está en nemu \ src \ monitor \ cpu-exec.c. Lo encontraremos:

n es un entero sin signo y -1 es el número más grande. Entonces, el bucle for puede ejecutar el número máximo de bucles, y la función ecex_wrapper () es ejecutar la instrucción actual apuntada por% eip y actualizar% eip. Finalmente, se pueden ejecutar todas las instrucciones.

 

3. Un solo paso si N

Primero, comprenda el propósito de estas tres funciones readline (), strtok (), sscanf ().

En nemu \ src \ monitor \ debug \ ui.c.

Se puede saber que luego de leer el comando que ingresamos con readline, usamos strtok () para descomponer la primera cadena (separada por espacios), y luego compararla con el nombre en cmd_table [] y ejecutar la función correspondiente.

Agregue si en cmd_table; en la función de un solo paso, debe usar strtok () para descomponer el carácter una vez, luego use sscanf para convertirlo en un número y ejecutar el número correspondiente de veces.

4. Imprimir registro

Similar a 1.3, printf genera el registro.

regsl [i], el nombre del registro de 32 bits, regsw [i], 16 bits y regsb [i], 8 bits.

En la estructura de registro anterior CPU_state, podemos saber que cpu.gpr [i] ._ 32 pone el valor del registro de 32 bits, que es similar a 16 y 8 bits.

5. Escanear la memoria

El folleto mencionado anteriormente: la memoria es simulada por la matriz grande pmem definida en nemu \ src \ memory \ memory.c. En el proceso de ejecutar el programa cliente, vaddr_read () y vaddr_write () siempre se usan para acceder a la memoria simulada. vaddr, paddr representan la dirección virtual y la dirección física respectivamente. 

La función vaddr_read llama a paddr_read y pasa dos parámetros: dirección de inicio y longitud de escaneo. Entonces obtenemos la dirección de la cadena y la longitud del escaneo por separado a través de strtok, lo convertimos al formato requerido con sscanf y llamamos a la función vaddr_read para escanear la memoria.

PA1.2

1 Primero necesitamos entender las expresiones regulares.

2 Luego, agregaremos reglas para el token.

Necesita agregar espacios == () * / + -! = && ||! 16 reglas como las variables de registro decimal hexadecimal. Después de entender las expresiones regulares, sabemos que + * / | debe escaparse debido a la existencia de metacaracteres de expresiones regulares. Los primeros tres deben escaparse dos veces, una vez con \, \ y luego + * /. Algunos como (el código ascii se puede usar directamente, y otros como || deben asignarse en enum. La forma de la variable de registro hexadecimal decimal se expresa mediante una expresión regular, por ejemplo: {"\\ $ [a-dA -D] [hlHL] | \\ $ [eE]? (Ax | dx | cx | bx | bp | si | di | sp) ", TK_register} es un registro. {" \\ | \\ | ", TK_logical_OR} Sí ||. Nota: Pon! = Antes! Para evitar que se reconozca como! And =.

3 A continuación, necesitamos mejorar la función make_token ().

El propósito de la función es identificar cada token en la expresión. En el bucle for, use la función regexec () para hacer coincidir la cadena de texto de destino y compararla con la expresión regular en las reglas definidas previamente [i]. Pmatch.rm_so == 0 indica la primera posición de la cadena coincidente en la cadena de destino, pmatch. rm_eo indica la posición final, la posición y substr_len indican la posición y la longitud de lectura después de la lectura. Después de identificar con éxito las reglas correspondientes del carácter o cadena, necesitamos usar la instrucción switch para representar cada parte de la expresión con el número correspondiente, y copiar el ==, número decimal, etc. en tokens [nr_token] .str. Utilice la función strcpy o strncpy.

4 Compruebe si los corchetes izquierdo y derecho coinciden.

Mi idea es que en la función check_parentheses (), se establecen dos variables left = 0 y flag = 0. Si tokens [p] es un paréntesis izquierdo, entonces se juzga de tokens [p + 1] a tokens [q]. Cuando se encuentra el paréntesis izquierdo, left ++; cuando se encuentra el paréntesis derecho, left--, y determinar si left es igual a 0 y la posición actual está al final, si left es 0 y la posición actual no está al final, a la bandera se le asigna un valor de 1, lo que indica que los paréntesis no coinciden , Si la izquierda es menor que 0, afirme (0), porque muestra que hay una situación similar a (4 + 3)) * ((2 + 1) mencionada en el folleto. Finalmente, si (izquierda == 0) && (tokens [q ] 为)) && flag! = 1, es decir, la expresión tiene solo un par de paréntesis, ubicados en ambos extremos, coincidiendo entre sí, luego devuelve 1; si se deja! = 0, entonces afirma (0), lo que indica que puede haber paréntesis no coincidentes; otros Devuelve 0 en todos los casos;

5 Busque el operador dominante.

Puede establecer otra variable en las reglas para registrar la prioridad del operador. La idea es, independientemente del registro hexadecimal decimal y la negación, establecer el valor de op en la posición inicial (si la expresión es! 2, devuelva la posición donde está op!), Y luego juzgue al operador en la posición actual, (si el En el paréntesis izquierdo, use r para registrar el logaritmo de los paréntesis y luego determine la precedencia del operador a partir de un dígito después del rango encerrado entre los paréntesis izquierdo y derecho, omita los operadores entre paréntesis) y compare la precedencia con el operador en la posición opuesta, La prioridad es menor o igual que la posición op, entonces op = posición actual. Entre ellos, -y * necesitan juzgar si es la primera posición o si la anterior es un signo, excepto el paréntesis derecho, para evitar reconocer erróneamente el puntero y la multiplicación y el signo menos y el signo menos.

6 Mejore la función de evaluación eval ().

La función eval (p, q) básicamente juzga si la primera y la última dirección de la expresión son razonables, y asevera (0) no es razonable;

Luego juzgue si pq es igual, si es igual, es decimal o hexadecimal o un registro, si es un registro, use funciones como regsl para determinar si es de 32 bits o de 16 bits, y determine qué posición es la primera, y luego evalúe . Los registros de 8 bits se evalúan uno por uno. No importa qué, eventualmente debe ser un número y devolver ese valor;

Luego use la función check_parentheses para determinar si la expresión está rodeada por un par de paréntesis coincidentes y, de ser así, la expresión entre paréntesis se evalúa de forma recursiva.

Si los juicios anteriores son todos negativos, use la función find_dominant_operator para averiguar la posición del operador en el último paso, op, y luego llame a la función eval de forma recursiva para encontrar los valores val1 y val2 de las expresiones izquierda y derecha de op, y luego corresponda según el operador op Operación y devolución del resultado. Juzgue *, ya sea * 0x100000 o * (0x10000 + 4), haga un juicio, luego use eval para obtener un número entero y use vaddr_read () para leer la memoria. A juzgar por el signo negativo, el signo negativo no se considerará una op, por lo que solo se puede descomponer en la expresión más pequeña, como 3--2, y finalmente eval (2,3), que es -2. ¡Juzga !, ya sea! 2 o! (1-1) estas dos situaciones, haz un juicio. Las restantes sentencias no se dicen.

PA1.3

1 Estructura de puntos de seguimiento

Sobre la base de la estructura original, se debe agregar a la estructura el nuevo valor, el valor anterior, el tipo (a juzgar si es un punto de ruptura o un punto de monitoreo), si se abre y la expresión de monitoreo.

2Realizar la gestión del grupo de puntos de monitoreo

new_wp es tomar un nodo de la lista libre a la lista principal, asignarle la expresión y el valor, modificar el conmutador y generar el número del nodo. Utilice expresiones regulares para determinar si es un punto de interrupción, si lo es, el tipo es b, de lo contrario es w.

El uso de expresiones regulares se puede modelar en https://www.jb51.net/article/119725.htm

La función free_wp atraviesa la lista de encabezados enlazados hasta que se encuentra el nodo correspondiente a NO, se elimina del encabezado y se agrega a la lista de enlaces libres. Modifique el tipo, la expresión, el valor, cambie al mismo tiempo.

3 Realice puntos de monitoreo

Como se menciona en las notas de la clase, siempre que cpu_exec () termine de ejecutar una instrucción, llame a la función juez_wp para evaluar todas las expresiones y determinar si ha cambiado. Si cambia, devuelve -1, hace una pausa, genera un mensaje y regresa. Modifique en cpu_exec.c, y necesita declarar la función juez_wp (). La función juez_wp () está escrita en watchpoint.c.

Utilice info w para imprimir la información del punto de control. Aquí, la función print_wp () se llama en cmd_info.

Elimina el punto de seguimiento. Simplemente llame a la función free_wp en cmd_d.

4 puntos de interrupción

Eso es lo que dijo 2, use expresiones regulares para determinar si se trata de un formato de punto de interrupción: $ eip == 0x16 número hexadecimal, la función regcomp () compila la expresión regular, la ejecución devuelve 0 con éxito, luego el tipo es b, de lo contrario es w.

5

find. -name "* [. h | .cpp]" | xargs wc -l se puede utilizar para calcular el número de líneas en el archivo .c .h.

find. -name "* [. cpp | .h]" | xargs grep "^." | wc -l se usa para calcular el número de líneas en el archivo .c .h sin espacios.

 

 

 

 

Supongo que te gusta

Origin blog.csdn.net/weixin_41242380/article/details/81813084
PA1
PA1
PA1
PA1
PA1
PA1
PA1
241
Recomendado
Clasificación