Lenguaje de máquina

format_list_bulleted Contenido keyboard_arrow_down
ImprimirCitar

En la programación de computadoras, el código de máquina es cualquier lenguaje de programación de bajo nivel, que consta de instrucciones en lenguaje de máquina, que se utilizan para controlar la unidad central de procesamiento (CPU) de una computadora. Cada instrucción hace que la CPU realice una tarea muy específica, como una operación de carga, almacenamiento, salto o unidad lógica aritmética (ALU) en una o más unidades de datos en los registros o la memoria de la CPU.

El código de máquina es un lenguaje estrictamente numérico que está diseñado para ejecutarse lo más rápido posible y puede considerarse como la representación de nivel más bajo de un programa de computadora compilado o ensamblado o como un lenguaje de programación primitivo y dependiente del hardware. Si bien es posible escribir programas directamente en código de máquina, administrar bits individuales y calcular direcciones numéricas y constantes manualmente es tedioso y propenso a errores. Por esta razón, los programas rara vez se escriben directamente en código de máquina en contextos modernos, pero se pueden hacer para depuración de bajo nivel, parches de programas (especialmente cuando la fuente del ensamblador no está disponible) y desensamblaje de lenguaje ensamblador.

La mayoría de los programas prácticos de hoy están escritos en lenguajes de alto nivel o lenguaje ensamblador. Luego, el código fuente se traduce a código de máquina ejecutable mediante utilidades como compiladores, ensambladores y enlazadores, con la importante excepción de los programas interpretados, que no se traducen a código de máquina. Sin embargo, el intérprete en sí mismo, que puede verse como un ejecutor o procesador que ejecuta las instrucciones del código fuente, generalmente consiste en un código de máquina directamente ejecutable (generado a partir del código fuente de lenguaje ensamblador o de alto nivel).

El código de máquina es, por definición, el nivel más bajo de detalle de programación visible para el programador, pero internamente muchos procesadores usan microcódigo u optimizan y transforman las instrucciones del código de máquina en secuencias de microoperaciones. Esto generalmente no se considera un código de máquina.

Conjunto de instrucciones

Cada procesador o familia de procesadores tiene su propio conjunto de instrucciones. Las instrucciones son patrones de bits, dígitos o caracteres que corresponden a comandos de máquina. Por lo tanto, el conjunto de instrucciones es específico para una clase de procesadores que usan (en su mayoría) la misma arquitectura. Los diseños de procesadores sucesores o derivados a menudo incluyen instrucciones de un predecesor y pueden agregar nuevas instrucciones adicionales. Ocasionalmente, un diseño sucesor descontinuará o alterará el significado de algún código de instrucción (típicamente porque es necesario para nuevos propósitos), afectando la compatibilidad del código hasta cierto punto; incluso los procesadores compatibles pueden mostrar un comportamiento ligeramente diferente para algunas instrucciones, pero esto rara vez es un problema. Los sistemas también pueden diferir en otros detalles, como la disposición de la memoria, los sistemas operativos o los dispositivos periféricos. Debido a que un programa normalmente se basa en tales factores,

El conjunto de instrucciones de un procesador puede tener instrucciones de longitud fija o de longitud variable. La forma en que se organizan los patrones varía según la arquitectura particular y el tipo de instrucción. La mayoría de las instrucciones tienen uno o más campos de código de operación que especifican el tipo de instrucción básica (como aritmética, lógica, salto, etc.), la operación (como sumar o comparar) y otros campos que pueden dar el tipo de operando(s).), el(los) modo(s) de direccionamiento, el(los) desplazamiento(s) o índice de direccionamiento, o el propio valor del operando (estos operandos constantes contenidos en una instrucción se denominan inmediatos).

No todas las máquinas o instrucciones individuales tienen operandos explícitos. En una máquina con un solo acumulador, el acumulador es implícitamente tanto el operando izquierdo como el resultado de la mayoría de las instrucciones aritméticas. Algunas otras arquitecturas, como la arquitectura x86, tienen versiones de acumulador de instrucciones comunes, con el acumulador considerado como uno de los registros generales por instrucciones más largas. Una máquina de pila tiene la mayoría o todos sus operandos en una pila implícita. Las instrucciones de propósito especial también suelen carecer de operandos explícitos; por ejemplo, CPUID en la arquitectura x86 escribe valores en cuatro registros de destino implícitos. Esta distinción entre operandos explícitos e implícitos es importante en los generadores de código, especialmente en las partes de asignación de registros y seguimiento de rango en vivo.

