Comment les registres fs/gs sont-ils utilisés dans Linux AMD64?

Sur l'architecture x86-64, deux registres ont un but particulier: FS et GS. Dans linux 2.6.* , le registre FS semble être utilisé pour stocker des informations thread-local.

  • Est-ce exact?
  • Qu'est-ce qui est stocké à fs: 0? Y a-t-il une structure C qui décrit ce contenu?
  • Quelle est alors l'utilisation de GS?
28

3 réponses

Dans x86-64 Il y a 3 entrées TLS , deux d'entre elles accessibles via FS et GS , FS est utilisé en interne par la glibc (dans IA32 apparemment FS est utilisé par Wine et GS par la glibc).

La Glibc fait son point D'entrée TLS à un struct pthread cela contient des structures internes pour le threading. La glibc fait généralement référence à une variable struct pthread comme pd, probablement pour pthread descriptor .

Sur x86-64, struct pthread commence avec un tcbhead_t (cela dépend l'architecture, voir les macros TLS_DTV_AT_TP et TLS_TCB_AT_TP). Cet en-tête de bloc de contrôle de Thread, AFAIU, contient certains champs qui sont nécessaires même lorsqu'il y a un seul thread. Le DTV est le vecteur de Thread dynamique, et contient des pointeurs vers des blocs TLS pour les DSO chargés via dlopen(). Avant ou après le TCB, il existe un bloc TLS statique pour l'exécutable et les DSOs liés au temps de chargement (du programme). Le TCB et la DTV sont assez bien expliqués dans le document TLS d'Ulrich Drepper (regardez pour les diagrammes du chapitre 3).

32
répondu ninjalj 2011-07-07 20:55:54

Pour répondre réellement à votre question fs:0: L'ABI x86_64 exige que fs:0 contienne l'adresse "pointée" par fs elle-même. C'est, fs:-4 charge la valeur stockée à fs:0 - 4. Cette fonctionnalité est nécessaire car vous ne pouvez pas facilement obtenir l'adresse pointée par fs sans passer par le code du noyau. Avoir l'adresse stockée à fs:0 rend ainsi le travail avec le stockage local de thread beaucoup plus efficace.

Comme Vous pouvez le voir en action lorsque vous prenez l'adresse d'un thread local variable:

static __thread int test = 0;

int *f(void) {
    return &test;
}

int g(void) {
    return test;
}

Compile à

f:
    movq    %fs:0, %rax
    leaq    -4(%rax), %rax
    retq

g:
    movl    %fs:-4, %eax
    retq

I686 fait la même chose mais avec %gs. Sur aarch64, ce n'est pas nécessaire car l'adresse peut être lue à partir du registre tls lui-même.

12
répondu MuhKarma 2015-11-20 12:50:54

Quelle est alors l'utilisation de GS?

Le noyau Linux x86_64 utilise GS register comme un moyen efficace d'acquérir la pile d'espace du noyau pour les appels système.

GS register stocke l'adresse de base pour la zone par cpu. Pour acquérir la pile d'espace noyau, dans entry_SYSCALL_64

movq    PER_CPU_VAR(cpu_current_top_of_stack), %rsp

Après avoir développé PER_CPU_VAR, nous obtenons ce qui suit:

movq    %gs:cpu_current_top_of_stack, %rsp
2
répondu firo 2018-09-18 10:58:23