2010-08-07 5 views
0

Supposons que nous avons deux entiers et les variables caractères:quel sera le mode d'adressage dans le code d'assemblage généré par le compilateur ici?

int adad=12345; 
char character; 

Supposons que nous discutons d'une plate-forme dans laquelle, la longueur d'une variable entière est supérieure ou égale à trois octets, je veux accéder à la troisième octet de cet entier et de le mettre dans la variable de caractère, avec cela dit je l'écrire comme ceci:

character=*((char *)(&adad)+2); 

Considérant que la ligne de code et le fait que je ne suis pas un expert du compilateur ou de l'ensemble, je sais un peu sur les modes d'adressage dans l'assemblage et je me demande l'adresse du troisième octet (ou je suppose qu'il vaut mieux dire décalage du troisième octet) ici serait dans les instructions générées par cette ligne de code eux-mêmes, ou ce serait être dans une variable distincte dont adresse (ou décalage) est dans ces instructions?

+4

Cela dépend entièrement du compilateur. Vous devez regarder le code émis par votre compilateur (s). –

+0

Heck, ça dépend aussi de la puce. – dmckee

Répondre

3

La meilleure chose à faire dans de telles situations est de l'essayer. Voici un exemple de programme:

int main(int argc, char **argv) 
{ 
    int adad=12345; 
    volatile char character; 

    character=*((char *)(&adad)+2); 

    return 0; 
} 

J'ai ajouté le volatile pour éviter la ligne d'affectation étant complètement optimisé loin. Maintenant, voici ce que le compilateur est venu avec (pour -Oz sur mon Mac):

_main: 
    pushq %rbp 
    movq %rsp,%rbp 
    movl $0x00003039,0xf8(%rbp) 
    movb 0xfa(%rbp),%al 
    movb %al,0xff(%rbp) 
    xorl %eax,%eax 
    leave 
    ret 

Les trois seules lignes qui nous intéressent sont:

movl $0x00003039,0xf8(%rbp) 
    movb 0xfa(%rbp),%al 
    movb %al,0xff(%rbp) 

Le movl est l'initialisation de adad. Ensuite, comme vous pouvez le voir, il lit le troisième octet de adad, et le stocke dans la mémoire (le volatile force forcement ce magasin).

Je suppose qu'une bonne question est pourquoi est-ce important pour vous quel assemblage est généré?Par exemple, en changeant mon drapeau d'optimisation pour -O0, la sortie d'assemblage de la partie intéressante du code est:

movl $0x00003039,0xf8(%rbp) 
    leaq 0xf8(%rbp),%rax 
    addq $0x02,%rax 
    movzbl (%rax),%eax 
    movb %al,0xff(%rbp) 

Ce qui est assez franchement vu que les opérations exactes logiques de votre code:

  1. Initialiser adad
  2. Prenez l'adresse de adad
  3. Ajouter 2 à cette adresse
  4. Charge un octet par déréférencement la nouvelle adresse
  5. magasin un octet dans character

optimisations diverses changera la sortie ... si vous avez vraiment besoin d'un comportement spécifique/mode d'adressage pour une raison quelconque, vous pourriez avoir à écrire l'assemblée toi-même.

+0

Bonne réponse pour le x86, mais tout le monde n'est pas (même aujourd'hui) un x86. – dmckee

+1

@dmckee, le point n'est pas d'être x86, mais que l'OP devrait juste regarder son binaire et le découvrir. Il se trouve que j'ai une machine x86 à portée de main. Tu veux que je fasse un ARM? –

2

Sans rien savoir sur le compilateur et l'architecture CPU sous-jacente, aucune réponse définitive ne peut être donnée. Par exemple, toutes les architectures CPU n'autorisent pas l'adressage de tous les octets arbitraires en mémoire (même si je crois que tous les formats actuellement populaires le font): sur un CPU adressé par un mot, au lieu d'adressé par octet, ce que le compilateur va inévitablement être le chargement dans un registre du mot entier adad (vraisemblablement par un décalage d'un registre de pointeur de base, si la variable en question est sur la pile [1]), suivi par le décalage et le masquage pour isoler l'octet d'intérêt. Notez que, sans savoir de quelle architecture de CPU nous parlons et comment le compilateur l'utilise, nous ne pouvons même pas dire si "charger un mot à un offset fixe à partir d'un registre de base" est quelque chose qui est fait en ligne dans l'instruction (comme on pourrait l'espérer, et de nombreuses architectures populaires supportent définitivement ;-) ou nécessite une arithmétique d'adresse séparée dans un registre auxiliaire.

OIEau, que ce soit une bonne idée ou non, il est certainement possible de définir une architecture de CPU qui ne peut pas charger/registres de magasins, sauf d'autres registres ou adresses mémoire définies par d'autres registres ou constante, et certaines de ces architectures existent (Bien qu'ils ne soient pas très populaires en ce moment ;-).

Questions connexes