2009-08-28 18 views
6

Así que tomo mi programa C++ en Visual Studio, compilo, y escupirá un pequeño y agradable archivo EXE. Pero EXE solo se ejecutará en Windows, y escucho mucho sobre cómo C/C++ se compila en lenguaje ensamblador, que se ejecuta directamente en un procesador. El EXE se ejecuta con la ayuda de Windows, o podría tener un programa que crea un ejecutable que se ejecuta en un mac. ¿Pero no estoy compilando el código de C++ en el lenguaje ensamblador, que es específico del procesador?¿Cómo puedo crear un ejecutable para ejecutar en una determinada arquitectura de procesador (en lugar de cierto sistema operativo)?

Mis Insights:

  1. supongo que probablemente no lo soy. Sé que hay un compilador Intel C++, ¿entonces sería un código ensamblador específico del procesador? Los EXEs se ejecutan en Windows, por lo que se benefician de toneladas de cosas ya configuradas, desde paquetes de gráficos hasta el enorme framework .NET. Un ejecutable específico del procesador estaría literalmente comenzando desde cero, con solo el conjunto de instrucciones del procesador.

  2. ¿Sería este ejecutable un tipo de archivo? Podríamos estar ejecutando Windows y abrirlo, pero luego controlaríamos cambiar al procesador solamente? Supongo que este ejecutable sería algo así como un sistema operativo, en el sentido de que debería ejecutarse antes de arrancar cualquier otra cosa, y tener solo las instrucciones del procesador configuradas para "usar".

+3

El compilador de Intel no es lo que usted piensa, es simplemente otro compilador de Windows (o Linux, ambos) que pasa a ser escrito por Intel. Hace EXEs o binarios estándar de Linux. –

Respuesta

16

Vamos a pensar en lo que "correr" significa ...

Algo tiene que cargar los códigos binarios en la memoria. Esa es una característica del sistema operativo. El .EXE o archivo ejecutable binario o paquete, o lo que sea, está formateado de una manera muy específica de sistema operativo para que el sistema operativo pueda cargarlo en la memoria.

Algo tiene que pasar el control a esos códigos binarios. Ahí está el sistema operativo, de nuevo.

Las rutinas de E/S (en C++, pero esto es cierto en la mayoría de los lugares) son sólo una biblioteca que encapsulan OS API. Drat ese sistema operativo, está en todas partes.

Recordando.

En los viejos tiempos (sí, soy así de viejo) trabajaba en máquinas que no tenían sistemas operativos. Asimismo, no tenemos C.

nos escribió códigos de máquina utilizando herramientas como "montadores" y "enlazadores" para crear grandes imágenes binarias que puede mostrarse en la máquina. Tuvimos que cargar estas imágenes binarias a través de un doloroso proceso de arranque.

Usaríamos teclas del panel frontal para cargar el código en la memoria suficiente para leer un práctico dispositivo como un lector de cinta de papel perforado. Esto cargaría una pequeña pieza de software de cargador de enlaces de arranque bastante estándar. (Usamos cinta mylar para que no se desgaste.)

Luego, cuando teníamos este cargador de enlaces en la memoria, podíamos alimentar la cinta que habíamos preparado anteriormente con el ensamblador.

Escribimos nuestros propios controladores de dispositivo. O utilizamos rutinas de biblioteca que estaban en forma de fuente, perforadas en cintas de papel.

Un "parche" en realidad era parches de cinta de papel. Además, como también había pequeños errores, teníamos que ajustar la imagen de la memoria según las instrucciones escritas a mano, parches que no se habían insertado en la cinta.

Más tarde, tuvimos sistemas operativos simples que tenían API simples, controladores de dispositivos simples, y algunos servicios públicos como un "sistema de archivos", un "editor" y un "compilador". Era para un lenguaje llamado Jovial, pero también utilizamos Fortran a veces.

Tuvimos que soldar placas de interfaz serie para que pudiéramos conectar un dispositivo. Tuvimos que escribir controladores de dispositivo.

línea de base.

Puede escribir fácilmente programas en C++ que no requieren un sistema operativo.

  1. Conozca las instalaciones de hardware de BIOS (o BIOS) que forman parte del conjunto de chips de su procesador. La mayoría del hardware moderno tiene un sistema operativo simple conectado a la ROM que realiza la autoprueba de encendido (POST), carga algunos controladores simples y localiza los bloques de arranque.

  2. Aprenda a escribir su propio bloque de arranque. Esa es la primera cosa de "software" adecuada que se carga después de POST. Esto no es tan difícil. Puede usar varias herramientas de particionamiento para forzar su programa de bloque de arranque en un disco y tendrá control total sobre el hardware. Sin sistema operativo

  3. Descubra cómo GRUB, LILO o BootCamp inician un sistema operativo. No es complicado. Una vez que se inician, pueden cargar su programa y usted está apagado y funcionando. Esto es un poco más simple porque crea el tipo de partición que un cargador de arranque desea cargar. Base el tuyo en el kernel de Linux y estarás más feliz. No intente averiguar cómo arranca Windows, es demasiado complicado.

  4. Lectura en ELF. http://en.wikipedia.org/wiki/Executable_and_Linkable_Format

  5. Aprenda cómo se escriben los controladores del dispositivo. Si no usa un sistema operativo, necesitará escribir controladores de dispositivo.