Programas

Un programa de computadora es una lista de instrucciones que puede ejecutar una unidad central de procesamiento (CPU). La ejecución de un programa se realiza para que la CPU que lo ejecuta resuelva un problema y así lograr un resultado. Mientras que los procesadores simples pueden ejecutar instrucciones una tras otra, los procesadores superescalares pueden ejecutar muchas instrucciones simultáneamente.

El flujo del programa puede verse influido por instrucciones especiales de "salto" que transfieren la ejecución a una dirección (y, por lo tanto, a una instrucción) distinta de la siguiente dirección numéricamente secuencial. Que estos saltos condicionales ocurran depende de una condición, como que un valor sea mayor, menor o igual que otro valor.

Lenguajes ensambladores

Una interpretación del lenguaje de máquina mucho más amigable para los humanos, llamada lenguaje ensamblador, usa códigos mnemotécnicos para referirse a instrucciones de código de máquina, en lugar de usar los valores numéricos de las instrucciones directamente, y usa nombres simbólicos para referirse a ubicaciones de almacenamiento y, a veces, registros. Por ejemplo, en el procesador Zilog Z80, el código de máquina 00000101, que hace que la CPU disminuya el Bregistro del procesador, se representaría en lenguaje ensamblador como DEC B.

Ejemplo

La arquitectura MIPS proporciona un ejemplo específico para un código de máquina cuyas instrucciones siempre tienen una longitud de 32 bits. El tipo general de instrucción viene dado por el campo op (operación), los 6 bits más altos. Las instrucciones de tipo J (salto) y tipo I (inmediato) están completamente especificadas por op. Las instrucciones de tipo R (registro) incluyen una función de campo adicional para determinar la operación exacta. Los campos utilizados en estos tipos son:

   6 5 5 5 5 6 bits
[ op | rs | hora | rd |falsa| función] tipo R
[ op | rs | hora | dirección/inmediato] tipo I
[ op | dirección de destino] tipo J

rs, rt y rd indican operandos de registro; shamt da una cantidad de cambio; y la dirección o campos inmediatos contienen un operando directamente.

Por ejemplo, sumar los registros 1 y 2 y colocar el resultado en el registro 6 se codifica:

[ op | rs | hora | rd |falso| función]
    0 1 2 6 0 32 decimal
 000000 00001 00010 00110 00000 100000 binario

Cargue un valor en el registro 8, tomado de la celda de memoria 68 celdas después de la ubicación indicada en el registro 3:

[ op | rs | hora | domicilio/inmediato]
   35 3 8 68 decimal
 100011 00011 01000 00000 00001 000100 binario

Saltando a la dirección 1024:

[ op | dirección de destino]
    2 1024 decimal
 000010 00000 00000 00000 10000 000000 binario

Instrucciones superpuestas

En arquitecturas de procesadores con conjuntos de instrucciones de longitud variable (como la familia de procesadores x86 de Intel), dentro de los límites del fenómeno de resincronización del flujo de control conocido como Kruskal Count, a veces es posible a través de la programación a nivel de código de operación organizar deliberadamente el código resultante para que que dos rutas de código comparten un fragmento común de secuencias de código de operación. Estos se denominan instrucciones superpuestas, códigos de operación superpuestos, código superpuesto, código superpuesto, escisión de instrucción o salto en medio de una instrucción, y representan una forma de superposición.

En las décadas de 1970 y 1980, a veces se usaban instrucciones superpuestas para conservar espacio en la memoria. Un ejemplo fue la implementación de tablas de errores en Altair BASIC de Microsoft, donde las instrucciones intercaladas compartían mutuamente sus bytes de instrucción. La técnica rara vez se usa en la actualidad, pero aún podría ser necesario recurrir a ella en áreas donde es necesaria una optimización extrema del tamaño a nivel de byte, como en la implementación de cargadores de arranque que tienen que encajar en los sectores de arranque.

También se utiliza a veces como una técnica de ofuscación de código como medida contra el desmontaje y la manipulación.

El principio también se utiliza en secuencias de código compartidas de binarios gordos que deben ejecutarse en múltiples plataformas de procesadores incompatibles con el conjunto de instrucciones.

