I've read a couple things about memory management/virtual memory and I need a little more details on one important point.

If I compile a program and it does an access to a hard-coded address without any allocation calls, when I run it the process gets an error signal, terminated by signal SIGSEGV (Address boundary error).

Example program:

#include <stdio.h>

void main()
    int * x = 0x1312;
    printf("%d\n", *x);

Compiled with mere:

$ gcc accessing-random-address.c -o random-address-access

Here I don't get what exactly happens when a program is turned into a process. The compiled program is all-machine-code, isn't it? The address access should look like mv (0x1312) regN. If this code runs -- how could the OS detect that the code accesses a memory outside of its' memory range?

So, my question is -- what mechanism is used in Linux/Unixes to catch such rogue memory accesses and send the signal to the process? At what moment is it done?

In fact, the same question applies to the way how a program is converted to a process. If the program has been compiled for some architecture -- it should use the physical addresses and registers of the processor. But the process uses the virtual memory, with page-tables etc. So, is there some intermediate executable Linux-specific format, which gcc compiles to? And this format is somehow converted to real machine code when the program is loaded into memory as a process? And then in the real machine code the memory access is not just mv A B but some procedure with kernel's page tables, page numbers and offsets?


Probably this question would be clarified with more reading. But I would like to have this knowledge upfront -- so that "the main picture" is complete before getting other details.