La respuesta a su pregunta es específica de la arquitectura particular que está utilizando. Como ha mencionado ARM, le daré una respuesta basada en esto.
El ARM Cortex es un diseño basado en registros, por lo que básicamente cualquier operandos (constantes o no) deben, de alguna manera, abrirse camino en uno de los registros internos antes de que puedan ser utilizados por las instrucciones del programa. Esto es fundamental para responder a su pregunta, porque hay varias formas diferentes en que la arquitectura permite que esto se haga.
Para constantes pequeñas (normalmente menos de 8 o 10 bits), el valor se puede codificar directamente en ciertas instrucciones. Por ejemplo, hay una instrucción ADD #imm que agregará un valor de 12 bits codificado en la palabra de instrucción a un registro. Esto se puede utilizar para especificar directamente una constante en su programa. Si estuviera agregando la misma constante en varios lugares diferentes de su código, y el valor fuera de 12 bits o menos, entonces el compilador solo usaría una instrucción ADD #imm en todas partes donde se requería su constante. En otras palabras, la constante real se replicará en varias ubicaciones a lo largo del código almacenado en FLASH.
Si la constante es grande, entonces esto no funcionará, por lo que el valor deberá almacenarse en su propia ubicación de memoria FLASH dedicada. El chip tiene otra instrucción, llamada LDR, que utiliza para mover un valor desde una ubicación de memoria a los registros internos donde se puede usar. A esta instrucción no le importa si el valor se almacena físicamente en FLASH o RAM, simplemente extrae el valor de una dirección específica en la memoria y lo coloca en un registro. Tenga en cuenta que, en comparación con la situación con constantes pequeñas, esto requiere un ciclo de instrucción adicional, pero si la constante se usa repetidamente en un bloque de código, el compilador lo almacenará en caché colocándolo en un registro de reserva si hay uno disponible.
Sin embargo, ahora nos encontramos con un problema potencial. En la mayoría de los chips Cortex, la memoria FLASH se ejecuta a la misma velocidad o más lenta que el núcleo de la CPU. Si intentamos ejecutar una instrucción LDR desde una ubicación FLASH, esta operación de lectura de la memoria física debe competir con la lectura de la siguiente instrucción. Esto crea un cuello de botella, lo que hace que la CPU tenga que detenerse hasta que se hayan leído los datos. Peor aún, en muchas implementaciones, el FLASH se ejecuta muy lento y se utiliza un caché de canalización para enviar las instrucciones a la CPU más rápido. En estos dispositivos de lectura, digamos, una tabla de valores constantes puede exponer el cuello de botella fundamental del acceso FLASH que causa una pérdida severa de rendimiento.
Por esta razón, muchos compiladores buscarán copiar cualquier dato constante en ubicaciones de RAM de repuesto si es posible. Esto evitará estos problemas, y dado que la memoria RAM suele tener un acceso más rápido que FLASH, puede evitar muchos cuellos de botella en el rendimiento. Si de todos modos, si el programa no tiene memoria RAM no utilizada, virtualmente no es una sobrecarga para el compilador hacer esto.
Definitivamente, existe una lógica de cómo el compilador asigna datos constantes a la memoria física, pero afortunadamente en la mayoría de las situaciones, los diseñadores de chips y compiladores han hecho todo este trabajo por usted, y puede confiar en que está haciendo lo que sea. es mejor para su código particular y nivel de optimización.