En MIPS, mientras usamos una instrucción de salto, usamos una etiqueta.

again: nop
    $j again

Entonces, cuando alcanzamos la instrucción de salto, usamos la etiqueta again para mostrar a dónde ir y el valor de la dirección real allí utilizada. Quería saber dónde se almacena la etiqueta nuevamente . Es decir, digamos que nop está almacenado en 0x00400000, y la instrucción de salto está en 0x00400004. Dónde, entonces, se guarda again, ¿cómo sabe MIPS que again apunta a 0x00400000? ¿Se almacena en el área de datos dinámicos del mapa de memoria? Este es el mapa de memoria que he proporcionado para MIPS

También he incluido la pregunta que causó esta confusión a continuación, como referencia.

Dé el código de objeto en hexadecimal para las siguientes instrucciones de rama (be, bne) y jump (j).

... # some other instructions
again:  add ... # there is an instruction here and meaning is insignificant
    add ... # likewise for the other similar cases
    beq    $t0, $t1, next
    bne  $t0, $t1, again
    add ...
    add ...
    add ...
next:   j   again

Suponga que la etiqueta nuevamente se encuentra en la ubicación de memoria 0x10 01 00 20. Si cree que no tiene suficiente información para generar el código, explique.

1
ali.salemwala 5 mar. 2017 a las 20:14

3 respuestas

La mejor respuesta

Cada etiqueta corresponde a una dirección única en la memoria. Entonces, en su ejemplo, y de acuerdo con lo que usted indicó, si la instrucción nop existe en 0x00400000, entonces again corresponderá (no señalará más sobre eso en un segundo) a esa misma dirección.

Las etiquetas pueden existir tanto en el texto como en los segmentos de datos. Sin embargo, en su ejemplo, la etiqueta se muestra en el segmento .text:. Por lo tanto, representa la dirección de una instrucción en lugar de una variable.

Aquí está la distinción importante:

Las etiquetas son parte de la mayoría de los ISA para hacer que el ensamblaje de escritura sea más fácil para los humanos . Sin embargo, es importante recordar que el ensamblaje no es la forma final de código. En otras palabras, en la representación binaria su etiqueta ya no será una gran etiqueta.

Entonces, esto es lo que sucederá:

El ensamblador reconocerá la dirección de memoria asociada con las instrucciones de cada etiqueta. Mantengamos nuestro ejemplo de ejecución de 0x00400000. Luego, en cada instrucción de salto tomará esta dirección y la usará para reemplazar la etiqueta en el código de operación. Poof , no más etiquetas y definitivamente ningún puntero (lo que implicaría que tendríamos otro lugar en la memoria que está almacenando una dirección de memoria).

Por supuesto, la dirección de memoria en sí corresponde a un punto en el segmento de texto en su ejemplo porque coincide con una instrucción.

En pocas palabras, las etiquetas existen para hacernos la vida más fácil. Sin embargo, una vez que se ensamblan, se convierten a la dirección de memoria real de la instrucción / variable que han etiquetado.

1
Faris Sbahi 5 mar. 2017 a las 17:37

La etiqueta en sí no se almacena en ningún lado. Es solo una dirección simbólica para ensamblador / enlazador. El código de operación de salto j again almacena la dirección resultante real, como un número.

El enlazador pegará todos los archivos de objetos, fusionará todos los símbolos en los archivos de objetos y completará las direcciones relativas correctas + creará una tabla de reubicación para el cargador del sistema operativo y producirá un archivo ejecutable.

El SO al cargar el ejecutable también cargará la tabla de reubicación, modificará / completará las instrucciones que funcionan con direcciones absolutas de acuerdo con la dirección real, donde se cargó el binario, luego tira la tabla de reubicación y ejecuta el código.

Por lo tanto, las etiquetas son simplemente "fuente" para el programador, alias para una dirección de memoria fija particular, para evitar que el programador cuente los tamaños de código de operación de las instrucciones y calcule las compensaciones de salto en la cabeza o las direcciones de las variables de memoria.

Es posible que desee verificar el "archivo de lista" de su ensamblador (a menudo /l modificador), mientras compila alguna fuente de ensamblaje, para ver código de máquina bytes producidos (ninguno para etiquetas).


Su código de "tarea" cuando se compila en 0x00400000 tiene este aspecto (configuro esos add para que t1 = t1 + t1 tenga algo allí):

 Address    Code        Basic                     Source

