Como a get_current() funciona?

  1. static inline struct task_struct * get_current(void)
  2. {
  3. struct task_struct *current;
  4. __asm__("andl %%esp,%0; ":"=r" (current) : "0" (~8191UL));
  5. return current;
  6. }

get_current() é uma rotina para conceder acesso para a estrutura task_struct da tarefa que está atualmente em execução.

Ele usa frequentemente assembly inline características do GCC, para realizar esta tarefa, conforme a seguir:

  1. __asm__(

Isto mostra uma parte do assembly inline que o compilador deve inserir dentro do código de saída.

O ___asm___ é o mesmo que asm, mas não pode ser desabilitado por flags pela linha de comando

  1. "andl %%esp,%0

"%%" é a macro que expande para um "%".
"%0" é a macro que expande para o primeira especificação de entrada e saída.

Assim neste caso, ele pega o ponteiro da pilha (Registro %esp) e faz uma operação logica AND e armazena dentro de um registrador que contém o valor 0xFFFFE000, Deixando o resultando no registrador.

Basicamente, a estrutura task_struct e a pilha de tarefas do kernel ocupam um bloco de 8KB alinhado, com a estrutura task_struct no inicio e o crescimento da pilha ocorre a partir do final para baixo. Assim você pode encontrar a estrutura task_struct pela zerando o valor da base a partir de 13 bits do ponteiro da pilha.

  1. ; "

O ponto e virgula pode ser usado para separar expressões em assembly, como acontece com uma seguência de caracter de nova linha("\n").

  1. :"=r" (current)

Isto especifica uma exceção de saída( todos os que ocorrem após os primeiros dois pontos, mas antes da segunda). O '=' tambem especifica qual desta e uma saida. O "r" indica que um registrador de finalidade geral deve ser alocado tal que a instrução pode colocar o valor na saída dele. Os bits dentro dos parentesis - 'current' - é o destino do valor de saida (normalmente uma variável local) uma vez que o C é retornado a parte.

  1. : "0" (~8191UL));

Isto especifica um exceção de entrada (todos que ocorrem após o segundo dois pontos, mas antes do terceiro). O '0' faz referência a outra exceção(Neste caso, a primeira exceção de saída), dizendo que o mesmo registro ou localização de memória deve ser utilizado para ambos. O '~8191UL' dentro dos parentesis é uma constante o qual deve ser carregada dentro do registrador alocado para o valor de saída antes de utilizar as instruções dentro do bloco asm.

Veja também a página de informações do compilador GCC, Tópico "Extensões C", Subtópico "Extensões asm"