I can tell you how this works on x86.
All programs in non-64-bit modes operate with addresses combined of two items: segment selector
(for brevity "selector" is often omitted in text and that may be confusing) and offset
. This selector:offset
pair is called the logical address
.
The selector portion isn't always explicitly specified or manipulated with in code since the CPU has "default" associations of segment registers containing selectors with specific instructions or specific instruction encodings. It's also uncommon to manipulate selectors in 32-bit mode, but is very often necessary in 16-bit code.
The virtual address
is formed from the logical address either "directly" (in real
or 8086 virtual
mode) or "indirectly" (in protected
mode).
"Direct" virtual address
= selector
* 16 + offset
.
"Indirect" virtual address
= SegmentDescriptorTable[selector
].Base + offset
.
SegmentDescriptorTable is either the Global Descriptor Table
(AKA GDT
) or the Local Descriptor Table (AKA LDT
). It's set up by the OS and describes the location and size of various segments of memory. selector
is used to select a segment in the table. The Base
entry of the table tells the segment's beginning (virtual address). The Limit
entry tells the segment size (generally; the details are a little more complex).
When a program tries to access memory with an offset resulting access beyond the end of the segment (the CPU compares offset
and Limit
), the CPU generates an exception
and the OS handles it, by usually terminating the program.
Btw, in real/v86
mode, even though the virtual address is formed directly from selector:offset
, there's still a 16-bit Limit
imposed on offsets, which is why you need to use a different selector to access more than 64KB of memory.
The Base
entry in a segment descriptor can be used to either isolate the segment from the rest of the memory (Limit
helps here) or to place or move the entire segment to an arbitrary virtual address without having to modify anything (or much) in the program it belongs to (if we're moving a segment, the data has to be moved in the memory, obviously). Basically, it can be used for relocation purposes. In real/v86
mode for relocation purposes the selector
is changed.
The virtual address
can be further translated to the physical address
if the CPU is running in protected mode
and has set up page tables
. If there're no page tables, the physical address is the same as the virtual address. The translation is done in blocks of physical memory and address ranges that are called pages
(often 4KB).
There's no dedicated relocation register on x86 CPUs. Relocation can be achieved by adjusting:
- segment selectors in CPU registers or program's code
- segment base addresses in GDT/LDT
- offsets in program's code
- physical addresses in page tables
As for virtual address : reside in the hard disk , as a pages
, I'm not sure what exactly you want to say with this, but just because there's virtual to physical address translation, it doesn't mean there's also virtual on-disk memory. There are other uses for the translation besides virtual on-disk memory. And the addresses reside in the CPU and wherever your (and OS's) code writes them to, not necessarily on the disk.