0x00400000  0x01294820  add $9,$9,$9          4     add  $t1,$t1,$t1
0x00400004  0x01294820  add $9,$9,$9          5     add  $t1,$t1,$t1
0x00400008  0x11090004  beq $8,$9,0x00000004  6     beq  $t0, $t1, next
0x0040000c  0x1509fffc  bne $8,$9,0xfffffffc  7         bne  $t0, $t1, again
0x00400010  0x01294820  add $9,$9,$9          8     add  $t1,$t1,$t1
0x00400014  0x01294820  add $9,$9,$9          9     add  $t1,$t1,$t1
0x00400018  0x01294820  add $9,$9,$9          10    add  $t1,$t1,$t1
0x0040001c  0x08100000  j 0x00400000          11   next:   j   again

Como puede ver, cada instrucción real produce un valor de 32 bits, que a veces se denomina "código de operación" (código de operación), ese valor es visible en la columna "Código". La columna "Dirección" dice, donde este valor se almacena en la memoria, cuando se carga el ejecutable y está preparado para ejecutarse. La columna "Básico" muestra las instrucciones desensambladas de los códigos de operación, y en la última posición hay la columna "Fuente".

Ahora vea cómo los saltos condicionales codifican el valor de salto relativo en 16 bits (beq $8, $9 el código de operación es 0x1109, y los otros 16 bits 0x0004 son el valor extendido de signo de 16 bits "cuánto saltar" ). Ese valor se entiende como el número de instrucciones fuera de la "posición actual", donde actual es la dirección de la siguiente instrucción, es decir.

0x0040000c + 0x0004 * 4 = 0x0040001c = target address

* 4, porque en MIPS cada instrucción tiene exactamente 4 bytes de longitud, y el direccionamiento de memoria funciona por byte, no por instrucción.

Lo mismo ocurre con el siguiente bne, el código de operación en sí es 0x1509, el desplazamiento es 0xfffc, eso es -4. =>

0x00400010 + (-4) * 4 = 0x00400000

El salto absoluto usa una codificación diferente, es un código de operación de 6 bits 0b000010xx (xx son dos bits de dirección almacenados en el primer byte junto con el código de operación j, en este ejemplo son cero) seguido de una dirección 26b dividida por cuatro 0x0100000, porque cada instrucción debe comenzar en una dirección alineada, por lo que sería un desperdicio codificar los dos bits menos significativos, siempre serían 00. 0x100000 * 4 = 0x00400000 ... Soy demasiado vago para comprobar cómo funciona en MIPS, pero creo que j define los bits 2-27, 0-1 son ceros y 28-31 se copian de la corriente ¿pc tal vez? Hacer que la CPU sea capaz de funcionar en un rango completo de direcciones de 4GiB, pero probablemente haya alguna forma especial de saltar entre diferentes "bancos" (4 bits superiores de pc)). No estoy seguro, nunca codifiqué para MIPS, así que no leí las especificaciones de la CPU.

De todos modos, si dice que again: está en 0x10010020, se puede recalcular todo esto para seguir que un código funcional de producción está listo para ejecutarse en 0x10010020 (aunque eso j será complicado, tendría que saber con seguridad cómo se compone la dirección total, si se copian los 4 bits superiores o qué).

Por cierto, la CPU MIPS real retrasa la bifurcación (es decir, la siguiente instrucción después del salto de rama se ejecuta siempre, mientras se evalúa la condición y el salto ocurre después de la siguiente instrucción), y creo que el pc utilizado para calcular la dirección de destino también es 1 instrucción "posterior", por lo que el código correcto para MIPS real tendría que beq delante del segundo add, pero el desplazamiento relativo aún sería 0x0004. :) simple eh? Si no tiene sentido para usted, verifique la configuración de MARS (la emulación de bifurcación retrasada está desactivada de forma predeterminada, para no confundir a los estudiantes), y busque en Google alguna explicación mejor. Una pequeña y divertida CPU que es MIPS. :)

1
CL. 21 sep. 2017 a las 10:37

La conversión de la etiqueta a su dirección correspondiente la realiza el ensamblador de código o el simulador MIPS que está utilizando, por ejemplo, MARS es un simulador MIPS, por lo que MARS está haciendo esa conversión. MARS encontrará la dirección de la etiqueta para usted.

0
Sayed Abdullah Qutb 6 abr. 2019 a las 16:22