Pourquoi la rbp et la rsp appelés registres?
selon Intel dans x64 les registres suivants sont appelés registres à usage général (RAX, RBX, RCX, RDX, RBP, RSI, RDI, RSP et R8-R15) https://software.intel.com/en-us/articles/introduction-to-x64-assembly.
dans l'article suivant, il est écrit que RBP et RSP sont des registres spéciaux (point RBP à la base du cadre de la pile actuelle et point RSP au sommet de la pile actuelle cadre.) https://www.recurse.com/blog/7-understanding-c-by-learning-assembly
maintenant j'ai deux affirmations contradictoires. La déclaration Intel devrait être celle qui est fiable, mais qu'est-ce qui est correct et pourquoi la RBP et la RSP sont appelés à des fins générales du tout ?
merci de votre aide.
2 réponses
usage général signifie que tous ces registres peuvent être utilisés avec n'importe quelles instructions faisant le calcul avec des registres à usage général tandis que, par exemple, vous ne pouvez pas faire ce que vous voulez avec le pointeur d'instruction (RIP) ou le registre de drapeaux (RFLAGS).
certains de ces registres ont été conçus pour être utilisés à des fins précises, et le sont couramment. Les plus critiques sont la RSP et la RBP.
si vous avez besoin de les utiliser pour votre propre usage, vous devez enregistrer leur contenu avant de stocker quelque chose d'autre à l'intérieur, et les restaurer à leur valeur originale une fois fait.
Si un registre peut être un opérande add
, ou utilisé dans un mode d'adressage, c'est "généraliste", par opposition aux registres comme le FS
registre de segment, ou RIP. Les registres GP sont aussi appelés "registres entiers", même si d'autres types de registres peuvent contenir des entiers, aussi.
dans l'architecture informatique, il est courant pour les CPU de traiter en interne des registres / instructions entiers séparément des registres/instructions FP / SIMD. par exemple Intel Sandybridge-famille de Processeurs ont des fichiers de registres physiques séparés pour renommer les registres GP integer vs. FP/vector. Ceux-ci sont simplement appelés les dossiers de registre integer vs. FP. (Où FP est un raccourci pour tout ce qu'un noyau n'a pas besoin de sauvegarder/restaurer pour utiliser les registres GP tout en laissant intact L'état FPU/SIMD de l'espace utilisateur.) Chaque entrée dans le fichier de registre FP est de 256 bits de large( pour contenir un vecteur AVX ymm), mais les entrées de fichier de registre entier seulement doivent être 64 bits large.
sur les CPU qui renomment les registres de segments ( Skylake ne fait pas), je suppose que cela ferait partie de l'état entier, et donc RFLAGS + RIP. Mais quand nous disons "registre entier", nous voulons normalement dire spécifiquement un registre universel.
chaque registre a quelques particularités pour certaines instructions, à l'exception de quelques registres complètement nouveaux ajoutés avec x86-64: R8-R15. Ils ne les disqualifient pas en tant que Généraux. But La (faible 16 de la) 8 date de retour à 8086, et il y avait des utilisations implicites de chacun d'entre eux, même dans l'original 8086.
pour RSP, c'est spécial pour push/pop/call/ret, donc la plupart du code ne l'utilise jamais pour autre chose. (Et en mode noyau, utilisé asynchrone pour les interruptions, donc vous ne pouvez vraiment pas le cacher quelque part pour obtenir un registre GP supplémentaire de la façon dont vous pouvez dans le code de l'espace utilisateur: le PSR est-il aussi universel que le EAX?)
mais en controlled conditional (comme no signal handlers) vous n'avez pas besoin d'utiliser RSP pour un pointeur de pile. par exemple, vous pouvez l'utiliser pour lire un tableau dans une boucle avec de la pop, comme dans ce code-Réponse de golf. (J'ai utilisé esp
EN Code 32 bits, mais même différence:pop
est plus rapide que lodsd
sur Skylake, alors que les deux sont de 1 byte.)
utilisations implicites et particularités de chaque registre:
Voir aussi x86 Assemblée - Pourquoi est [e]bx conservé dans les conventions d'appel? pour une liste partielle.
Je limite principalement cela aux instructions de l'espace utilisateur, surtout celles qu'un compilateur moderne pourrait en fait émettre à partir du code C ou c++. Je n'essaie pas d'être exhaustif pour les règlements qui ont beaucoup d'utilisations implicites.
rax
: opérande [i]mul / [i]div / cdq / cdqe, instructions de chaîne (stos),cmpxchg
, etc. etc. Ainsi que des encodages Spéciaux plus courts pour de nombreuses instructions, commexchg
-avec-eax qui est où0x90 nop
provenait de (avant qu'il ne devienne une instruction séparée dans x86-64, parce quexchg eax,eax
zero-étend eax dans RAX et ne peut donc pas utiliser le0x90
l'encodage. Maisxchg rax,rax
peut encore s'assembler à REX.W=1 0x90.rcx
: maj compte,rep
chaîne compte, le lentloop
l'instructionrdx
:rdx:rax
est utilisé par diviser et multiplier, et cwd / cdq / cqo pour les configurer.rdtsc
. BMI2mulx
.rbx
: 8086xlatb
.cpuid
utilisez les quatre EAX..EDX. 486cmpxchg8b
, x86-64cmpxchg16b
. Les compilateurs émettrontcmpxchg8
std::atomic<long long>::compare_exchange_weak
, et 16b pouratomic<struct_16_bytes>
. RBX a le moins d'utilisations implicites des 8 originaux, maislock cmpxchg16b
est l'un des rares compilateurs utilisent réellement.rsi
/rdi
: chaîne de caractères de la fpo, y comprisrep movsb
que certains compilateurs utilisent parfois. (gcc aussi inlinesrep cmpsb
pour les littéraux de chaîne, dans certains cas, mais ce n'est probablement pas optimale).rbp
:leave
(seulement 1 uop plus lent quemov rsp, rbp
/pop rbp
. gcc l'utilise réellement dans des fonctions avec un pointeur de cadre, quand il ne peut pas justepop rbp
). Aussi horriblement lententer
que personne n'utilise jamais.rsp
: pile ops: push/pop / appel/reg, etleave
. (Etenter
).r11
:syscall
/sysret
l'utiliser pour enregistrer / restaurer les RFLAGS de l'espace utilisateur. (Avec RCX pour sauvegarder / restaurer le RIP de l'espace utilisateur).
encodage en mode adressage cas particuliers:
rbp
/r13
ne peut pas être un registre de base sans déplacement: codage au lieu de cela signifie: (en ModRM) rel32
RIP (relatif), ou (en SIB) disp32
sans registre de base. (r13
utilise les mêmes 3 bits dans ModRM / SIB, donc ce choix simplifie le décodage en ne faisant pas la longueur d'instruction décodeur regardez le REX.B bit pour obtenir le 4ième bit de base-register). [r13]
assemble [r13 + disp8=0]
. [r13+rdx]
assemble [rdx+r13]
(éviter le problème en changeant la base/l'index lorsque c'est une option).
rsp
/r12
en tant que base, le registre a toujours besoin d'un octet. (L'encodage ModR/M de base=RSP est un code d'échappement pour signaler un octet SIB, Et encore une fois, plus de décodeur devrait se soucier du préfixe REX si r12
a été traitée différemment.)
rsp
ne peut pas être un indice de registre. Cela permet de coder [rsp]
, qui est plus utile que [rsp + rsp]
. (Intel aurait pu concevoir les encodages ModRM/SIB pour les modes d'adressage 32 bits (nouveau en 386), de sorte que le SIB-with-no-index n'était possible qu'avec base=ESP. Que ferait [eax + esp*4]
possible et seulement exclure [esp + esp*1/2/4/8]
. Mais ce n'est pas utile, donc ils ont simplifié le matériel en faisant index = ESP le code pour no index indépendamment de la base. Cela permet deux méthodes redondantes pour encoder n'importe quel mode d'adressage base ou base+disp: avec ou sans SIB.)
r12
être un indice inscrire. Contrairement aux autres cas, cela n'affecte pas le décodage de la longueur d'instruction. En outre, il ne peut pas être travaillé avec un encodage plus long comme les autres cas. AMD voulait que le registre D'AMD64 soit aussi orthogonal que possible, donc c'est logique qu'ils aient dépensé quelques transistors supplémentaires pour vérifier REX.X as une partie de l'index / indice de décodage. Par exemple, [rsp + r12*4]
nécessite des index=r12, afin d'avoir r12
pas tout à fait généralement objectif ferait AMD64 une cible de compilateur pire.
0: 41 8b 03 mov eax,DWORD PTR [r11]
3: 41 8b 04 24 mov eax,DWORD PTR [r12] # needs a SIB like RSP
7: 41 8b 45 00 mov eax,DWORD PTR [r13+0x0] # needs a disp8 like RBP
b: 41 8b 06 mov eax,DWORD PTR [r14]
e: 41 8b 07 mov eax,DWORD PTR [r15]
11: 43 8b 04 e3 mov eax,DWORD PTR [r11+r12*8] # *can* be an index
compilateurs aiment quand tous les registres être utilisé pour n'importe quoi, seulement limiter l'allocation de Registre pour quelques opérations spéciales. C'est ce qu'on entend par orthogonalité de registre.