apuntes sistemas operativos

27
1.1 Que estudia la programación de sistemas. El trabajo de un programador de sistemas es seleccionar, modificar y mantener el complejo software del sistema operativo. Por lo tanto, los programadores de sistemas desempeñan una función de apoyo al mantener el ambiente del software del sistema operativo en el que trabajan los programadores de aplicaciones y los operadores de las computadoras. Se entiende por programación de sistemas el conjunto de programas necesario para que una computadora de una imagen coherente y monolítica ante sus usuarios. El estudio de la programación de sistemas En esta área se estudia la teoría de máquinas y su aplicación en el diseño de sistemas digitales y de arquitectura de computadora

description

unidad 1 sistemas operativos

Transcript of apuntes sistemas operativos

Page 1: apuntes sistemas operativos

1.1Que estudia la programación de sistemas.El trabajo de un programador de sistemas es seleccionar, modificar y mantener el complejo software del sistema operativo. Por lo tanto, los programadores de sistemas desempeñan una función de apoyo al mantener el ambiente del software del sistema operativo en el que trabajan los programadores de aplicaciones y los operadores de las computadoras.Se entiende por programación de sistemas el conjunto de programas necesario para que una computadora de una imagen coherente y monolítica ante sus usuarios.

El estudio de la programación de sistemas En esta área se estudia la teoría de máquinas y su aplicación en el diseño de sistemas digitales y de arquitectura de computadora

Page 2: apuntes sistemas operativos

3.4.- Creación de la Tabla de Símbolos.

La tabla de símbolos es una estructura de datos muy importante en casi todo el proceso de compilación. En ella se guarda durante las primeras fases de compilación los nombres de los identificadores (símbolos) usados en el programa fuente, además de los atributos de cada uno de estos identificadores. Estos identificadores y símbolos junto con sus atributos serán usados posteriormente para realizar funciones como el chequeo de tipos, la asignación de memoria, generación de código objeto etc.

Ejemplo.

Programa X1;          Var X, Y: Integer;                 Z: Real;                 Arreglo: Array [1…100] of int          Procedure compara (a, b: Integer)                    Var n, m: integer;                    Begin ---- End Begin ---- End

Page 3: apuntes sistemas operativos

Manejo de Errores de Léxico

Errores posibles detectados en el análisis de léxico son:

Patrones de tokens que no coincidan con algún patrón válido. Por ejemplo el token #### sería inválido en algunos L.P.

Caracteres inválidos para el alfabeto del el lenguaje. Longitud de ciertos tokens demasiado larga. Generadores de Código Léxico La construcción de un scanner puede automatizarse por medio de un

generador de analizadores de léxico. El primer programa de este tipo que se hizo popular fue Lex (Lesk, 1975)

que generaba un scanner en lenguaje C.

Hoy en día existen muchos programas de este tipo: Flex, Zlex, YooLex, JavaCC, SableCC, etc.

Ejemplo: JavaccJavacc (Java Compiler Compiler) es un generador de scanners y parsers (https://javacc.dev.java.net/).

Toma como entrada especificaciones de léxico (expresiones regulares) y sintaxis (gramática de contexto libre) y produce como salida un analizador de léxico y un parser recursivo descendente.

Se puede usar como pre-procesador de Javacc, a jjtree y a JTB para la construcción del árbol sintáctico.

4.1.- Introducción a las gramáticas Libres de Contexto y Árboles de derivación

El tipo de gramáticas usadas en los LP son llamadas gramáticas de contexto libre, las cuáles, junto con árboles de derivación, fueron estudiadas en el curso de Lenguajes y Autómatas.Un ejemplo de una gramática para un LP simple es la siguiente:

1) SàS;S 2) Sàid := E 3) Sàprint (L)4) Eà id 5) Eà num 6) Eà E + E 7) Eà(S,E)8) Là E 9) Là L , E

(ver ejemplo de derivaciones y árboles de parsing) A continuación veremos un ejemplo de una gramática para Java en formato BNF Gramática Ambigua. Una gramática es ambigua si puede derivar una oración (cadena) con dos diferentes árboles de parsing. La sig. Gramática es ambigüa:

Page 4: apuntes sistemas operativos

Eàid Eànum EàE*E EàE/EEàE+E EàE-E Eà(E)

ya que tiene dos árboles de parsing para la misma oración (árboles para id:=id+id+id con primera gramática y árboles para 1-2-3 con segunda en sig “slice”).

