Questão Como o OSX executa binários de 64 bits durante a execução em um kernel de 32 bits?


Recentemente descobri que o Mac OS X pode, na verdade, executar aplicativos de 64 bits (x64), mesmo se o kernel x86 estiver carregado. Isso foi chocante para mim pela primeira vez.

Mas então eu percebi que é realmente estranho se o sistema está instalado e rodando sob uma CPU compatível com x64 e não pode executar aplicações x64, não importa o kernel gerenciando os processos. Isso é realmente tão difícil? Basta carregar o maldito aplicativo na memória e configurar o ponteiro de operação da CPU para o primeiro byte, fácil como uma torta!

A única barreira para fazer isso, como eu poderia imaginar, é algum tipo de "cabeçalho executável". Infelizmente, não estou muito confortável com a arquitetura do Windows e a estrutura binária, portanto, preciso de mais explicações aqui.

De fato, o padrão de cabeçalho binário OS do tipo UNIX ELF tem seu irmão ELF64, que (como o documento Aqui descreve) não tem muitas diferenças com o ELF32, mas mesmo que os kernels de 32 bits não consigam rodar o código x64. Sim, este programa provavelmente está ligado a bibliotecas x64 e vamos imaginar que acabamos de copiá-los e colá-los na pasta / usr / lib64. Mas tenho certeza que isso não ajuda, por quê?

E finalmente, o que há de tão especial no kernel do Mac OS X para que não se preocupe com o conjunto de instruções do programa usado? O Mac OS X tem alguns universais e adequados para ambos os kernels executáveis ​​cabeçalho, por isso só pode carregar o aplicativo na memória e dizer para a CPU "executar a partir daqui, eu não me importo o que significa isso"?

P.S .: Eu realmente pensei muito sobre onde colocar essa questão: no stackoverflow.com ou no superuser.com, e decidi colocar aqui, porque o tópico provavelmente é mais específico do sistema operacional.


4


origem


O que fez você pensar que o OSX executará um binário de 64 bits durante a execução em um kernel Darwin de 32 bits? O que você viu? - James T Snell
Porque eu tinha certeza que estava rodando o kernel x64, então o único software que eu tinha instalado era x64 e o sistema operacional os executava perfeitamente. Mas há pouco tempo eu digitei 'uname -a' no meu terminal e fiquei surpreso. Além disso, a Wikipedia confirma isso - en.wikipedia.org/wiki/X86-64#Mac_OS_X - pechenie
Wikipedia e vocês dois podem estar enganados. A execução de um sistema operacional de 64 bits não significa que todos os seus binários sejam de 32 bits. Isso significa que sua arquitetura de kernel e hardware pode suportar binários de 64 bits. O que o seu uname -a Retorna? - James T Snell
Além disso, não entendi o título da sua pergunta. Você pode por favor reescrever isso? - James T Snell
Não é um erro, você pode tentar, se puder. Eu estava rodando o kernel x86, não o x64, então ainda era capaz de rodar o software x64. Eu já mudei para a arquitetura x64_86 agora, mas a saída de uname -a sob x86 kernel provavelmente foi algo assim: Darwin MacMini.local 11.1.0 Darwin Kernel Version 11.1.0: Tue Jul 26 16:07:11 PDT 2011; root:xnu-1699.22.81~1/RELEASE_i386 i386 - pechenie


Respostas:


A verdadeira questão seria por que alguns outros sistemas operacionais não podem executar binários de 64 bits em um kernel de 32 bits. Não há razão fundamental para que isso não seja possível. A arquitetura do processador subjacente suporta tanto um conjunto de instruções de 64 bits (amd64 aka x86-64) quanto um conjunto de instruções de 32 bits (i386), e não há restrição para os dois serem usados ​​juntos (em particular, não há “Modo de 64 bits” separado do “modo de 32 bits”; há um único modo longo, que permite instruções tanto do i386 quanto do conjunto “nativa” amd64.

A execução de aplicativos de 64 bits em um kernel de 32 bits requer um pouco mais de trabalho dentro do kernel, pois ele deve gerenciar ponteiros de 64 bits para o espaço do usuário junto com ponteiros de 32 bits para o espaço do kernel. A maioria, se não todos, os ponteiros passados ​​no kernel são conhecidos como sendo para o espaço do kernel ou conhecidos para o espaço do usuário, portanto, não é um problema se eles tiverem tamanhos diferentes. A principal dificuldade é abrir mão da possibilidade de ter um tipo de ponteiro universal que possua intervalos separados de valores para memória de processo, memória do kernel e memória usados ​​por várias peças de hardware (incluindo RAM), mas isso não é possível em kernels recentes de 32 bits no hardware de classe de PC, se você tiver 4 GB ou mais de RAM, ou quiser mapear 2 GB de RAM mais 2 GB de espaço de processamento, mais memória de kernel e mais, você precisa ser capaz de mapear endereços de mais de 32 bits. ).