+0

una adición a "Puede escribir fácilmente programas en C++ que no requieren un sistema operativo". Lo más fácil es hacerlo con microcontroladores, la mayoría (tal vez todos) tienen compiladores C++ o al menos C hoy en día. – vsz

6

El problema es que el sistema operativo realmente hace mucho para iniciar sus programas. El archivo EXE en sí tiene información de encabezado que reconoce Windows, identificándose como un archivo EXE. Tu aplicación hace todo, desde el acceso al sistema de archivos a las asignaciones de memoria, a través del sistema operativo.

Pero sí, PUEDE ejecutar aplicaciones compiladas para Windows/intel en otras plataformas sin emulación. Si desea ejecutar su EXE en una Mac o UNIX, necesitará instalar un poco más de software para hacer el trabajo que Windows haría para ejecutar su programa, eche un vistazo al proyecto "Wine".

1

Claro, existen. Se llaman cross compilers. Por ejemplo, así es como puedo programar para la plataforma de iPhone usando Xcode.

Un tipo de compilador relacionado es aquel que se compila para una plataforma virtual. That's how Java works.

+0

No creo que sea eso lo que se preguntó. La pregunta era sobre qué hace que un ejecutable sea específico del sistema operativo. – sleske

0

Sí, puede crear un ejecutable que se ejecute en el 'bare metal' de un procesador. Obviamente así es como funcionan los kernels del sistema operativo. Lo principal que debes hacer es crear un ejecutable que no use bibliotecas. Sin embargo, la restricción "sin bibliotecas" incluye la biblioteca estándar C Entonces eso significa que no hay malloc, no hay printf, etc. Tienes que ser básicamente tu propio sistema operativo y administrar la memoria y las E/S. Esto inevitablemente requerirá un poco de trabajo directamente en el montaje en algún momento.

También pierde muchos otros lujos, como main(), que no puede ser el punto de partida de su programa ya que main() es algo invocado por el sistema operativo y el entorno de ejecución de C.

+4

Parece que está confundiendo "biblioteca" con "biblioteca cargada dinámicamente". Cada compilador de metal por ahí (o al menos casi todos) incluye una copia enlazable estáticamente de la biblioteca estándar C, que está vinculada en tiempo de compilación para que las funciones relevantes se vuelvan parte del ejecutable, y funciona bien. Muchos proveedores de hardware incluyen bibliotecas adicionales para interactuar con su hardware específico, e incluso puede comprar bibliotecas de TCP/IP, etc. Muchos proveedores de hardware y compiladores también proporcionan el código de inicio básico necesario para que la placa pase de "activada" a "invoca a main()". –

+0

Un punto importante es que esto reemplaza el sistema operativo. La mayoría de los sistemas operativos no permiten el acceso directo a parte del hardware requerido para ejecutarse. Entonces, podría escribir un programa que reemplace a Windows o Linux, pero no uno que se pueda ejecutar dentro de un sistema operativo existente. (A menos que escriba para un sistema operativo y emule a los demás). – KeithB

1

Cualquier compilador/conjunto de herramientas dado produce código para una combinación particular de procesador/sistema operativo. Entonces su ejemplo de compilación de Visual Studio produce código para x86/Windows. Ese .EXE solo se ejecutará en x86/Windows y no en (por ejemplo) ARM/Windows (como lo usan algunos teléfonos celulares).

Para producir código para una combinación de procesador/sistema operativo que no sea el que está ejecutando, el compilador requiere lo que generalmente se conoce como compilador cruzado. Si tiene una suscripción profesional completa de Visual Studio, puede obtener el compilador cruzado ARM, que le permitirá producir ARM/Windows .EXE archivos que no se ejecutarán en su máquina de escritorio, pero se ejecutarán en un teléfono celular basado en ARM/Windows o palmtop.

3

