Respostas:
Programas compilados comuns "executam diretamente" na CPU, mas um programa não é executado no vácuo:
Muitos programas contam com bibliotecas externas carregadas dinamicamente ( DLLs
ou .so
bibliotecas). A maneira de vinculá-los é do compilador / vinculador, e cada sistema operacional possui padrões diferentes. No entanto, também existem programas "estaticamente vinculados" que fornecem todo o seu próprio código.
Um sistema operacional moderno não oferece controle total do computador para um programa em execução. Os programas contam com "chamadas do sistema" para E / S, acesso ao hardware e coisas como sinais e entrada no estado de suspensão. Os serviços e a interface disponíveis são definidos pelo sistema operacional. O sistema operacional também controla quais partes do sistema (memória, registros, interrupções) o programa pode usar.
Um programa GUI também deve trabalhar com o ambiente gráfico do usuário para se desenhar na tela. Mas você provavelmente já pensou nisso.
Por esses motivos, os aplicativos independentes do SO devem contar com uma "máquina virtual" de algum tipo, como a fornecida pelo Java Runtime. Fundamentalmente, uma VM fornece uma interface padrão para os recursos do SO (E / S, sinais, etc.). Obviamente, java ou python também interpretam "bytecode" em vez de lidar com as peculiaridades do conjunto de instruções da Intel; mas essa é uma história diferente.
Sistemas operacionais diferentes também têm funcionalidades diferentes. O Windows possui portas de conclusão de E / S, o Linux não. O FreeBSD tem kqueue, o Linux não. Linux tem futexes, Windows não. Eles também têm maneiras diferentes de fazer a mesma coisa - quais parâmetros você passa para abrir um arquivo? Em que ordem eles vão? Como você invoca especificamente a função "abrir um arquivo" do sistema operacional?
Em geral, os programas não são compatíveis devido às diferenças em sua interface binária de aplicativo (ABI) .
O programa não roda diretamente na CPU?
NÃO ! Esse é o trabalho do sistema operacional, para impedir que os aplicativos sejam executados "diretamente" na CPU. Normalmente, no nível mais baixo (ou seja, aquele em que a API do SO se baseia), um aplicativo faz interface com o kernel do sistema operacional .
É porque o próprio programa compilado precisa fazer referência a bibliotecas específicas do SO?
Sim . Muitas bibliotecas de SO são escritas para facilitar a interface com o próprio sistema operacional, mas há tantas que foram escritas para serem multiplataforma. Isso oculta a interface do SO de baixo nível do desenvolvedor e assume que a versão compilada para esse SO estará disponível em tempo de execução (veja abaixo).
Embora as bibliotecas possam ser escritas de uma forma multiplataforma, quando compiladas, elas não podem ser executadas em várias plataformas. Eles ainda precisam ser recompilados para o sistema operacional de destino específico, novamente para utilizar os componentes subjacentes específicos do sistema operacional (kernel).
Qual é a diferença entre um programa compilado para um sistema operacional e outro?
Por fim, os próprios arquivos executáveis geralmente contêm cabeçalhos de carregamento binário muito específicos e assim por diante (por exemplo, o formato de arquivo executável PE [.exe, .dll, etc ...] para Windows ou ELF para Linux [none, .o, .so , etc ...]). Isso também pode incluir código para carregar os binários específicos do SO compilados para uma biblioteca de software específica.
Por fim, da perspectiva de um programador: convocar convenção . O código compilado passa variáveis para funções de uma determinada maneira (ou seja, através de registradores ou na pilha) em uma ordem muito específica. Mesmo assim, também precisa ser acordado quem é responsável por "limpar" as chamadas de função (o chamador ou o chamado?). Embora existam várias convenções de chamada x86 padrão e amplamente usadas , algumas podem não ser suportadas por determinados sistemas operacionais (isso faz parte da ABI).