De acordo com Artigo da Wikipédia que você cita, o OSX tinha a capacidade de executar processos amd64 em processadores amd64 antes de ter um kernel de 64 bits. O Solaris também mistura indiferentemente os executáveis ​​i386 e amd64 em processadores amd64, independentemente de o kernel ser de 32 ou 64 bits (ambos disponíveis).

Outros sistemas operacionais podem executar processos i386 em um kernel (64 bits) amd64, mas não em processos amd64 em um kernel de 32 bits, por exemplo, Linux, FreeBSD, NetBSD e Windows. No entanto, outros sistemas operacionais tratam amd64 e i386 como arquiteturas completamente diferentes, por exemplo, o OpenBSD.


2



Os indicadores AIUI não são um problema no OS X, já que eles não são transmitidos entre o kernel e o espaço do usuário de qualquer maneira. Mesmo com um processo de 32 bits sendo executado em um kernel de 32 bits, o processo pode ter até 4 GB de espaço de memória virtual definido, e o kernel também pode ter até 4 GB, e os dois não se sobrepõem. Se você passou um ponteiro do espaço do usuário para o kernel, não teria sentido porque há algo completamente diferente naquele endereço no espaço do kernel. - Gordon Davisson
Se você olhar o código-fonte, verá como isso é feito. No OS X de 32 bits, o kernel não é mapeado para o espaço de endereço do usuário, portanto ambos têm espaços de endereço de 32 bits totalmente separados. Todos os dados transmitidos são copiados ou remapeados de qualquer maneira. A penalidade é falta de cache do TLB. - russbishop
A questão é como a CPU pode armazenar o contexto quando o modo de 32 bits não pode acessar o topo 64 bits, bem como 8 altos registros? - phuclv
@ LưuVĩnhPhúc Você precisa de um pequeno código de 64 bits, apenas para salvar e restaurar os registros. Até onde eu sei, isso é possível no x86-64 (e é assim que, por exemplo, o Solaris faz isso). Na verdade, seria um problema no braço, onde você não pode misturar instruções de 64 bits e 32 bits sem uma mudança de privilégio. - Gilles


Não estou familiarizado o suficiente com a arquitetura x86_64 para fornecer os detalhes, mas essencialmente o que acontece é que a CPU é alternada entre o modo de 64 bits e o modo de compatibilidade (32 bits) como parte da alternância de contexto entre o kernel e um espaço do usuário programa. Isso é basicamente a mesma coisa que seria feita para executar um programa de 32 bits em um kernel de 64 bits, apenas acontecendo de forma inversa.

BTW, OS X não usa o formato binário ELF, ele usa Mach-O binários. O formato Mach-O permite binários de múltiplas arquiteturas ("universais"), portanto os programas (e também o kernel) podem ser fornecidos em 32 e 64 bits (e PPC e PPC64 e ...), e o SO pode escolha qual versão carregar (e, portanto, em qual modo executá-la) no momento do carregamento. Você pode usar o file comando em um binário para ver em qual (is) formato (s) ele está. Por exemplo, aqui está o aplicativo Chess fornecido com o OS X v10.5:

$ file Applications/Chess.app/Contents/MacOS/Chess 
Applications/Chess.app/Contents/MacOS/Chess: Mach-O universal binary with 4 architectures
Applications/Chess.app/Contents/MacOS/Chess (for architecture ppc): Mach-O executable ppc
Applications/Chess.app/Contents/MacOS/Chess (for architecture ppc64):   Mach-O 64-bit executable ppc64
Applications/Chess.app/Contents/MacOS/Chess (for architecture i386):    Mach-O executable i386
Applications/Chess.app/Contents/MacOS/Chess (for architecture x86_64):  Mach-O 64-bit executable x86_64

E uma nota para aqueles que duvidam que isso seja possível: OS X suportava programas de 64 bits a partir da v10.4 (com suporte API limitado), mas não incluía um kernel de 64 bits até a v10.6 (e mesmo assim, o O kernel rodou no modo de 32 bits por padrão na maioria dos modelos). Vejo Guia de transição de 64 bits da Apple para detalhes. Estou postando isso de um MacBook Pro rodando 10.6 com um kernel de 32 bits (64 bits não é suportado para este modelo em particular), mas de acordo com o Activity Monitor  O processo que não está sendo executado no modo de 64 bits é kernel_task.


4