La computadora no es la CPU. Para hacer algo útil, la CPU debe estar conectada a la memoria y los controladores IO y otros dispositivos. Un sistema operativo se encarga de abstraer todo eso de ejecutar programas. Por lo tanto, si desea escribir un programa que se ejecute sin un sistema operativo, su programa deberá replicar al menos algunas características de un sistema operativo: tomar el relevo del BIOS durante el proceso de arranque, inicializar dispositivos, comunicarse con el controlador de disco para cargar el código y datos, comunicándose con el controlador de pantalla para mostrar información al usuario, comunicándose con el controlador del teclado y el controlador del mouse para leer la entrada del usuario, etc. etc.

A menos que esté construyendo un sistema integrado con hardware especializado, no hay señalar al hacer esto. Además, ejecutar tu programa significaría que el usuario tendría que dejar de ejecutar otros programas. Si bien esto puede ser aceptable para un cajero automático hoy en día o WordStar en 1984, en la actualidad la gente frunce el ceño al no poder consultar el correo electrónico mientras escucha música.

5

De lo que estás hablando es de lo que se conoce en el mundo integrado como una aplicación "bare-metal". Son muy comunes para cosas como un ARM Cortex-M3 que entra (digamos) en una caja de validación de tarjeta de débito o un juguete interactivo, y no tiene suficiente memoria o capacidad para ejecutar un sistema operativo completo. Entonces, en lugar de obtener un compilador "ARM/Linux" que compilaría una aplicación para ejecutar en Linux en un procesador ARM, obtendría un compilador "ARM bare-metal" que compila cosas para ejecutar en un procesador ARM sin un sistema operativo. (Estoy usando ARM en lugar de x86 como ejemplo, porque las aplicaciones de hardware puro x86 son bastante raras en la actualidad.)

Según lo expresado en su pregunta y en las demás respuestas, su aplicación deberá hacer algunas cosas que: de lo contrario sería atendido por el sistema operativo.

En primer lugar, necesita inicializar el sistema de memoria, los vectores de interrupción y varios otros bits de la placa goo. Por lo general, esto es algo que un compilador bare-metal hará por usted, aunque si tiene una placa extraña, es posible que necesite decirle cómo hacerlo. Esto hace que las cosas vayan desde el punto donde la placa se enciende hasta el punto donde comienza la función main().

Luego, necesita interactuar con cosas fuera de la CPU y la RAM. Un sistema operativo incluye todo tipo de funciones para hacer esto: E/S de disco, salida de pantalla, entrada de teclado y mouse, redes, etc., etc., etc. Sin un sistema operativo, debes obtenerlo de otro lugar. Puede obtener algo de eso de las bibliotecas de su fabricante de hardware; por ejemplo, una placa con la que estaba jugando recientemente tiene una pantalla LED de 40x200 píxeles, y viene con una biblioteca con el código para activarla y establecer valores de píxeles individuales en ella. Y hay varias compañías que venden bibliotecas para implementar una pila TCP/IP y cosas por el estilo, para hacer networking o cosas así.

Considere, por ejemplo, que esto dificulta incluso la impresión básica. Cuando tienes un sistema operativo, printf simplemente envía un mensaje al sistema operativo que dice "pon esta cadena en la consola", y el sistema operativo encuentra la posición actual del cursor en la consola, y hace todo lo posible para descubrir qué píxeles para cambiar en la pantalla, y qué instrucciones de la CPU usar para cambiar esos píxeles, con el fin de hacer eso.

Ah, ¿y mencionamos que primero tiene que averiguar cómo obtener el programa en la CPU? Una computadora típica tiene un poco de ROM programable que cargará las instrucciones desde el momento en que se inicie. En un x86, este es el BIOS, y normalmente ya contiene un práctico programa que inicia la CPU, configura la pantalla, busca discos y carga un programa fuera del disco que encuentra. En un sistema integrado, normalmente es donde va su programa, lo que significa que necesita alguna forma de poner su programa allí. A menudo, eso significa que tiene un dispositivo llamado "depurador" que está físicamente conectado a su placa embebida que carga el programa, y ​​también puede hacer cosas que le permiten pausar el procesador y determinar cuál es su estado, para que pueda dar un paso a través de su programa como si lo estuviera ejecutando en un depurador de software en su computadora. Pero yo divago.

De todos modos, para responder a su segunda pregunta, este ejecutable que usted crearía es algo que se almacenará en esa ROM en su placa embebida, o quizás simplemente guarde un poco de ella en la ROM (que es, después de todo, bastante pequeño) y almacena el resto en una unidad de memoria flash, y el bit en ROM incluiría las instrucciones para extraer el resto de la memoria USB. Probablemente se almacenaría como un archivo en su computadora principal (es decir, la computadora Linux o Windows donde la está creando), pero eso es solo para almacenamiento, no se ejecutaría allí.