4.2.- Diagramas de Sintaxis

Un método alternativo al BNF para desplegar las producciones de ciertas gramáticas es el diagrama de sintaxis. Ésta es una imagen de la producciones que permite al usuario ver las sustituciones en forma dinámica, es decir, verlas como un movimiento a través del diagrama.

4.3 Precedencia de Operadores

En los dos ejemplos vistos en sección 4.1, los dos árboles de parsing para 1-2-3 significaba diferentes cosas: (1-2)-3=-4 versus 1-(2-3)=2. Similarmente, (1+2)x3 no es lo mismo que 1+(2x3). Es por eso que gramáticas ambiguas son problemáticas para un compilador. Afortunadamente, una gramática ambigua puede convertirse en una no ambigua. Por ejemplo, si queremos encontrar una gramática no ambigua para el lenguaje de la segunda gramática de sección 4.1, lo podemos hacer por medio de dos operaciones: primero, aplicar orden de precedencia a los operadores y segundo aplicar asociatividad por la izquierda. Con esto, tenemos la sig. gramática:

Operador Propósito Asociatividad

:: Scope (unario) De derecha a izquierda

:: Scope (binario) De izquierda a derecha

-> . Selección de miembros De izquierda a derecha

[] Índices De izquierda a derecha

() Llamada a función De izquierda a derecha

++ Postincremento De izquierda a derecha

-- Postdecremento De izquierda a derecha

S

Id := E

E + E

E + E id

Id id

S

Id := E

E + E

E + E id

Id id

Page 5: apuntes sistemas operativos

sizeof Tamaño de un objeto De derecha a izquierda

++ Preincremento De derecha a izquierda

-- Predecremento De derecha a izquierda

* & + - ! ~ Operadores unarios De derecha a izquierda

new Crea un objeto De derecha a izquierda

delete Borra un objeto De derecha a izquierda

() Conversión de tipo (type cast) De derecha a izquierda

->* .* Puntero a un miembro De izquierda a derecha

* / % Operadores multiplicativos De izquierda a derecha

+ - Operadores aditivos De izquierda a derecha

<< >> Operadores bitwise De izquierda a derecha

< > <= >= Operadores de relación De izquierda a derecha

== != Operadores de igualdad De izquierda a derecha

& Y bitwise De izquierda a derecha

^ bitwise O exclusivo De izquierda a derecha

| bitwise O inclusivo De izquierda a derecha

&& Y lógico De izquierda a derecha

|| O lógico De izquierda a derecha

?: Operador condicional De derecha a izquierda

= *= /= += -= >*gt;=&= ^= |= %= <<=

Operadores de asignación De derecha a izquierda

, Operador coma De derecha a izquierda

4.4 Analizador Sintáctico

En esta fase se analiza la estructura de la frase del programa.

El parser es el programa que funciona como núcleo del compilador. Alrededor del parser funcionan los demás programas como el scanner, el analizador semántico y el generador de código intermedio. De hecho se podría decir que el parser comienza el proceso de compilación y su primer tarea es pedir al escáner que envíe los tokens necesarios para llevar a cabo el análisis sintáctico, del estatuto, expresión o declaración dentro de un programa.

También el parser llama rutinas del análisis semántico para revisar si el significado del programa es el correcto.

Por ultimo el parser genera código intermedio para los estatutos y expresiones si no se encontraron errores en ellos.

Page 6: apuntes sistemas operativos

Existen diferentes técnicas o métodos para realizar un análisis sintáctico “Parsing”. Estas técnicas se dividen en dos tipos:

Descendentes

Ascendentes

Las técnicas descendentes realizan su análisis partiendo desde el símbolo inicial de la gramática y realizando derivaciones hasta llegar a producir las hojas o tokens.

Por otra parte las técnicas ascendentes realizan su análisis partiendo de las hojas o tokens y mediante una serie de operaciones llamadas reducciones terminan en la raíz o símbolo inicial de la gramática.

Por lo general las técnicas descendentes son mas sencillas de implementar que las ascendentes, pero por otra parte son menos eficientes

4.4.1 Analizador descendente (LL).

Algunas gramáticas son sencillas de analizarse sintácticamente usando un algoritmo o método cuyo nombre es recursivo descendente. En esta técnica cada producción de la gramática se convierte en una cláusula de una función recursiva.

