2010-11-22 30 views
2

Comment un assembleur gère-t-il les classes et les objets lors de la compilation d'un programme? Et comment est-ce stocké dans la RAM et le fichier exécutable? Dans un premier temps, la mémoire est allouée en fonction de la taille de la classe, par exemple 20 octets. Dans ces 20 octets, toutes les variables de la classe sont stockées. Mais il y a deux problèmes:Comment l'assembleur gère-t-il les classes et les objets, et comment sont-ils stockés dans la RAM et l'exécutable?

  1. Comment les pointeurs vers les classes fonctionnent-ils?
  2. Comment une méthode appelée sait-elle objet à qui appartient-elle?

Pourriez-vous me expliquer mon explication? (Si vous utilisez un exemple de code, je préfère Objective-C, C++ et x86 Assembly)

Répondre

4

L'assembleur n'a aucune idée de ce qu'est une classe, il ne fait qu'assembler le code machine, dans lequel la macro occasionnelle est jetée. class est une structure avec un vftable optionnel, avec toutes les fonctions spéciales de manipulation et de classe (virtualism, polymorphism, inheiritanc, etc.) en cours à l'étape intermédiaire, quand le code IR est créé. La mémoire serait allouée comme une structure, une variable, un tableau ou toute autre donnée 'blob' (statiquement ou dynamiquement, prenant en compte l'alignement, la const'ness et l'empaquetage), excepté le code de support pour manipuler la pile statique. (fait à nouveau au niveau IR), les ctors, et l'initialisation statique (bien que l'initialisation statique peut se produire pour plus que des objets de classe). Je suggère que vous donniez une lecture au livre du dragon (les huit premiers chapitres le couvriraient), pour avoir une idée plus claire du fonctionnement du compilateur et de l'assembleur, vu que ces choses ne sont pas traitées par l'assembleur, mais par le compilateur./ou back ends, en fonction de la structure du compilateur et de son IL.

+0

Je pense que vous vouliez dire "comme ces choses ne sont pas traitées par l'assembleur, mais par les extrémités avant et arrière du compilateur". Et pour ajouter à cela, je pense que c'est juste le début et non la fin, dépend du compilateur et de son langage interne. –

+0

@dwelch: réparé, ne devrait pas poster si tôt le matin: p – Necrolis

3

(2) Les fonctions membres sont réécrites par le compilateur. Considérez class A comme suit.

class A { 
    int i; 
public: 
    A() : i (0) { } 

    void f (int a, char *b) { i = a; } 
} 

Alors ce que le compilateur fait de A::f ressemble à quelque chose comme ça (pseudo-code):

void A::f (A * const this, int a, char *b) { this->i = a; } 

Considérons maintenant un appel à A::f.

A a; 
a.f (25, ""); 

le compilateur génère un code similaire à ce (pseudo-code):

A a; 
A::f (&a, 25, ""); 

En d'autres termes, le compilateur fonctionne le pointeur this caché dans chaque fonction membre non statique et chaque appel reçoit une référence à l'instance à laquelle il a été appelé. Ceci, en particulier, signifie que vous pouvez appeler des fonctions membres non statiques sur des pointeurs NULL.

A *a = NULL; 
a->f (25, ""); 

L'accident ne se produit que lorsque vous faites référence en fait des variables membres de classe non statique. Le rapport d'accident qui en résulte illustre également la réponse à la question (1). Dans la plupart des cas, vous ne plantez pas sur l'adresse 0, mais un décalage de cela. Ce décalage correspond au décalage que la variable accédée a dans la disposition de la mémoire choisie par le compilateur pour class A (dans ce cas, de nombreux compilateurs vont effectivement le compenser avec 0x0 et class A ne seront pas distingués en mémoire de struct A { int i; };).Fondamentalement, les pointeurs vers les classes sont des pointeurs vers la structure C équivalente. Les fonctions membres sont implémentées en tant que fonctions libres en prenant comme référence une instance comme premier argument. Toutes les vérifications d'accès à l'égard des membres publics, protégés et privés sont faites au préalable par le compilateur, l'assemblée générée n'a aucune idée de l'un de ces concepts. En fait, les premières versions de C++ auraient été des ensembles de macros C intelligentes.

La disposition de la mémoire (généralement) change un bit lorsque vous avez des fonctions virtuelles.