1 votes

Peut-on utiliser des pointeurs de taille 4 bits, 8 bits, 16 bits ou 32 bits sur une machine 64 bits ?

J'ai juste fait un calcul approximatif autour de la taille maximale d'un entier non signé de 64 bits , qui est :

18,446,744,073,709,551,615
q5 q4  t   b   m   t   h

Regarder Spécifications matérielles d'AWS sur leurs plus grosses machines, il atteint jusqu'à 3,904GB , qui est :

3,904,000,000,000,000,000 bytes
5 q4  t   b   m   t   h

Pour moi, cela signifie que la les pointeurs sont stockés sous forme d'entiers de 64 bits . Je suis novice en matière de mémoire et de pointeurs, mais je voulais juste clarifier ce point.

Je suis encore un peu confus. A pointeur est une "construction de langage de programmation". Donc, techniquement, même sur une machine 64 bits, si vous n'utilisez que moins de ~4 milliards (taille maximale d'un entier de 32 bits), je me demande pourquoi il n'est pas possible de se contenter de pointeurs de 32 bits. De cette façon, les pointeurs sont de 32 bits jusqu'à ce que vous manquiez d'espace, puis vous pouvez commencer à utiliser des pointeurs de 64 bits. On aurait alors un peu plus d'espace pour avoir plus d'objets.

Mais je ne sais toujours pas ce qu'il en est. Un pointeur contient l'emplacement d'un adresse en mémoire . Il est indiqué que l'"adresse" est de 64 bits. Donc, si nous avions des pointeurs de 32 bits pointant sur des morceaux de 32 bits dans la mémoire de 64 bits, je ne suis pas sûr de savoir à quoi cela ressemblerait ou ce que cela signifierait. Il semble que cela signifie qu'il faudrait faire décalages (bien que je ne comprenne pas très bien).

Je me demandais si l'on pouvait démontrer en C, en Assembleur ou en JavaScript, comment il serait possible de stocker des pointeurs de 32 bits dans un espace d'adressage de 64 bits. Si le C le gère automatiquement, alors comment l'Assembleur le fait.


J'aimerais savoir comment je pourrais utiliser une grande mémoire comme ci-dessus, mais stocker des pointeurs 32 bits, jusqu'à ce que le maximum soit atteint, puis utiliser des pointeurs 64 bits, et je ne suis pas sûr de ce à quoi cela ressemblerait exactement. Je vais essayer de dessiner un diagramme expliquant comment j'envisage la chose.

  | The bars and . are like a ruler and mark the bit positions.
  - Each row under a number (1, 2, 3, ...) means a memory address.
   Means no data in memory address.
   Means data of type 1 in memory address.
   Means data of type 2 in memory address.
   Means a bit of integer pointer is plugged into memory address slot.
   Means no bit of integer pointer is plugged into memory address slot.
                                                                                                                                 |
                                                                 |                                                               |
                                 |                               |                               |                               |
                 |               |               |               |               |               |               |               |
         |       |       |       |       |       |       |       |       |       |       |       |       |       |       |       |
   . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . | . |

1. Empty 64-bit memory.

                                                                 ...
                                                                 ...
   ...
   ...

2. 64-bit memory filled with 32-bit pieces of data (type 1 , type 2 ).

                                                                 ...
                                                                 ...
   ...
   ...

3. 64-bit memory filled with 64-bit pieces of data.

                                                                 ...
                                                                 ...
   ...
   ...

4. 64-bit memory filled with 4-bit pieces of data.

                                                                 ...
                                                                 ...
   ...
   ...

5. 64-bit memory filled with 32-bit pieces of data, with second 32-bits accessed by a 32-bit pointer.

                                                                 ...
                                                                 ... 
   ...
   ...

6. 64-bit memory filled with 64-bit pieces of data, with second 64-bits accessed by a 64-bit pointer.

                                                                 ...
                                                                 ...
   ...
   ...

7. 64-bit memory filled with 4-bit pieces of data, with second piece of data accessed by a pointer.

                                                                 ...
                                                                 ...
   ...
   ...

8. 64-bit memory filled with 8-bit pieces of data, with second piece of data accessed by a pointer.

                                                                 ...
                                                                 ...
   ...
   ...

