Como alguém que escreveu programas que são executados sem um SO, ofereço uma resposta definitiva.
Would an executable need an OS kernel to run?
Isso depende de como esse programa foi escrito e criado.
Você poderia escrever um programa (supondo que você tem o conhecimento) que não requer um sistema operacional.
Esse programa é descrito como standalone .
Carregadores de inicialização e programas de diagnóstico são usos típicos para programas autônomos.
No entanto, o programa típico escrito e construído em algum ambiente do sistema operacional host teria como padrão a execução nesse mesmo ambiente do sistema operacional host.
Decisões e ações muito explícitas são necessárias para escrever e construir um programa independente.
... the output from the compiler is the machine code (executable) which I thought were instructions to the CPU directly.
Correto.
Recently I was reading up on kernels and I found out that programs cannot access the hardware directly but have to go through the kernel.
Essa é uma restrição imposta por um modo de CPU que o sistema operacional usa para executar programas e facilitado por certas ferramentas de compilação, como compiladores e bibliotecas. Não é uma limitação intrínseca em todos os programas já escritos.
So when we compile some simple source code, say with just a printf() function, and the compilation produces the executable machine code, will each instruction in this machine code be directly executed from memory (once the code is loaded into memory by the OS) or will each command in the machine code still need to go through the OS (kernel) to be executed?
Toda instrução é executada pela CPU.
Uma instrução não suportada ou ilegal (por exemplo, processo tem privilégio insuficiente) causará uma exceção imediata, e a CPU executará uma rotina para lidar com essa condição incomum.
Uma função printf () não deve ser usada como um exemplo de "código fonte simples" .
A tradução de uma linguagem de programação de alto nível orientada a objeto para um código de máquina pode não ser tão trivial quanto você sugere.
E então você escolhe uma das funções mais complexas de uma biblioteca de tempo de execução que realiza conversões de dados e I / O.
Observe que sua pergunta estipula um ambiente com um sistema operacional (e uma biblioteca de tempo de execução).
Uma vez que o sistema é inicializado e o sistema operacional recebe o controle do computador, restrições são impostas sobre o que um programa pode fazer (por exemplo, a E / S deve ser executada pelo sistema operacional).
Se você espera executar um programa independente (ou seja, sem um sistema operacional), não é necessário inicializar o computador para executar o SO.
... what happens after the machine code is loaded into memory?
Isso depende do ambiente.
Para um programa autônomo, ele pode ser executado, ou seja, o controle é entregue ao pular para o endereço inicial do programa.
Para um programa carregado pelo sistema operacional, o programa deve ser vinculado dinamicamente a bibliotecas compartilhadas das quais depende. O sistema operacional deve criar um espaço de execução para o processo que executará o programa.
Will it go through the kernel or directly talk to the processor?
O código da máquina é executado pela CPU.
Eles não "passam pelo kernel" , mas nem "conversam com o processador" .
O código da máquina (composto por código operacional e operandos) é uma instrução para a CPU que é decodificada e a operação é executada.
Talvez o próximo tópico que você deva investigar seja modos de CPU .