Innanzitutto, questo non ha nulla a che fare con la RAM, davvero. Stiamo parlando dello spazio degli indirizzi qui - anche se hai solo 16 MiB di memoria, hai ancora tutti i 32 bit di spazio degli indirizzi su una CPU a 32 bit.
Questo risponde già alla tua prima domanda, davvero - al momento in cui è stato progettato, i PC del mondo reale non avevano nulla vicino ai 4 GiB di memoria; erano più nel range di 1-16 MiB di memoria. Lo spazio degli indirizzi era, a tutti gli effetti, libero.
Ora, perché 0xFFFFFFF0 esattamente? La CPU non sa quanta parte del BIOS esiste. Alcuni BIOS possono richiedere solo pochi kilobyte, mentre altri possono occupare megabyte di memoria completa e non sto nemmeno entrando nelle varie RAM opzionali. Per iniziare, la CPU deve essere cablata a un determinato indirizzo: non è necessario configurare la CPU. Ma questa è solo una mappatura dello spazio degli indirizzi - l'indirizzo è mappato direttamente nel chip ROM del BIOS (sì, questo significa che non avrai accesso a tutti i 4 GiB di RAM a questo punto se ne hai così tanti - ma non è niente di speciale, molti dispositivi richiedono il proprio intervallo nello spazio degli indirizzi). Su una CPU a 32 bit, questo indirizzo fornisce 16 byte completi per eseguire l'inizializzazione di base, che è sufficiente per impostare i segmenti e, se necessario, la modalità indirizzo (ricorda,"procedura" di avvio reale . A questo punto, non usi affatto la RAM, è solo una ROM mappata. In effetti, la RAM non è nemmeno pronta per essere utilizzata a questo punto - questo è uno dei lavori del BIOS POST! Ora potresti pensare: come fa una modalità reale a 16 bit ad accedere all'indirizzo 0xFFFFFFF0? Certo, ci sono segmenti, quindi hai uno spazio di indirizzamento di 20 bit, ma non è ancora abbastanza buono. Bene, c'è un trucco: i 12 bit alti dell'indirizzo sono impostati fino a quando non esegui il tuo primo salto in lungo, dandoti accesso allo spazio di indirizzi alto (rifiutando l'accesso a qualcosa di inferiore a 0xFFF00000 - finché non esegui un salto in lungo) .
Tutto ciò è nascosto soprattutto ai programmatori (per non parlare degli utenti) sui moderni sistemi operativi. Di solito non hai accesso a nulla di così basso livello - alcune cose sono già al di là del recupero (non puoi cambiare le modalità della CPU in modo pessimo), altre sono gestite esclusivamente dal kernel del sistema operativo.
Quindi una visione migliore viene dalla codifica di vecchia scuola su MS DOS. Un altro esempio tipico di mappatura diretta della memoria del dispositivo nello spazio degli indirizzi è l'accesso diretto alla memoria video. Ad esempio, se volevi scrivere velocemente un testo sul display, scrivevi direttamente all'indirizzo B800:0000
(più offset - in modalità testo 80x25, questo significava che (y * 80 + x) * 2
se la mia memoria mi serve bene - due byte per carattere, riga per riga). Se volevi disegnare pixel per pixel, hai usato una modalità grafica e l'indirizzo iniziale di A000:0000
(in genere, 320x200 a 8 bit per pixel). Fare qualsiasi cosa ad alte prestazioni di solito significava immergersi nei manuali dei dispositivi, per capire come accedervi direttamente.
Questo sopravvive fino ad oggi - è appena nascosto. Su Windows, puoi vedere gli indirizzi di memoria associati ai dispositivi in Gestione dispositivi - apri le proprietà di qualcosa come la tua scheda di rete, vai alla scheda Risorse - tutti gli elementi del Range di memoria sono mappati dalla memoria del dispositivo al tuo spazio di indirizzi principale. E a 32 bit, vedrai che la maggior parte di quei dispositivi sono mappati sopra il segno 2 GiB (successivamente 3 GiB), ancora una volta, per ridurre al minimo i conflitti con la memoria utilizzabile dall'utente, sebbene questo non sia realmente un problema con la memoria virtuale ( le applicazioni non si avvicinano in alcun modo al reale spazio degli indirizzi hardware : hanno il loro pezzo di memoria virtualizzato, che potrebbe essere mappato su RAM, ROM, dispositivi o file di pagina, ad esempio).
Per quanto riguarda lo stack, beh, dovrebbe aiutare a capire che, per impostazione predefinita, lo stack cresce dall'alto. Quindi, se fai un push
, il nuovo puntatore dello stack sarà su 0xFFFFFEC
- in altre parole, non stai cercando di scrivere all'indirizzo di inizializzazione del BIOS :) Il che ovviamente significa che le routine di inizializzazione del BIOS possono usare lo stack in modo sicuro, prima di rimapparlo da qualche parte più utile. Nella programmazione di vecchia scuola, prima che il paging diventasse di fatto il default, lo stack di solito si avviava alla fine della RAM, e lo "overflow dello stack" si verificava quando si iniziava a sovrascrivere la memoria dell'applicazione. La protezione della memoria ha cambiato molto questo, ma in generale mantiene la retrocompatibilità il più possibile - nota come anche la più moderna CPU x86-64 può ancora avviare MS DOS 5 - o come Windows può ancora eseguire molte applicazioni DOS che non hanno idea del paging.