Notarás que cuando tienes muchas de estas bibliotecas juntas, están haciendo bastante de lo que hace un sistema operativo, y hay una especie de espacio entre la pila de bibliotecas y una verdadera operación sistema. En ese espacio va lo que se llama RTOS: "sistema operativo en tiempo real". Los más pequeños son simplemente colecciones de bibliotecas que trabajan juntas para hacer todas las cosas del sistema operativo, y a veces también incluyen cosas para que pueda ejecutar múltiples hilos a la vez (y luego puede tener diferentes hilos que actúen como diferentes programas) - - aunque todo esto está compilado en el mismo "programa" compilado, y el RTOS no es más que una biblioteca que ha incluido. Los más grandes comienzan a almacenar partes del código en lugares separados, y creo que algunos de ellos incluso pueden cargar trozos de código de los discos, al igual que Windows y Linux cuando ejecutan un programa. Es una especie de continuo, en lugar de uno u otro.

El sistema FreeRTOS es un RTOS de código abierto que se dirige hacia el extremo más pequeño del espacio RTOS; pueden ser un buen lugar para ver algo de esto si estás más interesado. Tienen algunos ejemplos de aplicaciones x86, que te darían una idea de qué tipo de sistemas x86 ejecutarían un programa baremo o basado en RTOS y cómo compilarías algo para ejecutar en uno; enlace aquí: http://www.freertos.org/a00090.html#186.

0

¡Absolutamente! Eso es lo que es la programación integrada. Como muchos probablemente ya han dicho, el sistema operativo hace bastante por ti. E incluso en el mundo integrado sin un sistema operativo, varias herramientas de desarrollo proporcionarán el código de inicio para que el procesador funcione lo suficiente como para saltar a su programa. Algunos/muchos proporcionan bibliotecas completas de C/C++ para que pueda llamar a funciones como memcpy() y algunas veces incluso malloc() y printf().

Puede proporcionar todas las líneas de código y todas las instrucciones y no utilizar un paquete de herramientas de desarrollo, pero aún así utilizar un compilador como gcc por ejemplo. Algunos de los formatos binarios son comunes a los que se ejecutan en sistemas operativos como el duende por ejemplo. Puede ejecutar archivos elf en Linux pero también tiene el resultado de un programa incrustado en un binario de duende. El procesador no puede ejecutar el duende en ese formato, pero cualquiera que sea el programa de arranque o carnero en algunos casos extraerá el programa binario del archivo elf, como un sistema operativo que extrae el programa para ejecutarse desde un archivo elf. EXE no es uno de esos formatos de archivo. Su compilador favorito de aplicaciones de Windows probablemente tampoco es un compilador incrustado, aunque a veces puede usar uno para hacer el lenguaje de alto nivel y luego usar un ensamblador y enlazador alternativo. Más trabajo del que normalmente vale. Por ejemplo, usted escribe una función en C (que NO realiza ninguna llamada a la biblioteca o al sistema) y la compila a un objeto.Escriba el suyo o encuentre una utilidad para extraer el binario compilado de ese objeto, convertirlo a otro formato de objeto o ensamblar (desensamblar). Agregue su código de inicio y otro ensamblado a él. Reunir y vincular todo junto como un programa integrado. Lo hice una vez con Microsofts embedded C visual para ver cómo se compara con otros compiladores, no fue horrible, pero ciertamente no valió la pena el esfuerzo de hackear para obtener la salida.

Todos los procesadores desde el que está en su computadora hasta el que está en su teléfono celular o en el microondas también tienen un código de arranque. Ese código no se ejecuta en un sistema operativo. Ese código usa los mismos o similares compiladores que las aplicaciones del sistema operativo. Para algunos dispositivos, el código coloca el procesador y la memoria y activa y desactiva periféricos de chip en un estado donde se puede iniciar el sistema operativo. A partir de ahí, el sistema operativo toma el control. En su computadora, este sería el BIOS seguido del gestor de arranque, luego el sistema operativo, dos, windows, linux, etc.

0

El problema principal es el formato de archivo. PE es muy diferente a ELF (utilizado en sistemas de tipo Unix). Un programa PE válido no puede ser un ELF válido. Entonces, o cargas el binario dinámicamente con diferentes iniciadores o tienes que darte por vencido.

Aparte de eso, con conocimiento de los servicios del sistema operativo, el valor de los registros en el inicio, etc. su código probablemente pueda detectar de manera fácil y confiable con qué sistema operativo se está ejecutando y actuar en consecuencia (algunos malware hacen precisamente eso). Otro desafío es reutilizar el código en lugar de tener dos o más programas diferentes en el mismo binario. Básicamente, debería escribir un emulador, al menos para los servicios que necesita.

0

No se olvide de las bibliotecas de Windows. Mire en QT y GTK +

+1

Bienvenido a SO. Probablemente sea mejor dejarlo como comentario ya que no responde completamente la pregunta. –

Cuestiones relacionadas