La réponse à votre question est spécifique à l'architecture particulière que vous utilisez. Puisque vous avez mentionné ARM, je vais vous donner une réponse basée sur ceci.
ARM Cortex est une conception basée sur des registres, donc fondamentalement tous les opérandes (const ou non) doivent se frayer un chemin dans l'un des registres internes avant de pouvoir être utilisés par les instructions du programme. Ceci est essentiel pour répondre à votre question, car l'architecture permet de le faire de différentes manières.
Pour les petites constantes (généralement inférieures à 8 ou 10 bits), la valeur peut être encodée directement dans certaines instructions. Par exemple, il existe une instruction ADD #imm qui ajoutera une valeur de 12 bits codée dans le mot d'instruction à un registre. Cela peut être utilisé pour spécifier directement une constante dans votre programme. Si vous ajoutiez la même constante à différents endroits dans votre code et que la valeur était de 12 bits ou moins, le compilateur utiliserait simplement une instruction ADD #imm partout où votre constante était requise. En d'autres termes, le const réel sera répliqué à plusieurs endroits dans tout le code stocké dans FLASH.
Si la constante est grande, cela ne fonctionnera pas, donc la valeur devra être stockée dans son propre emplacement mémoire FLASH dédié. La puce a une autre instruction, appelée LDR, qu'elle utilise pour déplacer une valeur d'un emplacement de mémoire dans les registres internes où elle peut être utilisée. Cette instruction ne se soucie pas de savoir si la valeur est physiquement stockée dans FLASH ou RAM, elle extrait simplement la valeur d'une adresse spécifique en mémoire et la met dans un registre. Notez que par rapport à la situation avec de petites constantes, cela nécessite un cycle d'instructions supplémentaire, mais si la constante est utilisée à plusieurs reprises dans un bloc de code, le compilateur la mettra en cache en la mettant dans un registre de réserve s'il en existe un.
Mais maintenant, nous rencontrons un problème potentiel. Sur la plupart des puces Cortex, la mémoire FLASH fonctionne à la même vitesse ou plus lentement que le cœur du processeur. Si nous tentons d'exécuter une instruction LDR à partir d'un emplacement FLASH, cette opération de lecture de la mémoire physique doit concurrencer la lecture de l'instruction suivante. Cela crée un goulot d'étranglement qui oblige le processeur à se bloquer jusqu'à ce que les données aient été lues. Pire encore, sur de nombreuses implémentations, le FLASH fonctionne très lentement et un cache pipeline est utilisé pour fournir des instructions au processeur plus rapidement. Dans ces appareils, la lecture, par exemple, d'un tableau de valeurs constantes peut exposer le goulot d'étranglement fondamental de l'accès FLASH causant de graves pertes de performances.
Pour cette raison, de nombreux compilateurs chercheront à copier toutes les données constantes dans des emplacements de RAM de réserve si possible. Cela évitera de tels problèmes, et étant donné que l'accès à la RAM est normalement plus rapide que FLASH, cela peut éviter de nombreux goulots d'étranglement des performances. S'il y a de toute façon de la RAM inutilisée dans votre programme, alors il n'y a pratiquement pas de surcharge pour le compilateur pour faire cela.
Il y a donc certainement une logique dans la façon dont le compilateur alloue des données constantes à la mémoire physique, mais heureusement, dans la plupart des situations, les concepteurs de puces et de compilateurs ont fait tout ce dur travail pour vous, et vous pouvez simplement être sûr qu'il fait tout convient le mieux à votre code et à votre niveau d'optimisation.