Ce que j'imagine, c'est que les nombres entiers sont comme les clés d'un verrou (qui est l'adresse de la mémoire). Un trou de serrure vide ressemble aux 64 's alignés dans (1). Un trou de serrure complet pour une adresse de 64 bits ressemble aux 64 's en ligne dans (6). Si je donne à l'espace d'adressage de la mémoire de 64 bits un 32 bits c'est comme si cela ressemblait à (5). Il ne remplirait donc pas entièrement le trou de clé de 64 bits, il n'en remplirait (dans ce cas) que la seconde moitié. Il semble donc que cela ne correspondrait pas à l'adresse. Mais j'essaie d'indiquer les 32 bits de données qui se trouvent dans la seconde moitié ! Pour que l'adresse corresponde, il semble qu'il faille combler les trous de la rangée complète de 64 bits, comme dans (6). Je me demande si je n'ai pas mal compris, merci de m'indiquer où je me trompe.

Au cas où cela n'aurait pas été clair, les premiers chiffres 1 à 4 du tableau indiquent les données qui se trouvent dans la mémoire (1 étant une mémoire vide). Les deuxièmes nombres 5 à 8 montrent que nous essayons de accès les données à l'aide d'un pointeur (les cercles noirs dans une rangée étant le pointeur/la clé du verrouillage de l'adresse mémoire).

Enfin, j'ai une dernière question à poser. Je me demande s'il est possible d'aller plus loin et de stocker des données encore plus petites. Par exemple, stocker 4 bits de données, comme dans (7). Cela démontre simplement comment le système de pointeurs et d'adresses fonctionne de manière un peu plus détaillée. Je ne sais pas s'il est possible d'avoir un Pointeur 4 bits pointent vers un morceau de mémoire de 4 bits. En raison des exigences en matière d'alignement, il semble que l'on doive récupérer au moins 8 bits à la fois. Mais ce n'est pas grave. Je veux juste m'assurer qu'il est possible ou non d'utiliser un pointeur de n bits pour accéder à n bits de données dans un espace mémoire de 64 bits.

Et si c'est le cas, comment cela se présenterait, soit en C, soit en Assemblage, soit en JavaScript.

J'aimerais savoir comment on est censé stocker des données dans une mémoire de 64 bits, et ce qu'on est autorisé à faire avec les pointeurs étant donné que "les adresses de la mémoire sont de 64 bits". Autrement dit, si je peux faire memory.get(a32BitPointer) et qu'il renvoie 32 bits de données, à partir d'un emplacement de mémoire aligné sur 32 bits. (Ou, de manière équivalente, un élément de données ou un pointeur de taille de 4, 8, 16, etc. bits).

3voto

LawrenceC Points 70381

Un pointeur pointe vers contient une adresse absolue.

Si vous devez ajouter une valeur avant d'utiliser le pointeur, vous disposez d'un compensation pas un vrai pointeur.

En C, un pointeur vide peut être un pointeur de fonction, c'est-à-dire que vous pouvez appeler une fonction par son intermédiaire. Pour que cela fonctionne, vous avez besoin des 64 bits si l'unité centrale est en mode 64 bits.

Si votre processeur prend en charge 64 lignes d'adresse (il peut physiquement en avoir moins), il dispose alors d'un espace d'adressage de 2^64, soit 0x1 0000 0000 0000 0000 - allant de 0x0000 0000 0000 0000 a 0xFFFF FFFF FFFF FFFF .

Si vous voulez que votre pointeur puisse être utilisé par les instructions de l'unité centrale sans avoir besoin d'instructions supplémentaires de l'unité centrale pour savoir ce que vous voulez vraiment dire (le code natif de l'unité centrale peut traiter les pointeurs directement), il doit être aussi large que l'espace d'adressage de l'unité centrale.

Les décalages sont plus lents car l'unité centrale doit effectuer une addition pour obtenir l'adresse souhaitée, bien que les unités centrales disposent d'instructions natives qui effectuent également cette opération.

Je ne suis pas un super expert de l'ISA x86-64, mais il y a probablement des instructions du CPU qui traitent les valeurs de 32 bits comme des valeurs de 64 bits avec les 32 premiers bits supposés être 0. Le CPU doit toujours "étendre" en interne la valeur réelle à 64 bits.

