Código máquina (lenguaje de máquina): definición, instrucciones y funcionamiento
Descubre qué es el código máquina, cómo funcionan sus instrucciones, opcodes y operandos, y por qué es vital para ejecutar programas en el hardware nativo.
El código máquina es un programa informático escrito en lenguaje máquina. Utiliza el conjunto de instrucciones de una determinada arquitectura informática. Suele estar escrito en binario. El código máquina es el nivel más bajo del software. Otros lenguajes de programación se traducen a código máquina para que el ordenador pueda ejecutarlos.
El código máquina está formado por secuencias de bits organizadas en bytes y palabras de longitud determinada por la arquitectura (por ejemplo 8, 16, 32 o 64 bits). Aunque su representación interna es binaria, habitualmente se visualiza y edita en hexadecimal para facilitar la lectura por humanos. Los ficheros ejecutables contienen secciones con código máquina, tablas de símbolos y metadatos que permiten al sistema operativo cargar y ejecutar el programa.
Formato de una instrucción
Una instrucción indica al procesador qué operación debe realizar. Cada instrucción se compone de un opcode (código de operación) y uno o más operandos. Los operandos suelen ser direcciones de memoria, registros del procesador o datos inmediatos.
Existen diferentes esquemas de codificación según la arquitectura:
- Longitud fija: cada instrucción ocupa el mismo número de bytes (común en arquitecturas RISC).
- Longitud variable: las instrucciones pueden tener tamaños distintos (típico en arquitecturas CISC como x86).
- Modos de direccionamiento: inmediato, directo, indirecto, indexado, registro, relativo, etc., que determinan cómo se interpreta el operando.
Las instrucciones se representan en código máquina mediante valores numéricos para el opcode y campos para los operandos; los lenguajes ensamblador ofrecen mnemónicos legibles por humanos que luego se traducen (ensamblan) a esos códigos binarios.
Cómo se genera y ejecuta
Los creadores de programas convierten el código en otro lenguaje o código máquina. El código máquina se denomina a veces código nativo. Se utiliza cuando se habla de cosas que sólo funcionan en algunos ordenadores.
Las rutas habituales para generar código máquina son:
- Compilación: el compilador traduce código fuente a código máquina (a menudo pasando por ensamblador y enlazador). El texto original incluía el enlace a que otros lenguajes compilan o interpretan en código máquina.
- Ensamblador: traduce código ensamblador (mnemónicos) a instrucciones binarios.
- Intérpretes y máquinas virtuales: algunos entornos ejecutan instrucciones de un lenguaje intermedio (bytecode) y generan código máquina en tiempo de ejecución mediante JIT.
En tiempo de ejecución, el procesador realiza el ciclo de búsqueda-decodificación-ejecución (fetch-decode-execute) sobre las instrucciones almacenadas en memoria. El cargador del sistema operativo coloca el código en memoria y gestiona permisos (por ejemplo, marcar páginas como ejecutables).
Portabilidad y dependencias de arquitectura
El código máquina depende directamente del diseño del procesador: del conjunto de instrucciones y de los detalles microarquitectónicos. Por eso un binario compilado para una arquitectura no funciona en otra sin emulación o traducción. Esta dependencia es la razón por la que se habla de código nativo y de la necesidad de recompilar o redistribuir versiones para diferentes plataformas (x86, ARM, MIPS, etc.).
Representación, edición y análisis
Además del binario puro, el código máquina se maneja con herramientas específicas:
- Desensambladores: traducen código máquina a mnemónicos legibles para análisis y depuración.
- Depuradores: permiten ejecutar paso a paso, inspeccionar registros y memoria.
- Hex editors y utilidades como hexdump para visualizar y editar bytes en disco.
- Enlazadores y relocadores: resuelven referencias entre módulos y ajustan direcciones en el código final.
Seguridad y comportamiento avanzado
El manejo y la ejecución de código máquina están estrechamente relacionados con la seguridad del sistema. Algunas consideraciones importantes:
- Ejemplo de riesgos: desbordamientos de búfer, inyección de código y ejecución de código no autorizado.
- Protecciones: DEP/NX (prohibir ejecución en ciertas páginas), ASLR (aleatorización de direcciones), firmas y control de integridad.
- Código auto-modificante y microcódigo: algunos programas (o firmware) modifican instrucciones en tiempo de ejecución; además, algunos procesadores usan microcódigo para implementar instrucciones complejas.
- Ingeniería inversa: análisis de código máquina con fines de depuración, auditoría o descubrimiento de vulnerabilidades.
Ejemplos prácticos y diferencias entre arquitecturas
Por ejemplo, las arquitecturas x86 suelen tener instrucciones de longitud variable y muchas modalidades complejas, mientras que arquitecturas RISC como ARM o RISC-V usan formatos más regulares y a menudo instrucciones de longitud fija, lo que simplifica el pipeline del procesador. Algunas variantes (como ARM Thumb) combinan instrucciones de 16 y 32 bits para equilibrio entre densidad y rendimiento.
En resumen, el código máquina es la representación binaria de las instrucciones que entiende un procesador concreto. Es el vínculo final entre el software escrito por humanos y las operaciones eléctricas y lógicas que realiza el hardware.
Escribir código máquina
El código máquina puede escribirse de diferentes formas:
- Utilizando un número de interruptores. Esto genera una secuencia de 1 y 0. Se utilizaba en los primeros tiempos de la informática. Desde los años 70, ya no se utiliza.
- Utilizar un editorhexadecimal. Esto permite el uso de opcodes en lugar del número del comando.
- Utilizar un ensamblador. Los lenguajes ensambladores son más sencillos que los opcodes. Su sintaxis es más fácil de entender que el lenguaje de máquina, pero más difícil que los lenguajes de alto nivel. El ensamblador traducirá por sí mismo el código fuente a código máquina.
- El uso de un lenguaje de programación de alto nivel permite que los programas utilicen un código más fácil de leer y escribir. Estos programas se traducen a código máquina. La traducción puede realizarse en varios pasos. Los programas Java se optimizan primero en bytecode. Después se traducen a lenguaje máquina cuando se utilizan.