Un parser Predictivo es aquel que “ predice ” que camino tomar al estar realizando el análisis sintáctico. Esto quiere decir que el parser nunca regresara a tomar otra decisión ( back tracking ) para irse por otro camino, como sucede en las derivaciones. Para poder contar con un parser predictivo la gramática debe de tener ciertas características, entre ellas la mas importante es que el primer símbolo de la parte derecha de cada producción le proporcione suficiente información al parser para que este escoja cual producción usar. Normalmente el primer símbolo mencionado es un Terminal o token.

Page 7: apuntes sistemas operativos

Esta técnica se utilizó o popularizó en los años 70 a partir del primer compilador de pascal implementado con ella. A continuación ilustraremos esto escribiendo un parser recursivo descendente para la siguiente gramática:

S à if E then S else S

S àbegin S L

S àprint E

L àend

L à; S L

E ànum = num

4.4.4 Analizador ascendente(LR LALR)

La debilidad de las técnicas descendentes LL(k) es que deben predecir que producciones usar, después de haber mirado los primeros k tokens de la cadena de entrada.

Una técnica ascendente mas poderosa es la técnica LR(K), la cual pospone la decisión hasta que ha visto los tokens de la entrada correspondientes a la parte derecha de la producción (además de k mas tokens también).

LR(K) quiere decir parser de izquierda a derecha, derivación por la derecha y “lookahead(k)”. Esta técnica fue introducida por primera vez en 1965 por Knuth.

4.5 Administración de tablas de símbolos.

Como se estudió en la unidad anterior, durante el análisis de léxico se inicia la construcción de la tabla de símbolos.

Page 8: apuntes sistemas operativos

Esto ocurre al detectarse las declaraciones en el programa fuente.

Sin embargo también el parser ayuda a realizar esta tarea pues el es quien llama a las respectivas rutinas semánticas para que realicen funciones relacionada con la tabla de símbolos

4.6 Manejo de errores sintácticos y su recuperacion

Dentro del código del parser predictivo estudiado en clase se puede observar que el parser llama un metodo “error” para el manejo de errores sintácticos, que es cuando el parser obtiene un token no esperado.

¿Cómo se maneja el error para esta clase de parsers? Una forma simple es ejecutar una excepción y parar la compilación. Esto como que no es muy amigable par el usuario.

La mejor técnica es desplegar un mensaje de error y recuperarse de este, para que otros posibles errores sintácticos puedan ser encontrados en la misma compilación.

Un error sintáctico ocurre cuando la cadena de tokens de entrada no es una oración en el lenguaje. La recuperación del error es una forma de encontrar alguna oración correcta, similar a la cadena de tokens.

Esto se puede realizar por medio de borrar, reemplazar o insertar tokens.

Por ejemplo la recuperación de un error en S, podría ser al insertar un token if,begin o print (o pretender que existe en la cadena), desplegar el mensaje del error y continuar la compilación.

Ejemplo

void S ( ) { switch ( tok ) {

case If: eat ( if ); E ( ); eat ( then ); S ( );

eat ( else ); S ( ); break;

case begin: eat ( begin ); S ( ); L ( ); break;

case print: eat ( print ); E ( ); break;

Page 9: apuntes sistemas operativos

default: print(“se esperaba if, begin o print”);

}}

Un problema que puede ocurrir al insertar un token faltante es que el programa caiga en un ciclo infinito, por eso a veces es preferible y mas seguro borrar el token, ya que el ciclo terminará cuando el EOF sea encontrado. Esta técnica trabaja muy cercanamente con la tabla de parsing (cuando el parser se implementa con tablas).

En un parser del tipo LR o LALR, la tabla de parsing tiene 4 acciones: shift, reduce, accept y error (entrada nula). Cuando el parser encuentra una acción error, se para el proceso de análisis y se reporta la falla.

4.7 Generadores de código para analizadores sintacticos

Como se vio al final del capítulo 3, Javacc es un generador de scanners y de parsers

Javacc produce un parser del tipo descendente (recursivo) o LL(k) donde k (lookahead) puede ser cualquier número entero positivo.

El parser producido puede correr en cualquier plataforma que cuente con el compilador de Java.

En el ejemplo siguiente del uso de Javacc, utilizamos de nuevo la gramática presentada anteriormente (sección 4.4.1) para un parser predictivo. Ejecutamos Javacc con la anterior gramática y obtendremos un parser recursivo descendente para dicha gramática.

5.1 Analizador semántico

