Cada região do diagrama é um segmento?
Estes são 2 usos quase totalmente diferentes da palavra "segmento"
- segmentação x86 / registradores de segmentos: os sistemas operacionais x86 modernos usam um modelo de memória plana em que todos os segmentos têm a mesma base = 0 e limite = max no modo de 32 bits, o mesmo que o hardware impõe no modo de 64 bits , tornando a segmentação um pouco vestigial . (Exceto para FS ou GS, usado para armazenamento local de encadeamento, mesmo no modo de 64 bits.)
- Seções / segmentos do vinculador / carregador de programas. ( Qual é a diferença de seção e segmento no formato de arquivo ELF )
Os usos têm uma origem comum: se você estivesse usando um modelo de memória segmentada (especialmente sem memória virtual paginada), poderá ter dados e endereços BSS relativos à base do segmento DS, pilha relativa à base SS e código relativo à Endereço base do CS.
Portanto, vários programas diferentes podem ser carregados em endereços lineares diferentes ou até movidos após a inicialização, sem alterar os desvios de 16 ou 32 bits em relação às bases do segmento.
Mas então você precisa saber a qual segmento um ponteiro é relativo, para ter "ponteiros distantes" e assim por diante. (Os programas x86 reais de 16 bits geralmente não precisavam acessar seu código como dados, portanto, poderia usar um segmento de código de 64k em algum lugar e talvez outro bloco de 64k com DS = SS, com a pilha crescendo de compensações altas e dados em ou um pequeno modelo de código com todas as bases de segmentos iguais).
Como a segmentação x86 interage com a paginação
O mapeamento de endereço no modo 32/64 bits é:
- segmento: deslocamento (base do segmento implícita no registro que mantém o deslocamento ou substituída por um prefixo de instrução)
- Endereço virtual linear de 32 ou 64 bits = base + deslocamento. (Em um modelo de memória plana como o Linux usa, ponteiros / deslocamentos = endereços lineares também. Exceto ao acessar o TLS em relação ao FS ou GS.)
as tabelas de páginas (armazenadas em cache pelo TLB) são mapeadas linearmente para o endereço físico 32 (modo herdado), 36 (PAE herdado) ou 52 bits (x86-64). ( /programming/46509152/why-in-64bit-the-virtual-address-are-4-bits-short-48bit-long-compared-with-the ).
Esta etapa é opcional: a paginação deve ser ativada durante a inicialização, definindo um pouco em um registro de controle. Sem paginação, endereços lineares são endereços físicos.
Observe que a segmentação não permite que você use mais de 32 ou 64 bits de espaço de endereço virtual em um único processo (ou thread) , porque o espaço de endereço simples (linear) em que tudo é mapeado tem apenas o mesmo número de bits que as compensações. (Esse não era o caso do x86 de 16 bits, onde a segmentação era realmente útil para usar mais de 64k de memória, com registros e deslocamentos principalmente de 16 bits.)
A CPU armazena em cache os descritores de segmento carregados do GDT (ou LDT), incluindo a base do segmento. Quando você desreferencia um ponteiro, dependendo do registro em que ele está, o padrão é DS ou SS como o segmento. O valor do registro (ponteiro) é tratado como um deslocamento da base do segmento.
Como a base do segmento é normalmente zero, as CPUs fazem isso em casos especiais. Ou a partir de outra perspectiva, se você faz tem uma base de segmento não-zero, cargas têm latência extra porque o caso "especial" (normal) de contornar adicionando o endereço de base não se aplica.
Como o Linux configura os registros do segmento x86:
A base e o limite de CS / DS / ES / SS são todos 0 / -1 no modo de 32 e 64 bits. Isso é chamado de modelo de memória plana porque todos os ponteiros apontam para o mesmo espaço de endereço.
(Os arquitetos de CPU AMD neutralizaram a segmentação ao impor um modelo de memória plana para o modo de 64 bits porque os sistemas operacionais principais não o usavam de qualquer maneira, exceto pela proteção sem execução, que era fornecida de uma maneira muito melhor paginando com o PAE ou x86- Formato de tabela de 64 páginas.)
TLS (Thread Local Storage): FS e GS não são fixos na base = 0 no modo longo. (Eles eram novos no 386 e não eram usados implicitamente por nenhuma instrução, nem mesmo rep
pelas instruções de cadeia de caracteres que usam ES). x86-64 Linux define o endereço base do FS para cada thread como o endereço do bloco TLS.
por exemplo, mov eax, [fs: 16]
carrega um valor de 32 bits de 16 bytes no bloco TLS para este encadeamento.
o descritor do segmento CS escolhe em que modo a CPU está (modo protegido de 16/32/64 bits / modo longo). O Linux usa uma única entrada GDT para todos os processos de espaço do usuário de 64 bits e outra entrada GDT para todos os processos de espaço do usuário de 32 bits. (Para que a CPU funcione corretamente, o DS / ES também deve ser definido como entradas válidas, assim como o SS). Ele também escolhe o nível de privilégio (kernel (anel 0) vs. usuário (anel 3)), portanto, mesmo ao retornar ao espaço do usuário de 64 bits, o kernel ainda precisa providenciar a alteração do CS, usando iret
ou em sysret
vez de um normal instruções de pular ou reter.
No x86-64, o syscall
ponto de entrada usa swapgs
para alternar o GS do GS do espaço do usuário para o kernel, que ele usa para encontrar a pilha de kernel desse encadeamento. (Um caso especializado de armazenamento local de encadeamento). A syscall
instrução não altera o ponteiro da pilha para apontar para a pilha do kernel; ainda está apontando para a pilha do usuário quando o kernel atinge o ponto de entrada 1 .
O DS / ES / SS também deve ser definido como descritores de segmento válidos para que a CPU funcione no modo protegido / modo longo, mesmo que a base / limite desses descritores seja ignorada no modo longo.
Então, basicamente, a segmentação x86 é usada para TLS e para os itens obrigatórios do osdev x86 que o hardware exige que você faça.
Nota de rodapé 1: Histórico de diversão: há arquivos de listas de discussão entre desenvolvedores do kernel e arquitetos da AMD alguns anos antes do lançamento do AMD64 silicon, resultando em ajustes no design, syscall
para que ele fosse utilizável. Veja os links nesta resposta para obter detalhes.