2015-04-03 4 views
-2

Que fait cet ensemble d'instructions?Que fait cet ensemble d'instructions?

7ffff7a97759 mov 0x33b780(%rip),%rax  # 0x7ffff7dd2ee0 
    7ffff7a97760 mov (%rax),%rax 
    7ffff7a97763 test %rax,%rax 
    7ffff7a97766 jne 0x7ffff7a9787a 

Je ne peux pas comprendre ce que ces instructions feraient, quelqu'un peut-il expliquer?

+0

Je suppose que "ne rien faire" signifie ne pas sauter? Il fait encore des choses – Shade

+0

@PaulGriffiths cela ressemble à une réponse. – Shade

+0

@Shade: D'accord, commentaire supprimé. –

Répondre

1

Franchir une étape à la fois ...

7ffff7a97759 mov 0x33b780(%rip),%rax  # 0x7ffff7dd2ee0 

Ce:

  1. Prend l'adresse dans rip, et ajoute 0x33b780 à elle. À ce stade, rip contient l'adresse de l'instruction suivante, qui est 0x7ffff7a97760. Ajoutant 0x33b780 à cela vous donne 0x7ffff7dd2ee0, qui est l'adresse dans le commentaire.

  2. Il copie la valeur de 8 octets stockée à cette adresse dans rax.

Sommes d'accord pour appeler cette valeur de 8 octets "le pointeur". Basé sur la valeur de l'adresse, 0x7ffff7dd2ee0 est presque certainement un emplacement sur la pile.

7ffff7a97760 mov (%rax),%rax 

Cette copie la valeur de 8 octets stocké à l'adresse dans le pointeur dans rax.

7ffff7a97763 test %rax,%rax 

Ce ET effectue une opération de rax avec lui-même, en rejetant le résultat, mais en modifiant les drapeaux.

7ffff7a97766 jne 0x7ffff7a9787a 

Ce sauts à l'emplacement 0x7ffff7a9787a si le résultat de cette opération AND binaire est non nul, autrement dit, si la valeur stockée dans rax est non nul.

Donc, en résumé, cela signifie « trouver la valeur de 8 octets stockés à l'adresse contenue dans le pointeur indiqué par rip, plus 0x33b780, et si cette valeur est zéro, saut à l'emplacement 0x7fff7a9787a ». Par exemple, en termes C, le pointeur stocké à 0x7ffff7dd2ee0 peut être un long * et ce code vérifie si le long qu'il pointe contient 0.

son équivalent en C pourrait être quelque chose comme:

long l = 0; 
long * p = &l; /* Assume address of p is 0x7ffff7dd2ee0 */ 


/* Assembly instructions in your question start here */ 

if (*p == 0) { 
    /* This would be the instruction after the jne */ 
    /* Do stuff */ 
} 

/* Location 0x7ffff7a9787a would be here, after the if block */ 
/* Do other stuff */ 

Voici un programme complet montrant l'utilisation de cette construction, la seule différence étant que nous trouvons notre pointeur en référence au pointeur de cadre, plutôt qu'à la pointeur d'instruction:

.global _start 

     .section .rodata 

iszerostr:  .ascii "Value of a is zero\n" 
isntzerostr: .ascii "Value of a is not zero\n" 

     .section .data 

a:  .quad 0x00     # We'll be testing this for zero... 

     .section .text 

_start: 
     mov  %rsp, %rbp    # Initialize rbp 
     sub  $16, %rsp    # Allocate stack space 
     lea  (a), %rax    # Store pointer to a in rax... 
     mov  %rax, -16(%rbp)   # ...and then store it on stack 

     # Start of the equivalent of your code 

     mov  -16(%rbp), %rax   # Load pointer to a into rax 
     mov  (%rax), %rax   # Dereference pointer and get value 
     test %rax, %rax    # Compare pointed-to value to zero 
     jne  .notzero    # Branch if not zero 

     # End of the equivalent of your code 

.zero: 
     lea  (iszerostr), %rsi  # Address of string 
     mov  $19, %rdx    # Length of string 
     jmp  .end 

.notzero: 
     lea  (isntzerostr), %rsi  # Address of string 
     mov  $24, %rdx    # Length of string 

.end: 
     mov  $1, %rax    # write() system call number 
     mov  $1, %rdi    # Standard output 
     syscall       # Make system call 

     mov  $60, %rax    # exit() system call number 
     mov  $0, %rdi    # zero exit status 
     syscall       # Make system call 

avec sortie:

[email protected]:~/src/asm$ as -o tso.o tso.s; ld -o tso tso.o 
[email protected]:~/src/asm$ ./tso 
Value of a is zero 
[email protected]:~/src/asm$ 

Incidemment, la raison du calcul d'un décalage basé sur le pointeur d'instruction est d'améliorer l'efficacité du code indépendant de la position, ce qui est nécessaire pour les bibliothèques partagées.Les adresses de mémoire et les bibliothèques partagées ne se mélangent pas aussi bien, mais si vous savez que le code et les données seront toujours à la même distance, le référencement du code et des données via le pointeur d'instruction vous permet de produire du code relogeable. Sans cette capacité, il est généralement nécessaire d'avoir une couche d'indirection, puisque les branches relatives sont généralement limitées dans la gamme.

+0

Une question rapide: pourquoi accèdent-ils à un élément de données en décalant le pointeur d'instruction? Est-ce commun? Les choses ont beaucoup changé depuis que j'avais l'habitude d'écrire du code asm sur le 386/486 etc .. Je me sens vieux! Merci pour l'excellente explication. –

+1

@BingBang: Il s'agit d'améliorer l'efficacité du code indépendant de la position, ce qui est nécessaire pour les bibliothèques partagées. Les adresses de mémoire et les bibliothèques partagées ne se mélangent pas aussi bien, mais si vous savez que le code et les données seront toujours à la même distance, le référencement du code et des données via le pointeur d'instruction vous permet de produire du code relogeable. Je crois que cette capacité a été introduite avec x86_64. Sans cette capacité, il est généralement nécessaire d'avoir une couche d'indirection, puisque les adresses relatives sont limitées dans la gamme. –