Os Macs suportam a execução de aplicativos de 64 bits em um kernel de 32 bits porque um plano de vários estágios faz exatamente isso:

  1. Os aplicativos para Mac são fornecidos como "binários gordos" em "pacotes" que permitem que todos os quatro combos de 64/32 bits e Intel / PPC façam parte de uma única instalação, que pode ser tão simples quanto arrastar e soltar. O sistema operacional executa o apropriado.
  2. Os Macs usam o PAE para acessar mais de 4 GB de RAM ao executar um kernel de 32 bits. O Windows não permite a PAE em versões que não são do servidor devido a problemas de compatibilidade com drivers, que eles têm muito mais, incluindo os de terceiros.
  3. O Tiger adiciona uma ABI (Application Binary Interface) de 64 bits para executar código de 64 bits na parte superior do kernel de 32 bits e uma versão de 64 bits das APIs de baixo nível (Application Programming Interface) para "console" (não GUI) apps.
  4. O Leopard adiciona o Cocoa de 64 bits para aplicativos GUI (mas não o Carbono de 64 bits).
  5. O Snow Leopard adiciona um kernel de 64 bits, que é o padrão em apenas alguns modelos high-end.
  6. O Lion requer uma CPU de 64 bits, mas ainda inclui o kernel de 32 bits. Um Mac antigo com uma CPU de 64 bits, mas uma GPU que possui apenas drivers de 32 bits, teria que executar o kernel de 32 bits, por exemplo.

Portanto, o OS X oferece suporte a aplicativos de 64 bits o mais rápido possível e continua a executar o kernel de 32 bits pelo maior tempo possível devido à situação do driver. (O bit ness do kernel só se torna um fator ao tentar gerenciar grandes quantidades de RAM - as tabelas de páginas também recebem memória - e mudar para um kernel de 64 bits oferece alguns benefícios de desempenho.) Mas a Apple certamente não tem vergonha de coisa.

A verdadeira questão, então, é por que o Windows e o Linux não fizeram a mesma coisa. Para o Windows, considere que sua primeira tentativa no Win64 foi com o Itanium, que era completamente diferente. Mas a resposta final pode se resumir ao que geralmente tem nas últimas décadas: compatibilidade com um monte de programas de terceiros que não fez as coisas do jeito certo:

A implementação de 64 bits do OS X difere significativamente da de   Windows, que trata suas versões de 32 e 64 bits como duas   sistemas operacionais armazenados em diferentes mídias de instalação. Isso está feito   principalmente para manter a compatibilidade do Windows com aplicativos mais antigos -   mover ou renomear coisas como a pasta System32 iria quebrar   programas que esperavam que ele estivesse lá - e como resultado os dois   separados ao ponto em que não há nem mesmo um caminho de atualização entre   Windows de 32 bits e Windows de 64 bits. Por causa disso, e porque   Aplicativos e drivers do Windows geralmente têm 32 bits distintos e   Versões de 64 bits, a transição do Windows para 64 bits foi levemente   mais rock e ligeiramente mais visível para o usuário.

Há muitas informações de segundo plano sobre a transição de 64 bits em ambos Lado Mac e a Lado do Windows. (Esses links são para o último de cada série de artigos; não se esqueça de voltar ao início de cada um.)

Eu não sei qual foi a história com o Linux, mas imagine que Linus tenha uma forte opinião sobre isso.


3



Do lado do Linux: o kernel suportava arquiteturas de 32 e 64 bits muito antes da existência do amd64. A execução de processos de 64 bits em um kernel de 32 bits exigiria alguma reengenharia, pelo menos nas partes dependentes de arquitetura do código. Foi feito o suficiente para executar binários i386 em um kernel amd64, mas não o outro (mais complicado), porque não há casos de uso realmente motivadores para essa direção (se você deseja executar processos de 64 bits, não há razão para não executar um Kernel de 64 bits). - Gilles
Muito obrigado pela sua explicação, eu ainda não posso ganhar (não tenho reputação suficiente), e não posso aceitar duas respostas também, mas tanto você quanto Gilles tornaram isso um pouco mais claro para mim! - pechenie


Eu percebi que é realmente estranho se o sistema está funcionando e sob CPU compatível com x64 não pode executar aplicações x64, não importa o kernel gerenciando os processos. Isso é realmente tão difícil? Basta carregar o maldito aplicativo na memória e configurar o ponteiro de operação da CPU para o primeiro byte, fácil como uma torta!

Você está perdendo uma parte importante. Os aplicativos fazem chamadas de API para funções e serviços fornecidos pelo sistema operacional. Se um aplicativo de 64 bits envia um ponteiro de 64 bits para um sistema operacional de 32 bits, as coisas devem explodir.

Eu suspeito que para fazer as coisas funcionarem de qualquer maneira, o SO deve sobrecarregar a função e fornecer uma versão de 64 bits e 32 bits de cada função. Para cada kernel, a função "off" (função de 64 bits em kernels de 32 bits, função de 32 bits em kernels de 64 bits) será apenas um stub que converte a chamada em segurança de 32 bits e chama novamente a função nativa.


0