Un compilador no solo tiene que revisar la sintaxis de código fuente, si no también la semántica de este.

Al igual que en los lenguajes naturales (español, ingles, etc.) en los lenguajes de programación existen reglas semánticas para definir el significado de los programas, estatutos, expresiones, etc.

Por ejemplo un error semántico es usar (en pascal ó java) un identificador que no fue anteriormente declarado.

Otro ejemplo de error semántico en un programa es cuando este es compilado y y no se detectan errores pero el momento de ser ejecutado este programa no funciona correctamente.

Page 10: apuntes sistemas operativos

5.2 Verificación de tipos en expresiones.

Cuando mezclamos diferentes tipos en una misma expresión o que llamamos una rutina que no existe existe un error semántico.

Una de las funciones del analizador smántico es verificar que los tipos de una expresión sean compatibles entre si.

Para hacer lo anterior el compilador cuenta con información de los atributos (tipos, tamaño, número de argumento, etc.) de los identificadores en una tabla de símbolos

5.3 Conversión de tipos.

Algunas veces los tipos de una expresión o estatuto son diferente.

Por ejemplo en la asignación,

a = b * c;

El tipo del resultado de evaluar b*c es diferente al de el identificador a.

El compilador algunas veces con ciertos diferentes tipos puede hacer una conversión interna en forma implícita para solucionar el problema. Otras veces el programador explícitamente es el que hace la conversión (casting).

Ejemplo:

float dinero;

int cambio;

dinero = (float) cambio;

5.4 Acciones agregadas en un Analizador sintáctico descendente(top-down)

En un parser recursivo-descendente, el código de las acciones semánticas es mezclado dentro del flujo de control de las acciones del parser. En un parser especificado en javaCC, las acciones semánticas son fragmentos de código de programa en java unido a las producciones gramáticales.

Cada símbolo terminal y noterminal puede asociarse con su propio tipo de valor semántico.

5.5 Pila semántica en un analizador sintáctico ascendente(botton-up)

Page 11: apuntes sistemas operativos

Como fue visto en el capitulo anterior (4), un parser ascendente utiliza durante el análisis una pila. En esta va guardando datos que le permiten ir haciendo las operaciones de reducción que necesita.

Para incorporar acciones semánticas como lo es construir el árbol sintáctico, es necesario incorporar a la pila del parser otra columna que guarde los atributos de los símbolos que se van analizando.

Estos atributos estarían ligados a la correspondiente producción en la tabla de parsing

5.6 Administracion de la tabla de simbolos

El análisis semántico conecta las definiciones de las variables con sus usos, checa que cada expresión tenga un tipo correcto y traduce la sintaxis abstracta a una representación mas simple para generar código máquina.

Esta fase es caracterizada por el mantener la tabla de símbolos (también llamada “environment”) la cual mapea identificadores con sus tipos y localidades.

Cada variable local en un programa tiene un ámbito (scope) dentro del cual es visible. Por ejemplo, en un método MiniJava m, todos los parámetros formales y variables locales declarados en m son visibles solo hasta que finalice m.

5.7 Manejo de errores semánticos.

Cuando el checador de tipos detecta un error de tipos o un identificador no declarado, debe imprimir el mensaje de error y continuar.

Esto debido a que normalmente el programador prefiere que le describan todos los errores posibles del programa fuente.

Esto quiere decir, que si un error de tipos es encontrado, no debe producirse un programa objeto por parte del compilador.

Así, las siguientes fases no deben ejecutarse.

Hasta esta etapa (chequeo de tipos), la parte del compilador se conoce con el nombre de “front End”.

Page 12: apuntes sistemas operativos

VI Generación de código intermedio

Al diseñar la parte de generación de código de un compilador debemos de decidir si genera código directamente para una maquina real o indirectamente a través de un código intermedio Es mucho mas que la separación y generación de código intermedio para la maquina destino

Lenguajes intermedios Los arboles sintácticos ascendentes o descendentes y la notación posfija son dos clases de representación de código intermedio.

Notación infijaEs la notación habitual. El orden de su recorrido es el siguiente 1er operando, operador, segundo operando, cuando se realiza el recorrido de una expresión con este tipo de notación, lo único que cambia es la eliminación de paréntesis

Expresión: (2+(3*4))

Recorrido: 2+ 3*4

Notación posfijaLa notación posfija E se puede definir como:1.- Si E es una variable o una cte. Entonces la notación posfija de E es también E2.- Si E es una expresión de la forma:

E1 op E2, Donde op es cualquier operando binario, entonces la notación posfija de E es E1’ E2’ op3.- Si E es una expresión de la forma (E1) entonces la notación posfija de E Otra forma de definir una expresión escrita en notación posfija seria escribiendo la siguiente gramática:

Exp: var Donde: |NUM

Page 13: apuntes sistemas operativos

|exp ou ou = operador unario (--,++,!,~) |exp ob ob = operador binario (+,-,*,/) |exp ot ot = operador ternario (engloba más de un operador)

Posfija = 1er operando, 2do operando, operador

Ejemplo:Exp= (4*X)+3 = 4X*3+

Exp= (9-5)+2 = 95-5+

La notación posfija no necesita paréntesis por que la posición y la variedad (numero de argumentos), de los operadores que permiten solo la descomposición de una expresiónEsta notación tiene ventajas con respecto a la notación infija, la cual es más sencilla; para como ya dijimos la notación posfija no necesita paréntesis y la evaluación de este tipo de tipo de expresiones es bastantemente sencilla y como inconveniente principal tiene que es muy difícil expresar en ella las estructuras de control del lenguaje.

Notación prefijaEsta notación es similar a la anterior pero ahora es descrita por la siguiente gramática: Exp: var Donde: |NUM |ou exp ou = operador unario (--,++,!,~) |ob exp exp ob = operador binario (+,-,*,/) |ot exp exp exp ot = operador ternario (engloba más de un operador)

Prefija = operador, 1er operando, 2do operandoEjemplo:

Exp= 2+(5+7) = +*572

Notación CuartetosLos cuartetos son la forma de código intermedio mas usado, este lenguaje consiste de una secuencia de cuartetos posiblemente precedida de una etiqueta, donde cada cuarteto puede tener las formas siguientes:

Del x + p; * x := y;Dep x + p; x [y] :=z;X := y opb z; goto etiy;X := opu y; if not v goto etiq;X := y; param x;X :=z[y]; call p, nX:=*y ; return ; return (x;);

Page 14: apuntes sistemas operativos

Notación tercetosEs una notación similar a la de los cuartetos pero mas compacta aquí cada terceto puede tener asociado un resultado temporal. Este resultado temporal puede ser referenciado por un terceto posterior

(1) / b c(2) = a (1)(3) X c d(4) = d (3)

Notación tercetos indirectaEs similar a la anterior se añade un arreglo que indica el orden en que se ejecutaran los tercetos

(1) / b c(3) = a (1)(2) X c d(4) = d (2)

Generación de código intermedioDespués de los análisis sintáctico y semántico, algunos compiladores generan una representación intermedia explícita del programa fuente. Se puede considerar esta representación intermedia como un programa para una máquina abstracta. Esta representación intermedia debe tener dos propiedades importantes:a) debe ser fácil de producir b) debe ser fácil de traducir al programa objeto.

La representación intermedia puede tener diversas formas. Existe una forma intermedia llamada “código de tres direcciones” que es como el lenguaje ensamblador de una máquina en la que cada posición de memoria puede actuar como un registro. El código de tres direcciones consiste en una secuencia de instrucciones, cada una de las cuales tiene como máximo tres operandos.

Ejemplo:

Exp = -(4*X+6)T1 = 4*XT2 = T1+6T3 = -T2

Exp = (7+4/2)T1 = 7+4T2 = T1/2T3 = T2

Page 15: apuntes sistemas operativos

VII Optimización

7.1 Tipos de optimización

La optimización se realiza reestructurando el código de tal forma que el nuevo código generado tenga mayores beneficios. La mayoría de los compiladores tienen una optimización baja, se necesita de compiladores especiales para realmente optimizar el código.La optimización es la última fase de la construcción de un compilador. Es un proceso que tiende a minimizar o maximizar alguna variable de rendimiento, generalmente tiempo espacio en procesador etc., son factores que influyen en la optimización de un compilador

7.1.1 Optimización localse realiza sobre módulos del programa. En la mayoría de las ocasiones a través de funciones, métodos, procedimientos, clases, etc. se ven reflejados en la rapidez y confiabilidad de un conjunto de instrucciones que se encuentran en un bloque.

7.1.2 Optimización de ciclos (bucles)Los ciclos son una de las partes más esenciales en el rendimiento de un programa dado que realizan acciones repetitivas, y si dichas acciones están mal realizadas, el problema se hace N veces más grandesLa mayoría de las optimizaciones sobre ciclos tratan de encontrar elementos que no deben repetirse en un ciclo