Pour x86 et x86-64, vous pouvez certainement utiliser 8, 16, 32 et 64 bits. décalages (aucune instruction de l'unité centrale x86/x86 ne fonctionne avec des valeurs de 4 bits seulement)

1voto

phuclv Points 22397

Tout d'abord, 3904 Go de mémoire ne nécessitent que 42 bits pour l'adresse . Il se compose uniquement de 3 904 000 000 000 au lieu de ce que vous avez calculé. Il est possible de le vérifier rapidement à l'aide de PowerShell

PS C:\> [math]::Log(3904GB, 2) # GB base 2, or GiB
41.9307373375629
PS C:\> [math]::Log(3904e9, 2) # GB base 10
41.8280901915491

Donc, techniquement, même sur une machine 64 bits, si vous n'utilisez que moins de 4 milliards d'entiers (taille maximale d'un entier de 32 bits), je me demande pourquoi vous ne pouvez pas simplement avoir des pointeurs de 32 bits. De cette façon, les pointeurs sont en 32 bits jusqu'à ce que vous manquiez d'espace, puis vous pouvez commencer à utiliser des pointeurs en 64 bits. On aurait alors un peu plus d'espace pour avoir plus d'objets.

x32 ABI es un ABI x86 64 bits qui utilise des pointeurs 32 bits. Les processus n'ont qu'un espace d'adressage de 32 bits, ce qui signifie qu'ils ne peuvent pas utiliser plus de 4 Go de mémoire (ce qui n'est pas un problème pour la plupart des applications utilisateur), mais qu'ils pourront profiter de l'espace de registre plus grand et plus large. L'espace mémoire global est toujours de 64 bits, puisqu'il est fixé dans le matériel, et le pointeur 32 bits sera donc utilisé comme un décalage par rapport à l'adresse de base du processus au lieu d'un pointeur direct. L'implémentation est simplement la suivante

void* getRealPointer(uintptr_t base_addr, uint32_t ptr)
{
    // value stored in pointer is the offset/distance from base
    return (void*)(base_addr + ptr);
}

Cette technique est également utilisée sur de nombreuses autres architectures RISC 64 bits telles que Sparc ( Pourquoi Linux sur l'architecture sparc64 utilise-t-il des pointeurs 32 bits dans l'espace utilisateur et des pointeurs 64 bits dans l'espace noyau ? ), MIPS ou PowerPC, puisque lors de la transition vers le 64 bits, ils n'ont pas augmenté le nombre de registres comme x86 et ARM, ce qui signifie qu'un processus 32 bits est probablement plus rapide qu'un processus 64 bits, à moins qu'il ne nécessite beaucoup de mathématiques 64 bits ou plus de 2/3/4 Go de RAM.

Sur les processeurs 64 bits comme le G5, Debian PPC utilise un noyau 64 bits avec un espace utilisateur 32 bits. C'est parce que les processeurs PowerPC 64 bits n'ont pas de " mode 32 bits " comme l'architecture Intel 64/AMD64. Par conséquent, les programmes PowerPC 64 bits qui n'ont pas besoin de fonctions mathématiques 64 bits fonctionneront un peu plus lentement que leurs homologues 32 bits, car les pointeurs 64 bits et les entiers longs consomment deux fois plus de mémoire, remplissent le cache du CPU plus rapidement, et nécessitent donc des accès plus fréquents à la mémoire.

Linux sur PowerPC

Néanmoins, vous ne pouvez pas vous contenter d'utiliser des pointeurs 32 bits until you run out of space then start using 64-bit pointers Cela n'a pas de sens. Un type a toujours une taille fixe. Si vous réservez de l'espace pour seulement 32 bits du pointeur, que se passera-t-il lorsque vous devrez utiliser des pointeurs de 64 bits ? Où stockerez-vous la partie haute ?


Ainsi, si nous devions avoir des pointeurs 32 bits pointant vers des morceaux 32 bits dans la mémoire 64 bits, je ne suis pas sûr de savoir à quoi cela ressemblerait ou ce que cela signifierait

C'est ce qu'on appelle mémoire adressable par mot . Au lieu de pointer vers chaque octet, chaque valeur pointe simplement vers un octet différent. mot

Il sera plus facile d'imaginer que la mémoire consiste en une série d'éléments linéaires. cellules qui sont identifiées par des identifiants uniques. Ces identifiants sont ce que nous appelons normalement "adresse" et sont stockés dans les pointeurs. La taille des cellules est généralement de 1 octet sur les systèmes modernes (c'est-à-dire une mémoire adressable par octet). Cependant, les de nombreux systèmes plus anciens, comme Unisys ou PDP, utilisent une mémoire adressable par mot avec une cellule contient un mot (d'une longueur de 36 bits dans le cas de ces architectures). Par conséquent, dans ces systèmes char* serait plus grand que int* puisque vous aurez besoin de quelques bits supplémentaires pour stocker la position de l'octet que vous voulez adresser

Je ne comprends pas très bien votre tableau, mais il est rare que l'on ait besoin d'adresser chaque bit de cette manière, car cela réduit évidemment la mémoire totale que l'on peut adresser. Bien que, pour être juste, il existe quelques architectures avec une mémoire adressable par bit, principalement des systèmes embarqués. On a l'impression que l'on veut les 32 premiers bits d'une valeur de 64 bits lorsqu'on donne une adresse de 32 bits à l'unité centrale, mais ce n'est pas comme ça que ça marche. Pour adresser chaque moitié, vous aurez besoin d'un bit significatif supplémentaire au lieu de la moitié du nombre de bits. Le principe est simple : Si l'on utilise des cellules plus grandes, pour la même quantité de mémoire, il faut moins de cellules, ce qui signifie qu'il faut moins de bits pour l'ID, et vice versa. Au niveau matériel, la taille des cellules est généralement fixe.

Voici un exemple pour les 16 premiers octets de la mémoire

 0000  0001  0010  0011  0100  0101  0110  0111  1000  1001  1010  1011  1100  1101  1110  1111 

 b0    b1    b2    b3    b4    b5    b6    b7    b8    b9    b10   b11   b12   b13   b14   b15  

 w0 000       w1 001       w2 010       w3 011       w4 100       w5 101       w6 110       w7 111      

 dw0 00                     dw1 01                     dw2 10                     dw3 11                    

 o0                                                     o1                                                    

Vous pouvez également consulter l'illustration dans cette réponse

Si nous adressons chaque mot de 2 octets, le Nième mot aura l'adresse de l'octet N*2. Il en va de même pour toutes les autres tailles de blocs, pour lesquelles le décalage réel peut être calculé comme suit offset*sizeof(chunk) . Par conséquent, les 2 bits de poids faible d'une adresse alignée sur 4 octets et les 3 bits de poids faible d'une adresse alignée sur 8 octets sont toujours à zéro. Si vous n'utilisez pas de pointeurs adressables par mot, ces bits de poids faible peut être utilisé pour stocker des données qui est appelé pointeur étiqueté

La JVM 64 bits utilise cette technique avec comprimés Oops . Voir le L'astuce derrière les Oops compressés de la JVM En Java, les objets sont toujours alignés sur 8 octets, de sorte qu'ils peuvent adresser 8*4 = 32 Go de mémoire avec une adresse de 32 bits.

Les pointeurs gérés dans le tas Java pointent vers des objets alignés sur des limites d'adresse de 8 octets. Les oops compressés présentent les pointeurs gérés (dans de nombreux endroits du logiciel de la JVM, mais pas dans tous) comme des décalages d'objets de 32 bits par rapport à l'adresse de base du tas Java de 64 bits. Comme il s'agit de décalages d'objets plutôt que de décalages d'octets, ils peuvent être utilisés pour adresser jusqu'à quatre milliards d'objets (et non d'octets), ou un tas d'une taille maximale d'environ 32 gigaoctets. Pour les utiliser, il faut les mettre à l'échelle par un facteur de 8 et les ajouter à l'adresse de base du tas Java pour trouver l'objet auquel ils se réfèrent. La taille des objets utilisant les oops compressés est comparable à celle du mode ILP32.

https://docs.oracle.com/javase/7/docs/technotes/guides/vm/performance-enhancements-7.html#compressedOop

Récemment, Google a également appliqué la même technique à son moteur de rendu V8 et utilise Pointeur 32 bits dans V8 64 bits réduction de l'empreinte mémoire de ~35%

Les instructions de branchement et de chargement/stockage de la plupart des architectures RISC stockent également l'adresse du mot dans la partie immédiate, car il est inutile de gaspiller un espace précieux en sauvegardant ces bits toujours nuls. Par exemple, les instructions de branchement et de chargement/stockage Instructions de branchement et de saut du MIPS : JAL, J, BEQ, BLEZ, BGTZ...

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X