Question

Puis le compteur de programme sur les processeurs Intel peuvent être lus directement (sans « trucs ») en mode noyau ou d'un autre mode?

Était-ce utile?

La solution

Non, EIP / IP ne peut pas accéder directement, mais dans le code dépendant de la position, il est une constante liaison en temps de sorte que vous pouvez utiliser un symbole à proximité (ou lointain) comme immédiat.

   mov eax, nearby_label    ; in position-dependent code
nearby_label:

Pour obtenir EIP ou IP en position indépendante code 32 bits:

        call _here
_here:  pop eax
; eax now holds the PC.

Sur les processeurs plus récents que Pentium Pro (ou PIII probablement), call rel32 avec rel32 = 0 est spéciale tubé pour ne pas affecter la pile de prédiction de retour adresse . C'est donc efficace, ainsi que sur x86 compact moderne, et est ce que clang utilise pour la position indépendante du code 32 bits.

Le vieux 32 bits Pentium CPU Pro, ce déséquilibrerait la pile de prédicteur appel / retour, donc préférez appeler une fonction qui ne renvoie en fait, pour éviter mispredicts branche sur un maximum de 15 ou si les futures instructions de ret dans vos fonctions parentales. (À moins que vous ne va pas revenir, ou si rarement qu'il n'a pas d'importance.) Les facteurs prédictifs de retour adresse pile récupérera, cependant.

get_retaddr_ppro:
    mov  eax, [esp]
    ret                ; keeps the return-address predictor stack balanced
                       ; even on CPUs where  call +0 isn't a no-op.

En mode x86-64, RIP peut être lu directement à l'aide d'un lea RIP-parent .

default rel           ; NASM directive: use RIP-relative by default

lea  rax, [_here]     ; RIP + 0
_here:

MASM ou GNU .intel_syntax: lea rax, [rip]

AT & T Syntaxe: lea 0(%rip), %rax

Autres conseils

Si vous avez besoin de l'adresse d'une instruction spécifique, généralement quelque chose comme ça fait l'affaire:

thisone: 
   mov (e)ax,thisone

(Note:. Sur certains assembleurs cela pourrait faire la mauvaise chose et lire un mot de [thisone], mais il y a généralement une syntaxe pour obtenir l'assembleur pour faire la bonne chose)

Si votre code est chargé statiquement à une adresse spécifique, l'assembleur connaît déjà (si vous l'avez dit le droit adresse de départ) les adresses absolues de toutes les instructions. Code Dynamiquement chargé, par exemple comme une partie d'une application sur un système d'exploitation moderne, va obtenir le droit adresse grâce à résoudre la délocalisation effectuée par l'éditeur de liens dynamiques (à condition que l'assembleur est assez intelligent pour générer les tables de réinstallation, dont ils sont en général).

Sur x86-64 vous pouvez le faire par exemple:

lea rax,[rip] (48 8d 05 00 00 00 00)

Il n'y a pas d'instruction pour lire directement le pointeur d'instruction (EIP) sur x86. Vous pouvez obtenir l'adresse de l'instruction en cours assemblé avec un peu de montage en ligne:

// GCC inline assembler; for MSVC, syntax is different
uint32_t eip;
__asm__ __volatile__("movl $., %0", : "=r"(eip));

La directive assembleur . sera remplacé par l'adresse de l'instruction en cours par l'assembleur. Notez que si vous enveloppez l'extrait ci-dessus dans un appel de fonction, vous aurez juste la même adresse (dans cette fonction) à chaque fois. Si vous voulez une fonction plus utilisable C, vous pouvez utiliser à la place un certain assemblage non-ligne:

// In a C header file:
uint32_t get_eip(void);

// In a separate assembly (.S) file:
.globl _get_eip
_get_eip:
    mov 0(%esp), %eax
    ret

Cela signifie que chaque fois que vous voulez obtenir le pointeur d'instruction, il est depuis un peu moins efficace, vous avez besoin d'un appel de fonction supplémentaire. Notez qu'il faire de cette façon ne souffle pas la pile d'adresse de retour (RAS). La pile d'adresses de retour est une pile séparée des adresses de retour utilisé en interne par le processeur pour faciliter pour les instructions de RET.

Chaque fois que vous avez une instruction d'appel, le courant EIP est poussé sur la RAS, et chaque fois que vous avez une instruction RET, le RAS est sauté, et la valeur supérieure est utilisée comme la prédiction de branchement cible pour cette instruction. Si vous vous trompez la RAS (par exemple en ne correspond pas à chaque appel avec un RET, comme dans solution de Cody de ), vous allez obtenir un tas de mauvaises prédictions de branche inutiles, ce qui ralentit votre programme vers le bas. Cette méthode ne sonne pas de la RAS, car il a une paire assortie d'instructions d'appel et RET.

Il y a une architecture de manière indépendante (mais dépendant gcc) d'accéder à l'adresse qui est en cours d'exécution en utilisant des étiquettes comme valeurs:

http://gcc.gnu.org/onlinedocs/gcc/ Les étiquettes-en-Values.html

void foo()
{
  void *current_address = $$current_address_label;
  current_address_label:
      ....
}

Vous pouvez également lire / proc / stat. Vérifiez les proc manpages.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top