2012-03-21 20 views
7

Estoy aprendiendo el lenguaje ensamblador en mi tiempo libre para convertirme en un mejor desarrollador.Lenguaje de ensamblaje - Apiladora

Entiendo la diferencia entre las máquinas basadas en pila y las máquinas basadas en registros a nivel conceptual, pero me pregunto cómo se implementan realmente las máquinas basadas en pila. Si es una máquina virtual, p. JVM o .NET, se ejecuta en una arquitectura basada en registro, p. x86 o x64, entonces debe usar registros en el nivel de ensamblaje (en lo que a mí respecta). Obviamente me falta algo aquí. Por lo tanto, no estoy seguro de la distinción en el lenguaje ensamblador.

He leído artículos aquí, p. Stack-based machine depends on a register-based machine? y también en Wikipedia, pero no creo que respondan mi pregunta directamente.

+0

Ellos * podrían * emularlo en el software, las JVM antiguas lo hicieron. Por lo general, el código de máquina de la pila se compila con código nativo (cualquiera que sea la arquitectura). El código de pila de la máquina es bueno porque tiene una codificación concisa, es fácil de generar a partir de AST y relativamente fácil de analizar. – harold

Respuesta

4

entonces debe utilizar registros en el nivel de ensamblado

No es un requisito, los procesadores tienen una pila de CPU que se comporta de forma muy similar a la pila virtual en el lenguaje intermedio. Puede traducir las instrucciones casi uno a uno a las instrucciones de la CPU. Ciertamente, una de las razones por las que las máquinas virtuales basadas en pila son populares, la inestabilidad es fácil de implementar.

El único problema al hacerlo de esa manera es que el código de la máquina no es muy eficiente. Es el trabajo del optimizador jitter para encontrar formas de utilizar los registros de la CPU de manera eficiente y hacer el código más rápido de esa manera.

El problema opuesto está presente en las máquinas virtuales basadas en registros. Es un problema más difícil de resolver ya que la CPU real no tiene tantos registros como la VM. Por lo tanto, la fluctuación de fase debe encontrar formas de utilizar la pila para derramar los registros que el hardware no proporciona.

7

Las máquinas basadas en apilamientos rara vez se implementan en hardware: solo he oído hablar de una de esas implementaciones, y nunca he tenido la oportunidad de trabajar en una.

En realidad, las máquinas apiladoras se implementan en procesadores basados ​​en registros reales por intérpretes nativos. En esencia, la máquina Stack teórica es emulada por la máquina real basada en el Registro.

Para responder a su pregunta: aunque el código máquina de la máquina de pila no tiene registros, el intérprete nativo que ejecuta estas instrucciones sí tiene registros y los utilizará.

P: ¿Entonces por qué la indirección? A: Portabilidad: el conjunto de instrucciones de la máquina de pila se puede emular en cualquier cantidad de diferentes máquinas basadas en registros. Esto significa que la misma aplicación JVM se puede ejecutar en cualquier máquina que tenga un intérprete, por lo tanto, la vieja consigna de Java "escribir una vez, ejecutar en cualquier lugar"

+0

¿qué quiere decir con "intérprete nativo". ¿Te refieres al compilador JIT (en el caso de .NET)? – w0051977

+0

Por "intérprete nativo" me refiero a que la aplicación que se ejecuta en su máquina local que lee las instrucciones de la máquina Apilamiento las ejecuta. Cada tipo de máquina (y sistema operativo) tendrá un "intérprete nativo" diferente. En el caso de Java, el "intérprete nativo" es la JVM. JIT son algo ligeramente diferente. – Stormcloud

+0

Solo para su referencia, un JIT es algo que convierte las instrucciones de la pila de máquinas en un conjunto equivalente de instrucciones para la máquina nativa (la basada en registro). Este es un intento de darle a la aplicación un rendimiento que sea similar al del procesador nativo, pero al mismo tiempo mantener las ventajas de la portabilidad. – Stormcloud

6

Como referencia, Burroughs B5000 y Inmos Transputer eran máquinas de pila. DEC PDP11 tenían modos de direccionamiento tan flexibles que se podían usar como una máquina de apilamiento. Creo que Niklaus Wirth's Lilith puede haber sido una máquina de apilar (hace más de 20 años, mi mente está cayendo :-)

Realmente no tenían ningún nombre/número de registro en las instrucciones para encontrar operandos, porque estaban en la pila.

Las instrucciones podrían cargar valores inmediatos (constantes) en la pila, o cargar/almacenar en la memoria.

Así que no era add.w r0, r1, r5 o add.w eax, [#fe34]. Hubo add.w.

Así un ejemplo (no en todos exacta, que era más compleja) de una secuencia de ensamblador podría ser

loadstack 0xfe34 -- got fe34 onto stack 
loadstackindirect -- use address on the stack, to load the value at that address 
add.w    -- assumes we already have the other operand on the stack 
        -- result back onto the stack 

Para calcular y cargar un valor en una matriz, la pila podría ser utilizada porque puede haber sin modo de direccionamiento indexado.

De modo que las instrucciones eran pequeñas, y se realizaba mucho trabajo implícitamente con el puntero de la pila y la pila. Transputers IIRC en realidad tenía una pila de solo tres valores, y el compilador (o desarrolladores) tenía que asegurarse de que se mantuviera.

XMOS ahora vendemos un "equivalente" moderno, y empleamos a algunas de las mismas personas.

Han pasado más de 20 años desde que escribí el código de Transputer, así que lo siento por ser un poco vago.

El sistema UCSD Pascal usaba una máquina virtual definida por software, que era una máquina de pila. La idea era hacer algo que fuera portátil para las computadoras nuevas, pero también fácil de escribir, fácil de compilar y un rendimiento razonable. Su máquina virtual se definió en su propio dialecto de Pascal. Cuando fue portado a computadoras reales, los registros se usarían para mantener el puntero de la pila, y es probable que haya algo de ingenio en cómo se manejó la parte superior de la pila (por registros), para obtener un rendimiento razonable.

Cuestiones relacionadas