Ejemplo:

while(a == b) {int c = a; c = 5; … } En este caso es mejor pasar el int c =a; fuera del ciclo de ser posible.

El problema de la optimización en ciclos y en general radica es que muy difícil saber el uso exacto de algunas instrucciones. Así que no todo código de proceso puede ser optimizado.

7.1.3 Optimización Global

Selleva a cabo cuando se declaran variables globales para agilizar los procesos (el proceso de declarar variables y eliminarlas toma su tiempo) pero consume más

Page 16: apuntes sistemas operativos

memoria. Algunas optimizaciones incluyen utilizar como variables registros del CPU, utilizar instrucciones en ensamblador.

7.1.4 Optimización de mirilla

trata deestructurar de manera eficiente el flujo del programa, sobre todo en instrucciones de bifurcación como son las decisiones, ciclos y saltos de rutinas. La idea es tener los saltos lo más cerca de las llamadas, siendo el salto lo más pequeño posible.

7.2 Optimización de costos

Los costos son el factor más importante a tomar en cuentaa la hora de optimizar ya que en ocasiones la mejora obtenida puede verse no reflejada en el programa finalpero si ser perjudicial para el equipo de desarrollo.La optimización de una pequeña mejora tal vez tenga una pequeña ganancia en tiempo o en espacio pero sale muy costosa en tiempo en generarla

7.2.1 Optimización de costos de ejecución

Los costos de ejecución son aquellos que vienen implícitos al ejecutar el programa. En algunos programas se tiene un mínimo para ejecutar el programa, por lo que el espacio y la velocidad del microprocesadores son elementos que se deben optimizar en lo posible.

Las aplicaciones multimedias como los videojuegos tienen un costo de ejecución alto por lo cual la optimización de su desempeño es crítico, la gran mayoría de las veces requieren de procesadores rápidos en tarjetas de video o de mucha memoria.

Los dispositivos móviles tiene recursos más limitados que un dispositivo de cómputo convencional razón por la cual, el mejor uso de memoriay otros recursos de hardware tiene mayor rendimiento para ser explotados.

7.2.2 Criterios para mejorar el código

La mejor manera de optimizar el código es hacer ver a los programadores que optimicen su código desde el inicio, el problema radica en que el costo podría ser muy grande ya que tendríaque codificar más y/o hacer su código mas legible.

Los criterios de optimización siempre están definidos por el lenguaje de programación a utilizar, no se comporta igual a todos sus programas.

7.2.3 Herramientas para el análisis de flujo de datos

Page 17: apuntes sistemas operativos

Existen algunas herramientas que permiten el análisis de los flujos de datos, entre ellas tenemos los depuradores y ensambladores, que sigue paso a paso todo el desarrollo del compilador.

Conclusión: La optimización al igual que la programación es un arte y no se ha podido sistematizar, es decir que indique el mejor camino para la optimización del compilador.

VIII Generador de código objeto

8.1 Características del lenguaje maquina

Un lenguaje de programación de bajo nivel es el que proporciona poca o ninguna abstracción del microprocesador de un ordenador. Consecuentemente es fácilmente trasladado a lenguaje de máquina.

La palabra “bajo” no implica que el lenguaje sea inferior a un lenguaje de alto nivel; se refiere a la reducida abstracción entre el lenguaje y el hardware. En general se utiliza este tipo de lenguaje para programar controladores (drivers).

Ventajas de los lenguajes maquina

a) Mayor adaptación al equipo. b) Posibilidad de obtener la máxima velocidad con mínimo uso de memoria.

Desventajasa) Imposibilidad de escribir código independiente de la máquina. b) Mayor dificultad en la programación y en la comprensión de los programas. c) El programador debe conocer más de un centenar de instrucciones.

8.1.2 Direccionamiento del lenguaje maquina

Es la forma en como se accede a la memoria. Recordar que un programa no puede ejecutarse sino se encuentra en memoria principal. La forma de acceder a la memoria depende del microprocesador, pero en general existen dos tipos de direccionamiento:

a) El direccionamiento directo también recibe el nombre de direccionamiento absoluto y el acceso a las direcciones se hace de manera directa.

b) El direccionamiento indirecto también recibe el nombre de direccionamiento relativo y se basa a partir de una dirección genérica, generalmente el inicio del programa.

