27 votes

Pourquoi utiliser un paramètre de fonction 'foo' de cette façon: * (& foo)?

Un extrait de code dans le noyau Linux 0.12 utilise un paramètre de fonction comme celui-ci:

 int do_signal(int signr, int eax /* other parameters... */) {
    /* ... */

    *(&eax) = -EINTR;

    /* ... */
}
 

Le but du code est de mettre -EINTR dans la mémoire où réside eax, mais je ne peux pas dire pourquoi cela ne fonctionnera pas si simplement en assignant à eax:

 eax = -EINTR
 

Comment le compilateur ferait-il une différence entre eax et * (& eax) ?

31voto

Ross Ridge Points 5534

Le vieux Linux que vous avez publié en essayant d'effectuer une très fragiles hack. La fonction a été définie comme ceci:

int do_signal(long signr,long eax,long ebx, long ecx, long edx, long orig_eax,
    long fs, long es, long ds,
    long eip, long cs, long eflags,
    unsigned long * esp, long ss)

Les arguments de la fonction ne représentent en fait les arguments de la fonction (sauf signr), mais les valeurs que l'appel de la fonction (un noyau d'interruption/gestionnaire d'exception écrit dans l'assemblée) est conservé sur la pile avant l'appel de do_signal. L' *(&eax) = -EINTR déclaration vise à modifier le préservés de la valeur de EAX sur la pile. De même, la déclaration *(&eip) = old_eip -= 2 vise à modifier l'adresse de retour de l'appel de gestionnaire. Après l' do_signal renvoie le gestionnaire de pop les 9 premiers "arguments" en dehors de la pile de la restauration à l'nommé registres. Ensuite, il exécute un IRETD instruction de la pop que les autres arguments de la pile et le retour au mode utilisateur.

Inutile de dire que ce hack est incroyablement fiable. C'est dépendante sur le compilateur de générer du code exactement de la même façon qu'ils peuvent en attendre. Je suis surpris qu'il a même travaillé le compilateur GCC de l'époque, je doute qu'il fut longtemps avant de GCC introduit une optimisation qui le rompit.

22voto

Shafik Yaghmour Points 42198

Une possible intention pourrait être de maintenir l' eax variable d'un registre. Si l'on regarde le projet de norme C99 , nous voyons que la section 6.5.3.2 l'Adresse et les opérateurs d'indirection dit (c'est moi qui souligne):

Unaire & opérateur donne l'adresse de son opérande. [...]Si l'opérande est le résultat d'une unaire * opérateur, ni que l'exploitant de l'opérateur & est évaluée et le résultat est comme si les deux ont été omis, sauf que les contraintes qui pèsent sur les opérateurs s'appliquent toujours et le résultat n'est pas une lvalue.[...]

dans la note de bas de page 87 il est dit (c'est moi qui souligne à l'avenir):

Ainsi, &*E est équivalent à E (même si E est un pointeur null), et &(E1[E2]) à ((E1)+(E2)). Il est toujours vrai que si E est une fonction désignation ou une lvalue qui est valable un opérateur unaire & l'opérateur, *&E est une fonction de désignation ou une lvalue égal à E.

nous retrouvons les suivants contrainte sur & operator:

L'opérateur unaire & exploitant doit être soit une fonction indicateur, le résultat d'un [] ou unaire * l'opérateur, ou une lvalue que désigne un objet qui n'est pas un peu de champ et n'est pas déclaré avec le registre de stockage de classe rédacteur de devis.

Ce qui est logique, puisque nous ne pouvons pas prendre l'adresse d'un registre et donc par la réalisation d'une adresse de fonctionnement ils peuvent avoir été d'essayer d'empêcher le compilateur d'effectuer les opérations complètement dans les registres et s'assurer que les données spécifiques dans les emplacements de mémoire sont modifiés.

Comme ouah points ce n'est pas d'empêcher le compilateur de l'optimisation de ce qui est effectivement un non-op de suite, mais comme documenté dans GCC hacks dans le noyau Linux. Linux s'est appuyé sur de nombreux gcc extensions et considérant qu' 0.12 est un très ancien noyau, gcc peut avoir la garantie que le comportement ou peuvent avoir, par accident, de manière fiable travaillé de cette façon, mais je ne peux pas trouver toute la documentation qui le dit.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X