Esta propiedad también se usa para encontrar instrucciones no deseadas denominadas gadgets en repositorios de código existentes y se utiliza en la programación orientada al retorno como alternativa a la inyección de código para vulnerabilidades como los ataques de retorno a libc.

Relación con el microcódigo

En algunas computadoras, el código de máquina de la arquitectura se implementa mediante una capa subyacente aún más fundamental llamada microcódigo, que proporciona una interfaz de lenguaje de máquina común en una línea o familia de diferentes modelos de computadora con flujos de datos subyacentes muy diferentes. Esto se hace para facilitar la transferencia de programas en lenguaje de máquina entre diferentes modelos. Un ejemplo de este uso es la familia de computadoras IBM System/360 y sus sucesores. Con anchos de ruta de flujo de datos de 8 bits a 64 bits y más, sin embargo, presentan una arquitectura común a nivel de lenguaje de máquina en toda la línea.

El uso de microcódigo para implementar un emulador permite que la computadora presente la arquitectura de una computadora completamente diferente. La línea System/360 usó esto para permitir la transferencia de programas de máquinas IBM anteriores a la nueva familia de computadoras, por ejemplo, un emulador IBM 1401/1440/1460 en el IBM S/360 modelo 40.

Relación con el código de bytes

El código de máquina generalmente es diferente del código de bytes (también conocido como código p), que es ejecutado por un intérprete o compilado en código de máquina para una ejecución más rápida (directa). Una excepción es cuando un procesador está diseñado para usar un código de bytes en particular directamente como su código de máquina, como es el caso de los procesadores Java.

El código de máquina y el código ensamblador a veces se denominan código nativo cuando se refieren a partes de funciones o bibliotecas de lenguaje que dependen de la plataforma.

Almacenamiento en la memoria

La arquitectura de Harvard es una arquitectura de computadora con almacenamiento físicamente separado y rutas de señal para el código (instrucciones) y los datos. Hoy en día, la mayoría de los procesadores implementan rutas de señal separadas por razones de rendimiento, pero implementan una arquitectura Harvard modificada, por lo que pueden admitir tareas como cargar un programa ejecutable desde el almacenamiento en disco como datos y luego ejecutarlo. La arquitectura de Harvard se contrasta con la arquitectura de Von Neumann, donde los datos y el código se almacenan en la misma memoria que lee el procesador, lo que permite que la computadora ejecute comandos.

Desde el punto de vista de un proceso, el espacio de código es la parte de su espacio de direcciones donde se almacena el código en ejecución. En los sistemas multitarea, esto comprende el segmento de código del programa y, por lo general, las bibliotecas compartidas. En un entorno de subprocesos múltiples, diferentes subprocesos de un proceso comparten espacio de código junto con el espacio de datos, lo que reduce considerablemente la sobrecarga del cambio de contexto en comparación con el cambio de proceso.

Legibilidad por humanos

Pamela Samuelson escribió que el código de máquina es tan ilegible que la Oficina de derechos de autor de los Estados Unidos no puede identificar si un programa codificado en particular es un trabajo original de autoría; sin embargo, la Oficina de derechos de autor de EE. UU . permite el registro de derechos de autor de programas informáticos y, a veces, el código de máquina de un programa se puede descompilar para que su funcionamiento sea más comprensible para los humanos. Sin embargo, a la salida de un descompilador o desensamblador le faltarán los comentarios y las referencias simbólicas, por lo que, si bien la salida puede ser más fácil de leer que el código objeto, seguirá siendo más difícil que el código fuente original. Este problema no existe para formatos de código objeto como SQUOZE, donde el código fuente está incluido en el archivo.

El profesor de ciencias cognitivas Douglas Hofstadter comparó el código de máquina con el código genético y dijo que "mirar un programa escrito en lenguaje de máquina es vagamente comparable a mirar una molécula de ADN átomo por átomo".

Contenido relacionado

Gráficos de trama

Vecindad (teoría de grafos)

En teoría de grafos, un vértice adyacente, vecindad o neighbourhood de un vértice v en un gráfico es un vértice que está conectado a v por una arista....

Grafe (tipo de datos abstracto)

En informática, un grafo es un tipo de datos abstracto que está destinado a implementar los conceptos de gráfico no dirigido y gráfico dirigido del campo...
Más resultados...
Tamaño del texto:
undoredo
format_boldformat_italicformat_underlinedstrikethrough_ssuperscriptsubscriptlink
save