Panel frontal de un primer miniordenador, con interruptores para introducir el código de la máquina
Instrucciones típicas del código máquina
Hay muchos tipos de instrucciones que suelen encontrarse en un conjunto de instrucciones:
- Operaciones aritméticas: Suma, resta, multiplicación, división.
- Operaciones lógicas: Conjunción, disyunción, negación.
- Operaciones que actúan sobre bits individuales: Desplazamiento de bits a la izquierda o a la derecha.
- Operaciones que actúan sobre la memoria: copiar un valor de un registro a otro.
- Operaciones que comparan dos valores: mayor que, menor que, igual.
- Operaciones que combinan otras operaciones: sumar, comparar y copiar si es igual a algún valor (como una sola operación), saltar a algún punto del programa si un registro es cero.
- Operaciones que actúan sobre el flujo del programa: saltar a alguna dirección.
- Operaciones que convierten tipos de datos: por ejemplo, convertir un entero de 32 bits en un entero de 64 bits, convertir un valor de coma flotante en un entero (truncando).
Muchos procesadores modernos utilizan el microcódigo para algunos de los comandos. Los comandos más complejos suelen utilizarlo. Esto se hace a menudo con las arquitecturas CISC.
Instrucciones
Cada procesador o familia de procesadores tiene su propio conjunto de instrucciones. Las instrucciones son patrones de bits que corresponden a diferentes órdenes que se pueden dar a la máquina. Así, el conjunto de instrucciones es específico de una clase de procesadores que utilizan (en su mayoría) la misma arquitectura.
Los nuevos diseños de procesadores suelen incluir todas las instrucciones de un predecesor y pueden añadir instrucciones adicionales. A veces, un diseño más nuevo suspende o altera el significado de un código de instrucción (normalmente porque se necesita para nuevos fines), lo que afecta a la compatibilidad del código; incluso los procesadores casi completamente compatibles pueden mostrar un comportamiento ligeramente diferente para algunas instrucciones, pero esto no suele ser 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. Dado que un programa suele depender de estos factores, los distintos sistemas no suelen ejecutar el mismo código máquina, aunque se utilice el mismo tipo de procesador.
La mayoría de las instrucciones tienen uno o más campos opcode. En ellos se especifica el tipo de instrucción básica. Otros campos pueden indicar el tipo de los operandos, el modo de direccionamiento, etc. También puede haber instrucciones especiales contenidas en el propio opcode. Estas instrucciones se denominan inmediatas.
Los diseños de los procesadores pueden ser diferentes en otros aspectos. Diferentes instrucciones pueden tener diferentes longitudes. También pueden tener la misma longitud. Hacer que todas las instrucciones tengan la misma longitud puede simplificar el diseño.
Ejemplo
La arquitectura MIPS tiene instrucciones de 32 bits de longitud. Esta sección tiene ejemplos de código. El tipo general de instrucción está en el campo op (operación). Son los 6 bits más altos. Las instrucciones de tipo J (salto) y de tipo I (inmediata) están totalmente dadas por op. Las instrucciones de tipo R (registro) incluyen el campo funct. Determina la operación exacta del código. Los campos utilizados en estos tipos son:
6 5 5 5 6 bits [ op | rs | rt | rd |shamt| funct] Tipo R [ op | rs | rt | address/immediate] Tipo I [ op | target address ] Tipo Jrs, rt y rd indican operandos de registro. shamt da una cantidad de desplazamiento. Los campos de dirección o inmediato contienen un operando directamente.
Ejemplo: sumar los registros 1 y 2. Coloca el resultado en el registro 6. Se codifica:
[ op | rs | rt | rd |shamt| funct] 0 1 2 6 0 32 decimal 000000 00001 00010 00110 00000 100000 binarioCargue un valor en el registro 8. Tómelo de la celda de memoria 68 celdas después de la ubicación que aparece en el registro 3:
[ op | rs | rt | dirección/intermedio] 35 3 8 68 decimal 100011 00011 01000 00000 00001 000100 binarioSalta a la dirección 1024:
[ op | dirección de destino ] 2 1024 decimal 000010 00000 00000 00000 10000 000000 binarioPáginas relacionadas
- Sistema numérico binario
- Ordenadores cuánticos
- Conjunto de instrucciones
- Ordenador con conjunto de instrucciones reducido
Preguntas y respuestas
P: ¿Qué es el código máquina?
R: El código máquina es un programa informático escrito en lenguaje máquina, que utiliza el conjunto de instrucciones de una arquitectura informática determinada y que suele estar escrito en binario.
P: ¿Cuál es el nivel más bajo de software?
R: El código máquina es el nivel más bajo de software.
P: ¿Cómo ejecutan los ordenadores otros lenguajes de programación?
R: Otros lenguajes de programación se traducen a código máquina, que el ordenador puede ejecutar.
P: ¿En qué consiste una instrucción en código máquina?
R: Una instrucción en código máquina consta de un opcode (código de operación) y un operando(s). Los operandos suelen ser direcciones de memoria o datos.
P: ¿Qué es un conjunto de instrucciones?
R: Un conjunto de instrucciones es una lista de los opcodes disponibles para un ordenador.
P: ¿Qué hacen los creadores de programas con el código?
R: Los creadores de programas convierten el código en otro lenguaje o código máquina.
P: ¿Cuál es otro nombre para el código máquina?
R: El código máquina se denomina a veces código nativo, y se utiliza cuando se habla de cosas que sólo funcionan en algunos ordenadores.
Buscar dentro de la enciclopedia