8.2 Características del lenguaje ensamblador

Page 18: apuntes sistemas operativos

Es un tipo de lenguaje de bajo nivel utilizado para escribir programas informáticos, y constituye la representación más directa del código máquina específico para cada arquitectura de computadoras legible por un programador.

Los ensambladores son por lo general más fáciles de programar que los compiladores de lenguajes de alto nivel, y han estado disponibles desde la década de los 50’sLos ensambladores de alto nivel ofrecen posibilidades de abstracción que incluyen:

a) Control avanzado de estructuras. b) Procedimientos de alto nivel c) Declaración de funciones d) Tipos de datos que incluyen estructuras, registros, uniones, clases y

conjuntos

La transformación del lenguaje ensamblador en código máquina la realiza un programa ensamblador, y la traducción inversa la puede efectuar un desensamblador.Cada arquitectura de computadoras tiene su propio lenguaje de máquina, y en consecuencia su propio lenguaje ensamblador.Las computadoras difieren en el tipo y número de operaciones que soportan; también pueden tener diferente cantidad de registros, y distinta representación de los tipos de datos en memoria

El lenguaje maquina está formado por instrucciones sencillas que dependiendo de la estructura del procesador puede especificar:

a) Registros específicos para operaciones aritméticas b) Direccionamiento o control de funciones c) Posiciones de memoria específicas

El código máquina, un simple patrón de bits, es hecho legible reemplazando valores crudos por símbolos denominados mnemónicos. Se inventó para facilitar la tarea de los primeros programadores que hasta ese momento tenían que escribir directamente en código binario.

8.2.2 Almacenamiento del lenguaje ensamblador

Una de las principales ventajas del uso del ensamblador, es que se encarga de administrar de manera transparente para el usuario la creación de memoria, las bifurcaciones y el paso de parámetros entre funciones o procedimeinetos.

Además nos permite acceder directamente a los recursos de la máquina para un mejor desempeño.

8.3 Registros del lenguaje ensamblador

Page 19: apuntes sistemas operativos

Los registros del procesador se emplean para controlar instrucciones en ejecución, manejar direccionamiento de memoria y proporcionar capacidad aritmética.Los registros son espacios físicos dentro del microprocesador con capacidad de 4 bits hasta 64 bits dependiendo del microprocesador que se emplee. 1.- Registro de segmento: se utiliza para alinear en un límite de párrafo o dicho de otra forma codifica la dirección de inicio de cada segmento y su dirección en un registro de segmento Los cuales pueden ser los siguientes:

CS = CódigoDS = DatosSS = PilaES = E/S de puertos 2.- Registro de apuntadores de instrucción: contiene el desplazamiento de dirección de la siguiente instrucción que se ejecuta.

3.- Registro de uso general: Se puede dividir en las siguientes categorías:

AX = Registro acumulador, Interviene en las operaciones aritméticas y lógicas, después de la operación arroja un resultado. BX = Registro base, Se utiliza en transferencias de datos entre la memoria y el procesador. CX = Registro contador, Se utiliza como contador en bucles. DX = Registro de datos, Se utiliza en operaciones de multiplicación y división junto con Ax en operaciones de entrada y salida de puertos

4.- Registro índice: están disponibles para direccionamientos indexados y para sumas y restas. Que son las operaciones principales.

5.- Registro de bandera: sirven parar indicar el estado actual de la maquina y el resultado del procesamiento, Cuando algunas instrucciones piden comparaciones o cálculos aritméticos.

8.3.1 Distribución del Lenguaje ensamblador

Es el proceso en el que el programa generado puede ejecutarse en otras máquinas. Con respecto al ensamblador, la mayoría del direccionamiento se hace relativo para que el programa sea relocalizable por un programa llamado cargador.

Debido a la complejidad del software actual se necesitan de asistentes para poder instalar y ejecutar un programa.

8.4 Administración del Lenguaje ensamblador

Page 20: apuntes sistemas operativos

Se refiere a la administración de la memoria lo cual hoy en día es un proceso muy importante, de tal modo que su mal o buen uso tiene una acción directa sobre el desempeño de memoria, y esto tiene que ver con el uso de punteros los cuales quedaban perdidos en la memoria consumiendo espacio.

Los lenguajes más recientes controlan el uso de punteros y tienen un programa denominado recolector de basura que se encarga de limpiar la memoria no utilizada mejorando el desempeño de la memoria.